14 bitowy encoder magnetyczny AS5047D SPI

Gotowe kody obsługi układów elektronicznych udostępnione przez użytkowników forum.
ODPOWIEDZ
Awatar użytkownika
Pikczu
Posty: 392
Rejestracja: 17 sie 2015, 13:46
Lokalizacja: Dublin, Ireland
Kontakt:

14 bitowy encoder magnetyczny AS5047D SPI

Post autor: Pikczu » 22 paź 2020, 21:52

Był sezon na klawiatury ADC to i musiał przyjść na enkodery.
Nie jest to tylko biblioteka ale cały projekt. Miał to byc wskaźnik kierunku wiatru ale świetnie wskazuje kierunek/kat czegokolwiek.
Układ bazuje na 14 bitowym enkoderze magnetycznym firmy AMS AS5047D.
Układ składa się z w dwóch płytek złożonych na kanapkę na pokładzie pierwszej płytki znajduje się atmega328P, AS5047D,DS18b20 i WS2812B.
Na pokładzie drugiej płytki znajduje się układ LTC2861 jest to konwerter full duplex rs485 oraz typowy stabilizator napięcia.

Główny bohater, układ AS5047D jest bardzo dobrze wyposażony ma 14 bitową rozdzielczość, z komunikacją po SPI oraz standardowe wyprowadzenia A i B + index.
Szczegóły doczytacie sobie w pdf-ie
https://ams.com/as5047d

Obsługa układu po SPI jest śmiesznie prosta i ciężko ją nazwać biblioteką.
Odczyt kąta:
  1. $nocompile
  2. ' AS5047D SPI read angle
  3. ' By SP9DR 2019 v.1
  4. Sub Spi_angle_read
  5. Spiout Spi_data(1) , 2
  6.  Anglecom = Spimove(spi_data(1) , 2)
  7.    Swap Anglecom
  8.    Show1 = Anglecom And &B00111111_11111111                 'maska na 14 bitów
  9.    Angle = Show1 * 36000                                    'do pierwszej cyfry po przecinku
  10.    Angle1 = Angle / 16383
  11.   Print Chr(10) ; Angle1
  12.    Tex = Str(angle1)
  13.    Kat = Format(tex , "0.00")
  14.    Print " kat= " ; Kat
  15.  
  16. End Sub
Odczyty diagnostyczne:
  1. $nocompile
  2. ' AS5047D SPI diagnostic info
  3. ' By SP9DR 2019 v.1
  4. Sub Spi_diaagc_read
  5.    Spiout Spi_data(3) , 2
  6.    Diaagc = Spimove(spi_data(3) , 2 )
  7.    Swap Diaagc
  8.  
  9.    If Diaagc.8 = 1 Then
  10.    Print "internal offset loop ok"
  11.    Else
  12.    Print "internal offset loops not ready "
  13.     End If
  14.  
  15.    If Diaagc.9 = 1 Then
  16.    Print "CORDIC overflow error"
  17.  
  18.    End If
  19.  
  20.    If Diaagc.10 = 1 Then
  21.    Print "Magnetic field strength too high; AGC=0x00"
  22.    End If
  23.  
  24.    If Diaagc.11 = 1 Then
  25.     Print "Magnetic field strength too low; AGC=0xFF"
  26.    End If
  27.    Agc = Diaagc And &B0000_0000_1111_1111                   'maska na 14 bitów
  28.    Print Bin(diaagc) ; " AGC value"
  29.    Print " AGC value= " ; Agc
  30. End Sub
Odczyt siły pola magnetycznego potrzebny do ustawienia odpowiedniej odległości pomiędzy magnesem a układem.
  1. $nocompile
  2. 'Odczyt sily pola
  3. 'AS5047D SPI maginitude reading
  4. 'By SP9DR 2019 v.1
  5. Sub Spi_magnitude_read
  6.    Spiout Spi_data(5) , 2
  7.    Magnitude = Spimove(spi_data(5) , 2)
  8.    Swap Magnitude
  9.    Mag = Magnitude And &B00111111_11111111                  'maska na 14 bitów
  10.  
  11.    Print " MAG value= " ; Mag                               ' magnitude
  12. End Sub
