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:
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $nocompile
- ' AS5047D SPI read angle
- ' By SP9DR 2019 v.1
- Sub Spi_angle_read
- Spiout Spi_data(1) , 2
- Anglecom = Spimove(spi_data(1) , 2)
- Swap Anglecom
- Show1 = Anglecom And &B00111111_11111111 'maska na 14 bitów
- Angle = Show1 * 36000 'do pierwszej cyfry po przecinku
- Angle1 = Angle / 16383
- Print Chr(10) ; Angle1
- Tex = Str(angle1)
- Kat = Format(tex , "0.00")
- Print " kat= " ; Kat
- End Sub
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $nocompile
- ' AS5047D SPI diagnostic info
- ' By SP9DR 2019 v.1
- Sub Spi_diaagc_read
- Spiout Spi_data(3) , 2
- Diaagc = Spimove(spi_data(3) , 2 )
- Swap Diaagc
- If Diaagc.8 = 1 Then
- Print "internal offset loop ok"
- Else
- Print "internal offset loops not ready "
- End If
- If Diaagc.9 = 1 Then
- Print "CORDIC overflow error"
- End If
- If Diaagc.10 = 1 Then
- Print "Magnetic field strength too high; AGC=0x00"
- End If
- If Diaagc.11 = 1 Then
- Print "Magnetic field strength too low; AGC=0xFF"
- End If
- Agc = Diaagc And &B0000_0000_1111_1111 'maska na 14 bitów
- Print Bin(diaagc) ; " AGC value"
- Print " AGC value= " ; Agc
- End Sub
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $nocompile
- 'Odczyt sily pola
- 'AS5047D SPI maginitude reading
- 'By SP9DR 2019 v.1
- Sub Spi_magnitude_read
- Spiout Spi_data(5) , 2
- Magnitude = Spimove(spi_data(5) , 2)
- Swap Magnitude
- Mag = Magnitude And &B00111111_11111111 'maska na 14 bitów
- Print " MAG value= " ; Mag ' magnitude
- End Sub
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- '-------------------------------------------------------------------------------
- ' Pawel Labedz SP9DR for hardware version 1.4
- ' Copyright Pawel Labedz 2019
- ' All rights reserved
- '```````````````````````````````````````````````````````````````````````````````
- '-------------------------------------------------------------------------------
- Debug Off
- '$sim
- $regfile = "m328pdef.dat"
- $crystal = 18432000
- $hwstack = 64
- $swstack = 64
- $framesize = 64
- $baud = 38400
- $projecttime = 289
- Config Submode = New
- '-------------------------------------------------------------------------------
- $version 0 , 0 , 49
- Dim Firmware As String * 7
- Firmware = "Ver_0.1"
- '-------------------------------------------------------------------------------
- Config Watchdog = 2048
- 'Start Watchdog
- '-------------------------------------------------------------------------------
- Config Com1 = 38400 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
- Config Serialin = Buffered , Size = 128
- Config Serialout = Buffered , Size = 128
- Enable Serial
- '------------------------------timer 1------------------------------------------
- Const Timer1reload = 31250
- Config Timer1 = Timer , Prescale = 256
- Load Timer1 , Timer1reload
- On Ovf1 Timer1_isr
- Enable Timer1
- Start Timer1
- 'Timer value explination
- ' The timer is a 16Bit timer, it overflows when the timer reaches 65536
- ' The AVR is running at 8000000Hz, the prescaler is 256
- ' Each tick is 0.032 ms - (1 / CPUSpeed in KHz ) * Prescaler
- ' The timer needs 3125 ticks to reach the required time ( 3125 * 0.032 = 100ms)
- ' The start value for the timer must be set to 34286 so that it will overflow at 65536 after 3125 ticks
- ' NOTE: The load command does the inversion for you (256-value or 65536-value)
- '-------------------------------SPI config---------------------------------
- Config Spi = Hard , Interrupt = Off , Data_order = Msb , Master = Yes , Polarity = Low , Phase = 1 , Clockrate = 128 , Noss = 0
- 'polarity =0 and phase 1 = spi mode 1
- '--------------------------------SPI variable-----------------------------------
- Dim Spi_data(8) As Byte
- Spi_data(1) = &HFF ' pobierz kat msb
- Spi_data(2) = &HFF ' pobierz kat lsb
- Spi_data(3) = &HFF 'diagnostyka msb
- Spi_data(4) = &HFC 'diagnostyka lsb
- Spi_data(5) = &H7F 'sila magnesu msb
- Spi_data(6) = &HFD 'sila magnesu lsb
- Spi_data(7) = &H00 'nop msb
- Spi_data(8) = &H00 'nop lsb
- '-------------------------------WS2818b---------------------------------
- Config Rainbow = 1 , Rgb = 4 , Rb0_len = 2 , Rb0_port = Portd , Rb0_pin = 6
- ' ^-- using rgbW leds #### MUST BE FIRST PARAMETER when defined ###
- ' ^ connected to pin 0
- ' ^------------ connected to portB
- ' ^-------------------------- 8 leds on stripe
- ' ^------------------------------------- 1 channel
- 'Global Color-variables
- Dim Color(3) As Byte
- R Alias Color(_base) : G Alias Color(_base + 1) : B Alias Color(_base + 2)
- 'CONST
- Const Numleds = 2
- Dim N As Byte
- '-------------------------------------------------------------------------------
- Dim Anglecom As Word
- Dim Diaagc As Word
- Dim Diag_bits As Word
- Dim Magnitude As Word
- Dim Mag As Word
- Dim Agc As Word
- Dim Ttx As Word
- Dim Angle As Dword
- Dim Angle1 As Dword
- Dim Kat As String * 6
- Dim Tex As String * 6
- Dim Show1 As Word
- Dim Index As Byte
- '----------------------------------UART adress --------------------------------
- Dim Rs485_adres As Byte , Rs485_adres_ee As Eram Byte At &H10 'Rs485 address
- Dim Rs485_adres_temp As Byte ' potrzebne przy porownywaniuadresu odebranego z wlasciwym
- '----------------------------------UART variable--------------------------------
- Dim Rs485_time_out As Word
- Dim Uart_flag As Byte 'flag used for uart
- Dim Lcount As Byte '
- Dim Char_ As Byte
- Dim Uart_command As String * 20 'Needs to be long enough for commands
- Dim Getcommands(10) As String * 11 'Here we have an array to chop up the commands from RS232
- '-------------------------------------------------------------------------------
- Dim Ds_t(2) As Byte ' array for temperature read form Ds18b20
- Dim Temp1 As Integer 'zmienna przchowuje wartosc temp1
- Dim Ds_index As Byte ' help variable for index value
- Dim Ds_signature(8) As Byte
- Dim Wind As Dword 'variable
- Dim Tick As Byte 'ziemnan na timer 1
- Dim Flagi As Byte ' flagi pomocnicze
- Dim Max_ As Byte
- Dim Tabilca As Byte
- Dim Binarnie As Word
- '--------------------------Uart commands----------------------------------------
- Const On_ = 1
- Const Off_ = 0
- '-------------------------------------------------------------------------------
- Const Broadcast = 255 'broadcast do wszytkich
- 'Const G1_c_2 =
- 'Const G1_c_3 =
- 'Const G1_c_4 =
- 'Const G1_c_5 =
- 'Const G1_c_6 =
- 'Const G1_c_7 =
- 'Const G1_c_8 =
- '------------------------------------------------------------------------------
- Const G2_c_1 = "a"
- Const G2_c_2 = "t"
- Const G2_c_3 = "c"
- Const G2_c_4 = "s"
- Const G2_c_5 = "diag_on" 'magnitude diagnostic
- Const G2_c_6 = "diag_off"
- Const G2_c_7 = "rs_term_on"
- Const G2_c_8 = "rs_term_off"
- Const Reboot = "reboot"
- Const Bootloader = "load"
- Const Help = "?"
- Const Notincommands = " nie rozpoznano "
- Const Ok = "ack"
- Const Prompt = "command>>"
- 'komnedy wewnatrz get command 2
- Const G3_c_1 = " i"
- Const G3_c_2 = " j"
- '-------------------------------------------------------------------------------
- Config 1wire = Portc.1
- Config Portc.3 = Output
- Rx_enable Alias Portc.3 'RX enable for RS 485
- Portc.3 = 0
- Config Portc.4 = Output
- Tx_enable Alias Portc.4 'TX enable rs485
- Portc.4 = 1 'tx enabled
- Config Portc.5 = Output
- Term_enable Alias Portc.5 ' internal 120 ohm termiantion for rs485
- Portc.5 = 1
- Config Portd.2 = Input 'int 0 index pin
- Portd.2 = 1
- Config Portd.3 = Output
- Slew_en Alias Portd.3 'slew rate enable for rs485
- Portd.3 = 0
- Config Portd.6 = Output 'WS2818b led
- '-------------------------------------------------------------------------------
- Config Int0 = Falling 'home position sensor
- On Int0 Int0_isr
- Enable Int0
- '---------------------------subs include file-----------------------------------
- '$include "Subs\Rs485_read.inc"
- $include "Subs\Spi_angle_read.inc"
- $include "Subs\Spi_magnitude_read.inc"
- $include "Subs\Spi_DIAAGC_read.inc"
- $include "Subs\Uart_rx.inc"
- $include "Subs\DS18b20_register.inc"
- $include "Subs\DS18b20_temp_read.inc"
- '-------------------------------------------------------------------------------
- '-------------------------------------------------------------------------------
- Rs485_adres = Rs485_adres_ee 'read adress from eeprom
- '-------------------------------------------------------------------------------
- Enable Interrupts
- Print Chr(10) ; "Position sensor by SP9DR"
- Print "Dla Pana Jacka SQ2EER"
- Print "Version: " ; Version(2)
- Print "RS_485 Adres= " ; Rs485_adres
- 'Print "SPI test"
- Print "watchdog started"
- Start Watchdog
- Spiinit
- 1wreset
- 1wwrite &HCC 'skip all
- 1wwrite &H44 'convert temp
- Wait 1
- Clear Serialout
- Clear Serialin
- Uart_command = ""
- Term_enable = 1
- Rb_selectchannel 0 ' select first channel
- R = 50 : G = 0 : B = 100 ' define a color
- Rb_setcolor 1 , Color(1) ' update leds
- Rb_setcolor 0 , Color(2) ' update leds
- Rb_send
- '-------------------------------------------------------------------------------
- Do
- If Ischarwaiting() > 0 Then 'calls _gotchar and use URXC
- Char_ = Inkey() 'get char from buffer
- Rs485_time_out = 0
- If Char_ = 13 Or Len(uart_command) > 20 Then ' check for ENTER of more then 20 characters
- Call Uart_rx '
- 'Print '
- 'Print Prompt; 'Using a constant will let us change the prompt
- Uart_command = ""
- Else
- Uart_command = Uart_command + Chr(char_) 'buffor building
- Print Chr(char_) ; 'this is echo
- End If
- End If
- If Flagi.2 = 1 Then ' if diagnostic enable
- If Flagi.3 = 1 Then
- Call Spi_angle_read
- Call Spi_diaagc_read
- Call Spi_magnitude_read
- Flagi.3 = 0
- End If
- End If
- Reset Watchdog
- If Uart_command <> "" Then
- Incr Rs485_time_out
- End If
- If Rs485_time_out > 65000 And Uart_command <> "" Then
- Debug "czyszczenie"
- Clear Serialin
- Uart_command = ""
- End If
- Reset Watchdog
- Loop
- End
- Int0_isr: 'wind speed meter index value
- 'Incr Index
- 'Wind = Index '* 24
- Return
- Timer1_isr:
- Load Timer1 , Timer1reload
- Incr Tick
- If Tick = 2 Then
- Set Flagi.1 '
- 'elseif Tick = 10 Then
- Flagi.3 = 1
- Tick = 0
- End If
- Return
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $nocompile
- 'DSS18b20 temperature read
- '*******************************************************************************
- 'DALLAS DS18B20 ROM and scratchpad commands''''''''''''''''''''''''''
- '1wwrite....
- '&H 33 read rom - single sensor
- '&H 55 match rom, followed by 64 bits
- '&H CC skip rom
- '&H EC alarm search - ongoining alarm >TH <TL
- '&H BE read scratchpad
- '&H 44 convert T
- '*******************************************************************************
- '*******************************************************************************
- Sub Ds18b20_temp_read
- 1wreset
- 1wwrite &HCC
- 1wwrite &HBE
- Ds_t(1) = 1wread(2)
- Wait 1
- 1wreset
- 1wwrite &HCC
- 1wwrite &H44
- Temp1 = Ds_t(2) ' starszy bajt temperatury
- Shift Temp1 , Left , 8 'przesun w lewo o 8 miejsc
- Temp1 = Temp1 + Ds_t(1)
- Shift Temp1 , Right , 4
- Print "temp: " ; Temp1
- End Sub
Czyli RS485 i zestaw komend.
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $nocompile
- Sub Uart_rx():
- Reset Watchdog
- Debug "jestem w uar_rx"
- Lcount = Split(uart_command , Getcommands(1) , " ") 'This choping coomand after space
- Debug Chr(13)
- Debug "lcount= " ; Lcount
- Debug "uart_command= " ; Uart_command
- Debug "Getcommands(1)= " ; Getcommands(1)
- Debug "Getcommands(2)= " ; Getcommands(2)
- Debug "Getcommands(3)= " ; Getcommands(3)
- Debug " "; 'command>> az 0 0 'printing proper spaces
- Rs485_adres_temp = Val(getcommands(1)) 'zamien tekst na numer
- Select Case Rs485_adres_temp
- Case Rs485_adres : 'komneda 1 case 1, sprawdzenie adresu
- Debug "odebrlem poprawnie adres "
- Select Case Getcommands(2)
- Case G2_c_1: 'aa
- Debug "jestem w command 2, case 1 "
- Call Spi_angle_read 'angle
- Case G2_c_2: 'temp
- Debug "jestem w command 2, case 2 " 'temp
- Call Ds18b20_temp_read
- Case G2_c_3: 'cc
- Debug "jestem w command 2, case 3 " 'c
- 'zrób cos
- Case G2_c_4: 'sp =wind speed
- Debug "jestem w command 2, case 4 " '
- Print Wind
- Case G2_c_5:
- Debug "jestem w command 2, case 5 " ' diag_on
- Flagi.2 = 1
- Case G2_c_6:
- Debug "jestem w command 2, case 6 " 'diag_off
- Flagi.2 = 0
- Case G2_c_7:
- Debug "jestem w command 2, case 7 " 'rs_term_on
- Term_enable = 1
- Case G2_c_8:
- Debug "jestem w command 2, case 8 " 'rs_term_off
- Term_enable = 0
- Case Reboot:
- 'zrestartój system
- Print
- Print "Device will now reboot"
- Start Watchdog
- Do
- Loop
- Case Bootloader: 'load
- Disable Interrupts
- Config Watchdog = 16
- Start Watchdog
- Do
- Loop
- Case Help : '?
- 'wysietl komendy
- Print Chr(10) ; "Ekoder absolutny SP9DR"
- Print "Version: " ; Version(2)
- Print "RS_485 Adres= " ; Rs485_adres
- Print "RS485, 120 Ohm terminacia = ";
- If Portc.5 = 1 Then
- Print "Wlaczona"
- Else
- Print "Wylaczona"
- End If
- Print Chr(10) ; " lista komend: "
- Print "a------------Podaj azymut"
- Print "t------------Podaj temperature"
- Print "c------------Wolne"
- Print "s------------Predkosc"
- Print "diag_on------Diagnostyka wlacz" 'magnitude diagnostic
- Print "diag_off-----Diagnostyka wylacz"
- Print "rs_term_on---Terminacja wlacz"
- Print "rs_term_off--Terminacja wylacz"
- Print "reboot ------Restart systemu"
- Print "load---------Aktualizuj oprogramowanie"
- Print "?------------Wyswielt liste komend"
- Case Else
- 'ponizej NIE USUWAJ TO JEST WAZNE!
- 'jak komenda nie rozpoznana zrób to
- Print Prompt ; " " ; Uart_command ; " " ; Notincommands
- Print Prompt
- Getcommands(1) = ""
- Getcommands(2) = ""
- Getcommands(3) = ""
- End Select
- 'ponizej NIE USUWAJ TO JEST WAZNE!
- 'jak komenda nei rozpoznana zrób to
- Getcommands(1) = ""
- Getcommands(2) = ""
- Getcommands(3) = ""
- Case Broadcast: '255 broadcast do wszystkich
- 'Select Case Getcommands(2)
- ' Case Reboot:
- ' 'zrestartój system
- ' Print
- ' Print "Device will now reboot"
- ' Start Watchdog
- ' Case Help : '?
- ' Waitms Rs485_adres
- ' Print "Wind speed board ver: " ; Version(2)
- ' Print "RS_485 Adres= " ; Rs485_adres
- ' Case Else
- ' 'Print Prompt ; " " ; Uart_command ; " " ; Notincommands
- ' 'Print Prompt
- ' Getcommands(1) = ""
- ' Getcommands(2) = ""
- ' Getcommands(3) = ""
- ' End Select
- ' Getcommands(1) = ""
- ' Getcommands(2) = ""
- ' Getcommands(3) = ""
- Case Else
- 'ponizej NIE USUWAJ TO JEST WAZNE!
- Debug "odebrlem zly adres "
- Print Prompt ; " " ; Uart_command ; " " ; Notincommands
- 'Print Prompt
- 'Jelsi zly adres wyczysc wszytkie komorki z odebranymi danymi
- Getcommands(1) = ""
- Getcommands(2) = ""
- Getcommands(3) = ""
- End Select
- 'ponizej NIE USUWAJ TO JEST WAZNE!
- 'jak komenda nei rozpoznana zrób to
- Getcommands(1) = ""
- Getcommands(2) = ""
- Getcommands(3) = ""
- End Sub
Gotowy twór wyglada tak (tu akurat jako miernik prędkośći wiatru): 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.