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
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)