Kod główny:
  1. '-------------------------------------------------------------------------------
  2. ' Pawel Labedz SP9DR for hardware version 1.4
  3. ' Copyright Pawel Labedz 2019
  4. ' All rights reserved
  5. '```````````````````````````````````````````````````````````````````````````````
  6. '-------------------------------------------------------------------------------
  7. Debug Off
  8. '$sim
  9. $regfile = "m328pdef.dat"
  10. $crystal = 18432000
  11. $hwstack = 64
  12. $swstack = 64
  13. $framesize = 64
  14. $baud = 38400
  15. $projecttime = 289
  16. Config Submode = New
  17. '-------------------------------------------------------------------------------
  18. $version 0 , 0 , 49
  19. Dim Firmware As String * 7
  20. Firmware = "Ver_0.1"
  21.  
  22. '-------------------------------------------------------------------------------
  23. Config Watchdog = 2048
  24. 'Start Watchdog
  25. '-------------------------------------------------------------------------------
  26. Config Com1 = 38400 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
  27. Config Serialin = Buffered , Size = 128
  28. Config Serialout = Buffered , Size = 128
  29. Enable Serial
  30. '------------------------------timer 1------------------------------------------
  31. Const Timer1reload = 31250
  32. Config Timer1 = Timer , Prescale = 256
  33. Load Timer1 , Timer1reload
  34. On Ovf1 Timer1_isr
  35. Enable Timer1
  36. Start Timer1
  37.  
  38. 'Timer value explination
  39. ' The timer is a 16Bit timer, it overflows when the timer reaches 65536
  40. ' The AVR is running at 8000000Hz, the prescaler is 256
  41. ' Each tick is 0.032 ms  -  (1 / CPUSpeed in KHz ) * Prescaler
  42. ' The timer needs  3125 ticks to reach the required time  ( 3125 * 0.032 = 100ms)
  43. ' The start value for the timer must be set to 34286 so that it will overflow at 65536 after 3125 ticks
  44. ' NOTE: The load command does the inversion for you (256-value or 65536-value)
  45.  
  46. '-------------------------------SPI config---------------------------------
  47. Config Spi = Hard , Interrupt = Off , Data_order = Msb , Master = Yes , Polarity = Low , Phase = 1 , Clockrate = 128 , Noss = 0
  48. 'polarity =0 and  phase 1 = spi mode 1
  49.  
  50. '--------------------------------SPI variable-----------------------------------
  51. Dim Spi_data(8) As Byte
  52. Spi_data(1) = &HFF                                          ' pobierz kat msb
  53. Spi_data(2) = &HFF                                          ' pobierz kat lsb
  54.  
  55. Spi_data(3) = &HFF                                          'diagnostyka  msb
  56. Spi_data(4) = &HFC                                          'diagnostyka  lsb
  57.  
  58. Spi_data(5) = &H7F                                          'sila magnesu msb
  59. Spi_data(6) = &HFD                                          'sila magnesu lsb
  60.  
  61. Spi_data(7) = &H00                                          'nop  msb
  62. Spi_data(8) = &H00                                          'nop lsb
  63. '-------------------------------WS2818b---------------------------------
  64.  
  65. Config Rainbow = 1 , Rgb = 4 , Rb0_len = 2 , Rb0_port = Portd , Rb0_pin = 6
  66. '                      ^-- using rgbW leds #### MUST BE FIRST PARAMETER when defined ###
  67. '                                                   ^ connected to pin 0
  68. '                                       ^------------ connected to portB
  69. '                         ^-------------------------- 8 leds on stripe
  70. '              ^------------------------------------- 1 channel
  71. 'Global Color-variables
  72. Dim Color(3) As Byte
  73. R Alias Color(_base) : G Alias Color(_base + 1) : B Alias Color(_base + 2)
  74.  
  75. 'CONST
  76. Const Numleds = 2
  77. Dim N As Byte
  78. '-------------------------------------------------------------------------------
  79. Dim Anglecom As Word
  80. Dim Diaagc As Word
  81. Dim Diag_bits As Word
  82. Dim Magnitude As Word
  83. Dim Mag As Word
  84. Dim Agc As Word
  85. Dim Ttx As Word
  86. Dim Angle As Dword
  87. Dim Angle1 As Dword
  88. Dim Kat As String * 6
  89. Dim Tex As String * 6
  90. Dim Show1 As Word
  91. Dim Index As Byte
  92.  
  93. '----------------------------------UART adress --------------------------------
  94.  
  95. Dim Rs485_adres As Byte , Rs485_adres_ee As Eram Byte At &H10       'Rs485 address
  96. Dim Rs485_adres_temp As Byte                                ' potrzebne przy porownywaniuadresu odebranego z wlasciwym
  97.  
  98. '----------------------------------UART variable--------------------------------
  99. Dim Rs485_time_out As Word
  100. Dim Uart_flag As Byte                                       'flag used for uart
  101. Dim Lcount As Byte                                          '
  102. Dim Char_ As Byte
  103. Dim Uart_command As String * 20                             'Needs to be long enough for commands
  104. Dim Getcommands(10) As String * 11                          'Here we have an array to chop up the commands from RS232
  105. '-------------------------------------------------------------------------------
  106. Dim Ds_t(2) As Byte                                         ' array for temperature read form Ds18b20
  107. Dim Temp1 As Integer                                        'zmienna przchowuje wartosc temp1
  108. Dim Ds_index As Byte                                        ' help variable for index value
  109. Dim Ds_signature(8) As Byte
  110. Dim Wind As Dword                                           'variable
  111. Dim Tick As Byte                                            'ziemnan na timer 1
  112. Dim Flagi As Byte                                           ' flagi pomocnicze
  113. Dim Max_ As Byte
  114. Dim Tabilca As Byte
  115. Dim Binarnie As Word
  116. '--------------------------Uart commands----------------------------------------
  117.  
  118. Const On_ = 1
  119. Const Off_ = 0
  120.  
  121. '-------------------------------------------------------------------------------
  122. Const Broadcast = 255                                       'broadcast do wszytkich
  123. 'Const G1_c_2 =
  124. 'Const G1_c_3 =
  125. 'Const G1_c_4 =
  126. 'Const G1_c_5 =
  127. 'Const G1_c_6 =
  128. 'Const G1_c_7 =
  129. 'Const G1_c_8 =
  130. '------------------------------------------------------------------------------
  131. Const G2_c_1 = "a"
  132. Const G2_c_2 = "t"
  133. Const G2_c_3 = "c"
  134. Const G2_c_4 = "s"
  135. Const G2_c_5 = "diag_on"                                    'magnitude diagnostic
  136. Const G2_c_6 = "diag_off"
  137. Const G2_c_7 = "rs_term_on"
  138. Const G2_c_8 = "rs_term_off"
  139. Const Reboot = "reboot"
  140. Const Bootloader = "load"
  141. Const Help = "?"
  142. Const Notincommands = " nie rozpoznano "
  143. Const Ok = "ack"
  144. Const Prompt = "command>>"
  145.  
  146.  
  147. 'komnedy wewnatrz get command 2
  148. Const G3_c_1 = " i"
  149. Const G3_c_2 = " j"
  150.  
  151. '-------------------------------------------------------------------------------
  152. Config 1wire = Portc.1
  153. Config Portc.3 = Output
  154. Rx_enable Alias Portc.3                                     'RX enable for RS 485
  155. Portc.3 = 0
  156. Config Portc.4 = Output
  157. Tx_enable Alias Portc.4                                     'TX enable rs485
  158. Portc.4 = 1                                                 'tx enabled
  159. Config Portc.5 = Output
  160. Term_enable Alias Portc.5                                   ' internal 120 ohm termiantion for rs485
  161. Portc.5 = 1
  162. Config Portd.2 = Input                                      'int 0  index pin
  163. Portd.2 = 1
  164. Config Portd.3 = Output
  165. Slew_en Alias Portd.3                                       'slew rate enable for rs485
  166. Portd.3 = 0
  167. Config Portd.6 = Output                                     'WS2818b led
  168. '-------------------------------------------------------------------------------
  169. Config Int0 = Falling                                       'home position sensor
  170. On Int0 Int0_isr
  171. Enable Int0
  172. '---------------------------subs include file-----------------------------------
  173. '$include "Subs\Rs485_read.inc"
  174. $include "Subs\Spi_angle_read.inc"
  175. $include "Subs\Spi_magnitude_read.inc"
  176. $include "Subs\Spi_DIAAGC_read.inc"
  177. $include "Subs\Uart_rx.inc"
  178. $include "Subs\DS18b20_register.inc"
  179. $include "Subs\DS18b20_temp_read.inc"
  180.  
  181. '-------------------------------------------------------------------------------
  182. '-------------------------------------------------------------------------------
  183. Rs485_adres = Rs485_adres_ee                                'read adress from eeprom
  184.  
  185. '-------------------------------------------------------------------------------
  186. Enable Interrupts
  187.  
  188. Print Chr(10) ; "Position sensor by SP9DR"
  189. Print "Dla Pana Jacka SQ2EER"
  190. Print "Version: " ; Version(2)
  191. Print "RS_485 Adres= " ; Rs485_adres
  192. 'Print "SPI test"
  193. Print "watchdog started"
  194.  
  195. Start Watchdog
  196. Spiinit
  197. 1wreset
  198. 1wwrite &HCC                                                'skip all
  199. 1wwrite &H44                                                'convert temp
  200. Wait 1
  201.  
  202. Clear Serialout
  203. Clear Serialin
  204. Uart_command = ""
  205. Term_enable = 1
  206.  
  207. Rb_selectchannel 0                                          ' select first channel
  208. R = 50 : G = 0 : B = 100                                    ' define a color
  209. Rb_setcolor 1 , Color(1)                                    ' update leds
  210. Rb_setcolor 0 , Color(2)                                    ' update leds
  211. Rb_send
  212.  
  213.  
  214. '-------------------------------------------------------------------------------
  215. Do
  216.  
  217.  
  218.  
  219.  
  220.    If Ischarwaiting() > 0 Then                              'calls _gotchar and use URXC
  221.       Char_ = Inkey()                                       'get char from buffer
  222.       Rs485_time_out = 0
  223.  
  224.       If Char_ = 13 Or Len(uart_command) > 20 Then          ' check for ENTER of more then 20 characters
  225.          Call Uart_rx                                       '
  226.          'Print                                              '
  227.          'Print Prompt;                                      'Using a constant will let us change the prompt
  228.          Uart_command = ""
  229.       Else
  230.          Uart_command = Uart_command + Chr(char_)           'buffor building
  231.          Print Chr(char_) ;                                 'this is echo
  232.  
  233.       End If
  234.    End If
  235.  
  236.    If Flagi.2 = 1 Then                                      ' if diagnostic enable
  237.       If Flagi.3 = 1 Then
  238.          Call Spi_angle_read
  239.          Call Spi_diaagc_read
  240.          Call Spi_magnitude_read
  241.          Flagi.3 = 0
  242.       End If
  243.    End If
  244.    Reset Watchdog
  245.    If Uart_command <> "" Then
  246.    Incr Rs485_time_out
  247.    End If
  248.  
  249.    If Rs485_time_out > 65000 And Uart_command <> "" Then
  250.      Debug "czyszczenie"
  251.       Clear Serialin
  252.       Uart_command = ""
  253.    End If
  254.  Reset Watchdog
  255. Loop
  256. End
  257.  
  258. Int0_isr:                                                   'wind speed meter index value
  259.    'Incr Index
  260.    'Wind = Index                                             '* 24
  261. Return
  262.  
  263. Timer1_isr:
  264.    Load Timer1 , Timer1reload
  265.    Incr Tick
  266.  
  267.    If Tick = 2 Then
  268.       Set Flagi.1                                           '
  269.    'elseif Tick = 10 Then
  270.       Flagi.3 = 1
  271.       Tick = 0
  272.    End If
  273. Return
