Hallöchen, ich bräuchte mal wieder Hilfe bei einem S-Bus Dekoder.
Ich möchte einen S-Bus -> PWM - Konverter programmieren. Dazu, versuche
ich nun erst einmal den S-Bus zu dekodieren, um auf einem Display
dezimal den Wertebereich jedes Kanals angezeigt zu bekommen. Doch egal
was ich wie programmiere, ich bekomme immer nur Zahlenmüll angezeigt.
Vielleicht habe ich die spezifikationen des Busses nicht verstanden,
oder ich mache programmtechnisch einen Fehler.. ?!
Nun, zu meiner Hardware:
Ich benutze zum testen einen ATMega 16 mit 16 MHz externem
Taktoszillator. Da der S-Bus ja ein invertierter serieller Bus sein
soll, gebe ich das Signal, generiert aus einem FrSky X8R Empfänger
invertiert auf den RX des Mega 16. (Bild - S-Bus-invert.png)
Ein Display 2x16 hängt am Port-C.
Die Hardware des Prozessors initialisiere ich wie folgt:
1 | reset: ldi r16, HIGH (RAMEND)
| 2 | out SPH, r16
| 3 | ldi r16, LOW(RAMEND)
| 4 | out SPL, r16 ;Stack
| 5 | ldi r16, 0xFF
| 6 | out DDRC, r16 ;Port-C-Ausgang
| 7 | com r16
| 8 | out PORTC, r16 ;Port-C-Low
| 9 | out DDRD, r16 ;Port-D-Eingang
| 10 | ldi r16, 0b11111110
| 11 | out PORTD, r16 ;Pullups setzen, bis auf RX - PD-0
| 12 | ldi r16, 0b00000001
| 13 | out DDRB, r16 ;PB-0 ausgang, da dort eine LED hängt
| 14 | clr r16
| 15 | out PORTB, r16
| 16 | out UBRRH, r16 ;Bit-Rate-Register-High nullen
| 17 | ldi r16, 9
| 18 | out UBRRL, r16 ;Bit Rate Register Low = 9 (UBBR = ( fosc/16*Baud) -1 ) = (16000000 / (16*100000)) = 10 -1 = 9 )
| 19 | ldi r16, 0b10010000
| 20 | out UCSRB, r16 ;RX Enable und RX Complete Interrupt Enable
| 21 | ldi r16, 0b10101110
| 22 | out UCSRC, r16 ;Gerade Paritaet / 2 Stop Bits (Obwohl für empfänger laut Datenblatt nicht konfigurierbar) und 8 Bit Charakter Size
|
Die UART (RX-Complete) Interrupt Routine (Zurzeit nach vielen
versuchen):
1 | uartrxok: in r2, SREG
| 2 | push r20
| 3 | push r21
| 4 | push r22
| 5 | push YL
| 6 | push YH
| 7 | sbrc r19, 0 ;gesetzt wenn Startbyte empfangen wurde
| 8 | rjmp getdata ;dann empfange Datenbates der einzelnen Kanäle
| 9 | in r21, UDR ;Datenregister einlesen
| 10 | cpi r21, 0b11110000 ;mit Startbyte vergleichen
| 11 | brne enduartint ;kein Startbyte dann ende
| 12 | sbr r19, 1 ;Statusbit für datenempfang setzen
| 13 | ldi r22, 24 ;Zähler für 24 Bytes einstellen
| 14 | sts $006C, r22 ;Zähler sichern
| 15 | ldi YL, LOW ($0070) ;Ram Zeiger Setzen
| 16 | ldi YH, HIGH($0070)
| 17 | sts $006A, YL ;Ram Zeiger sichern
| 18 | sts $006B, YH
| 19 | cbi PORTB, 0 ;LED aus schalten
| 20 | rjmp enduartint ;und ende
| 21 | getdata: in r20, UDR ;Datenregister einlesen
| 22 | lds YL, $006A ;Aktuellen Ram-Zeiger laden
| 23 | lds YH, $006B
| 24 | lds r22, $006C ;Aktuellen Byte Zähler laden
| 25 | st Y+, r20 ;Empfangenes Datenbyte ins Ram schreiben und Ram Zeiger um 1 erhöhen
| 26 | sts $006A, YL ;Ram Zeiger wieder sichern
| 27 | sts $006B, YH
| 28 | dec r22 ; Byte Zähler um 1 verringern
| 29 | breq enddata ;wenn alle bytes empfangen dann ->enddata
| 30 | sts $006C, r22 ;sonst Byte Zähler wieder sichern
| 31 | rjmp enduartint ;und ende
| 32 | enddata: cbr r19, 1 ;Statusbyte wieder löschen
| 33 | sbr r19, 2 ;Statusbit für fertigen Empfang setzen
| 34 | sbi PORTB, 0 ;LED einschalten
| 35 | enduartint: pop YH
| 36 | pop YL
| 37 | pop r22
| 38 | pop r21
| 39 | pop r20
| 40 | out SREG, r2
| 41 | reti
|
Nachdem alle bytes empfangen wurden versuche ich einzig und alleine die
Daten für den ersten Kanal heraus zu holen. Da die daten ja nahtlos
zusammenhängen sollen (so wie ich es verstanden habe) und 11 Bit
betragen und somit aus den ersten 8 Bits des ersten Bytes plus den 3
Bits des zweiten Bytes bestehen und das höchstwertige Byte Rechts liegen
soll schiebe ich die bits folgendermaßen in der nächsten Routine
zurecht. Erst fünf mal nach rechts und dann 11 bits links in 2 leere
register um das höchstwertige bit wieder links für die dezimal
umrechnung zu haben)
1 | ortbits: push YL
| 2 | push YH
| 3 | push r20
| 4 | push r21
| 5 | push r22
| 6 | ldi YL, LOW ($0070)
| 7 | ldi YH, HIGH($0070)
| 8 | clr r21
| 9 | clr r22
| 10 | ld r17, Y+
| 11 | ld r18, Y
| 12 | ror r17
| 13 | ror r18
| 14 | ror r17
| 15 | ror r18
| 16 | ror r17
| 17 | ror r18
| 18 | ror r17
| 19 | ror r18
| 20 | ror r17
| 21 | ror r18
| 22 | ldi r20, 11
| 23 | loop10: ror r17
| 24 | ror r18
| 25 | rol r21
| 26 | rol r22
| 27 | dec r20
| 28 | brne loop10
| 29 | sts $0090, r21
| 30 | sts $0091, r22
| 31 | pop r22
| 32 | pop r21
| 33 | pop r20
| 34 | pop YH
| 35 | pop YL
| 36 | ret
|
danach erfolgt die dezimal Umwandlung dieser beiden ergebnis bytes (aus
den Ram Zellen $0090 und $0091) und werden aufs Display ausgegeben. (Das
funktioniert auch) Man sieht auch, dass sich die Zahlen ändern, wenn ich
den Knüppel für kanal 1 bewege, aber eben total wirr, als wenn... tja
wenn ich das wüsste... Als wenn ich die daten falsch interpretiere...
als wenn der Uart nicht richtig konfiguriert und ich keine Ahnung welche
Bytes erhalte... Als wenn ich falsch sortiere.. oder oder oder. Ich
weiss es nicht. Mittlerweile verstehe ich nur noch Bahnhof.
Vielleicht hat ja jemand von euch den Bus schon erfolgreich über den
UART decodiert und kann mir mal stützend unter die Arme greifen. Wäre
echt dankbar, denn ich weiss grad nicht mehr weiter, geschweige denn was
ich falsch mache.
Falls noch weitere infos benötigt werden, bitte sagen. Ansonsten erst
mal besten Dank für eure mühe.
Gruß, Andy
Falls es hilft, das S-Bus protokoll habe ich aus folgendem PDF...
S-BUS protocol
Note- Much of this first page is from mbed, but it was written for the
original s.bus using the "FASST MULT" mode. Here's the original page
link-
http://mbed.org/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/
The protocol is 25 Byte long and is send every 14ms (analog mode) or 7ms
(highspeed mode). One Byte = 1 startbit + 8 databit + 1 paritybit + 2
stopbit (8E2), baudrate = 100'000 bit/s, so one bit takes 10
microseconds.
The highest bit is send first, so data "00000000001" = 1024
The logic is inverted out of the receiver.
[startbyte] [data1] [data2] .... [data22] [flags][endbyte]
startbyte = 11110000b (0xF0)
data 1-22 = [ch1, 11bit][ch2, 11bit] .... [ch16, 11bit] (ch# = 0 bis
2047) channel 1 uses 8 bits from data1 and 3 bits from data2 channel 2
uses last 5 bits from data2 and 6 bits from data3 etc.
flags = bit7 = ch17 = digital channel (0x80) bit6 = ch18 = digital
channel (0x40) bit5 = Frame lost, equivalent red LED on receiver (0x20)
bit4 = failsafe activated (0x10) bit3 = n/a bit2 = n/a bit1 = n/a bit0 =
n/a
endbyte = 00000000b (Prior to the s.bus2 capable receivers, and the
R7003SB)
(as captured)
100001111100111111111100111011111000111111000000111111111100100111111100
11110111100
011111110100011111111110011011111100011111011100011111111000011111111110
01110111110
001111110110001111111111001011111110001111011110001111111010001111111111
00110111111
0001111101110001111111100001111111111001111111111
(inverted before FC input)
011110000011000000000011000100000111000000111111000000000011011000000011
00001000011
100000001011100000000001100100000011100000100011100000000111100000000001
10001000001
110000001001110000000000110100000001110000100001110000000101110000000000
11001000000
1110000010001110000000011110000000000110000000000
(inverted before FC input and grouped in 12 bit bytes)
011110000011 (Start byte)
000000000011 (data 1)
000100000111 CH1
000000111111 CH2
000000000011 CH3
011000000011 CH4
000010000111 CH5
000000010111 CH6
000000000011
001000000111 CH7
000001000111 CH8
000000001111
000000000011 CH9
000100000111 CH10
000000100111 CH11
000000000011
010000000111 CH12
000010000111 CH13
000000010111 CH14
000000000011
001000000111 CH15
000001000111 CH16
000000001111 (data 22)
000000000011 (flags byte) DCH1, DCH2, Frame lost, failsafe activated,
rest are NA
000000000011 (11 added by dead space between frames)
Hat sich erledigt. Habs hin bekommen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|