Jest tam jeszcze DS18b20 jako czujnik temperatury, w koncu to czujnik kierunku wiatru/prędkości to i temperaturę też możemy zmierzyć.
  1. $nocompile
  2. 'DSS18b20 temperature read
  3. '*******************************************************************************
  4. 'DALLAS DS18B20 ROM and scratchpad commands''''''''''''''''''''''''''
  5. '1wwrite....
  6. '&H 33  read rom - single sensor
  7. '&H 55  match rom, followed by 64 bits
  8. '&H CC  skip rom
  9. '&H EC  alarm search  - ongoining alarm >TH <TL
  10. '&H BE  read scratchpad
  11. '&H 44  convert T
  12. '*******************************************************************************
  13. '*******************************************************************************
  14. Sub Ds18b20_temp_read
  15.  
  16.    1wreset
  17.  1wwrite &HCC
  18.  1wwrite &HBE
  19.  Ds_t(1) = 1wread(2)
  20.  Wait 1
  21.    1wreset
  22.    1wwrite &HCC
  23.    1wwrite &H44
  24.   Temp1 = Ds_t(2)                                           '          starszy bajt temperatury
  25.     Shift Temp1 , Left , 8                                  'przesun w lewo o 8 miejsc
  26.     Temp1 = Temp1 + Ds_t(1)
  27.     Shift Temp1 , Right , 4
  28.  Print "temp: " ; Temp1
  29.  
  30. End Sub
Oczywiscie nie obejdzie się bez komunikacji.
Czyli RS485 i zestaw komend.
  1. $nocompile
  2. Sub Uart_rx():
  3.   Reset Watchdog
  4.    Debug "jestem w uar_rx"
  5.    Lcount = Split(uart_command , Getcommands(1) , " ")      'This choping coomand after space
  6.    Debug Chr(13)
  7.    Debug "lcount= " ; Lcount
  8.    Debug "uart_command= " ; Uart_command
  9.    Debug "Getcommands(1)= " ; Getcommands(1)
  10.    Debug "Getcommands(2)= " ; Getcommands(2)
  11.    Debug "Getcommands(3)= " ; Getcommands(3)
  12.    Debug " ";                                               'command>> az 0 0  'printing proper spaces
  13.  
  14.    Rs485_adres_temp = Val(getcommands(1))                   'zamien tekst na numer
  15.  
  16.    Select Case Rs485_adres_temp
  17.  
  18.       Case Rs485_adres :                                    'komneda 1 case 1, sprawdzenie adresu
  19.          Debug "odebrlem poprawnie adres "
  20.  
  21.  
  22.          Select Case Getcommands(2)
  23.             Case G2_c_1:                                    'aa
  24.                Debug "jestem w command 2, case 1 "
  25.                Call Spi_angle_read                          'angle
  26.  
  27.             Case G2_c_2:                                    'temp
  28.                Debug "jestem w command 2, case 2 "          'temp
  29.                Call Ds18b20_temp_read
  30.  
  31.             Case G2_c_3:                                    'cc
  32.  
  33.                Debug "jestem w command 2, case 3 "          'c
  34.           'zrób cos
  35.  
  36.             Case G2_c_4:                                    'sp =wind speed
  37.                Debug "jestem w command 2, case 4 "          '
  38.                Print Wind
  39.             Case G2_c_5:
  40.                Debug "jestem w command 2, case 5 "          ' diag_on
  41.                Flagi.2 = 1
  42.  
  43.             Case G2_c_6:
  44.                Debug "jestem w command 2, case 6 "          'diag_off
  45.                Flagi.2 = 0
  46.             Case G2_c_7:
  47.                Debug "jestem w command 2, case 7 "          'rs_term_on
  48.                Term_enable = 1
  49.  
  50.             Case G2_c_8:
  51.                Debug "jestem w command 2, case 8 "          'rs_term_off
  52.                Term_enable = 0
  53.  
  54.             Case Reboot:
  55.       'zrestartój system
  56.                Print
  57.                Print "Device will now reboot"
  58.                Start Watchdog
  59.                Do
  60.                Loop
  61.  
  62.             Case Bootloader:                                'load
  63.                Disable Interrupts
  64.                Config Watchdog = 16
  65.                Start Watchdog
  66.                Do
  67.                Loop
  68.  
  69.  
  70.             Case Help :                                     '?
  71.           'wysietl komendy
  72.                Print Chr(10) ; "Ekoder absolutny SP9DR"
  73.                Print "Version: " ; Version(2)
  74.                Print "RS_485 Adres= " ; Rs485_adres
  75.                Print "RS485, 120 Ohm terminacia = ";
  76.                If Portc.5 = 1 Then
  77.                Print "Wlaczona"
  78.                Else
  79.                Print "Wylaczona"
  80.                End If
  81.                Print Chr(10) ; " lista komend: "
  82.                Print "a------------Podaj azymut"
  83.                Print "t------------Podaj temperature"
  84.                Print "c------------Wolne"
  85.                Print "s------------Predkosc"
  86.                Print "diag_on------Diagnostyka wlacz"       'magnitude diagnostic
  87.                Print "diag_off-----Diagnostyka wylacz"
  88.                Print "rs_term_on---Terminacja wlacz"
  89.                Print "rs_term_off--Terminacja wylacz"
  90.                Print "reboot ------Restart systemu"
  91.                Print "load---------Aktualizuj oprogramowanie"
  92.                Print "?------------Wyswielt liste komend"
  93.  
  94.             Case Else
  95.  
  96.       'ponizej NIE USUWAJ TO JEST WAZNE!
  97.       'jak komenda nie rozpoznana zrób to
  98.                Print Prompt ; " " ; Uart_command ; " " ; Notincommands
  99.                Print Prompt
  100.                Getcommands(1) = ""
  101.                Getcommands(2) = ""
  102.                Getcommands(3) = ""
  103.  
  104.          End Select
  105.    'ponizej NIE USUWAJ TO JEST WAZNE!
  106.    'jak komenda nei rozpoznana zrób to
  107.          Getcommands(1) = ""
  108.          Getcommands(2) = ""
  109.          Getcommands(3) = ""
  110.  
  111.       Case Broadcast:                                       '255 broadcast do wszystkich
  112.  
  113.          'Select Case Getcommands(2)
  114. '            Case Reboot:
  115. '      'zrestartój system
  116. '               Print
  117. '               Print "Device will now reboot"
  118. '               Start Watchdog
  119.  
  120. '            Case Help :                                     '?
  121. '               Waitms Rs485_adres
  122. '               Print "Wind speed board ver: " ; Version(2)
  123. '               Print "RS_485 Adres= " ; Rs485_adres
  124.  
  125.  
  126. '            Case Else
  127. '                 'Print Prompt ; " " ; Uart_command ; " " ; Notincommands
  128. '               'Print Prompt
  129. '               Getcommands(1) = ""
  130. '               Getcommands(2) = ""
  131. '               Getcommands(3) = ""
  132. '         End Select
  133. '         Getcommands(1) = ""
  134. '         Getcommands(2) = ""
  135. '         Getcommands(3) = ""
  136.  
  137.  
  138.       Case Else
  139.       'ponizej NIE USUWAJ TO JEST WAZNE!
  140.          Debug "odebrlem zly adres "
  141.          Print Prompt ; " " ; Uart_command ; " " ; Notincommands
  142.          'Print Prompt
  143.          'Jelsi zly adres wyczysc wszytkie komorki z odebranymi danymi
  144.          Getcommands(1) = ""
  145.          Getcommands(2) = ""
  146.          Getcommands(3) = ""
  147.  
  148.    End Select
  149.    'ponizej NIE USUWAJ TO JEST WAZNE!
  150.    'jak komenda nei rozpoznana zrób to
  151.    Getcommands(1) = ""
  152.    Getcommands(2) = ""
  153.    Getcommands(3) = ""
  154. End Sub
Część kodu która nie powstała to miganie WS2812B jakoś nie było weny jakim kolorem migać i kiedy.
1.png
2.png
Gotowy twór wyglada tak (tu akurat jako miernik prędkośći wiatru):
3.png
Obudowę, ośkę i łożyskowanie wykonał forumowy kolega Jacek SQ2EER za co mu bardzo dziękuje.
Był to nasz wspólny projekt choć dzieli nas jakieś 2500 kilometrów i cztery kraje.
Z tego co wiem gotowy układ jest zamontowany w obrotnicy do anteny krótkofalarskiej.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony 09 lis 2020, 21:16 przez Pikczu, łącznie zmieniany 2 razy.
Awatar użytkownika
Jacek
Posty: 384
Rejestracja: 25 kwie 2016, 19:14

Re: 14 bitowy encoder magnetyczny AS5047D SPI

Post autor: Jacek » 22 paź 2020, 22:01

Witam - tak zgadza się jest zamontowany w rotorze - ale jeszcze na ziemi :( .
pozdrawiam Jacek.
ODPOWIEDZ