Hi @all mal wieder ;), ich versuche mich gerade in eine art Konfigurationsoberfläche per UART zusammen zu basteln. Leider komme ich mit dem "Ringpuffer" Prinzip zeichen zu empfangen nicht wirklich klar... und diese dann evtl. Auszuwerten... in meiner RX_ISR mache ich derzeitig folgendes: ******************************************************************** Uart_RX_Complete: push temp1 push temp2 push temp3 in Save_SREG, SREG sbr Flags, 1<<USART_RX in temp1, udr st x+,temp1 inc rs_puffer cpi rs_puffer, 8 breq rs_count out SREG, Save_SREG pop temp3 pop temp2 pop temp1 reti rs_count: clr rs_puffer ldi xl, low(rs232_rx_puffer) ldi xh, high(rs232_rx_puffer) reti ******************************************************************** Wenn ich jetzt davon ausgehe, das ich 8 Zeichen Empfangen habe (welche ja nach und nach kommen) wie lese ich diese jetzt gescheit aus... irgendwie bin ich durcheinander... bis jetzt hab ich das immer so gemacht. ISR setzt ein Flag das ein byte empfangen wurde, liest dieses aus und stored es in den SRAM Main schaut ob RX Flag gesetzt wurde und weis jetzt das ein Zeichen da ist und springt zu einem RS232 Receive Handler welcher das eine Zeichen verarbeitet... nur komme ich im moment nicht mit dem kopf weiter als ein zeichen... Gruß Dennis P.S: @peter habe mir deinen Bootloader auch angeschaut nur verstanden hab ich es immer noch nicht...
Hi du solltest, bei der Verwendung von mehreren reti's in einer ISR auch bei beiden deine Register wieder vom Stack holen. Matthias
@Matthias, uppss... hab ich noch gar nicht gesehen ;) Wird gleich gemacht ;) aber verstanden hab ich es leider dennoch nicht... (mit dem auswerten) Gruß Dennis
Oder einfach mal umstellen: Uart_RX_Complete: push temp1 push temp2 push temp3 in Save_SREG, SREG sbr Flags, 1<<USART_RX in temp1, udr st x+,temp1 inc rs_puffer cpi rs_puffer, 8 brne URXC1 ;Bei Zeichen < 8 zu URXC1 clr rs_puffer ldi xl, low(rs232_rx_puffer) ldi xh, high(rs232_rx_puffer) URXC1: out SREG, Save_SREG pop temp3 pop temp2 pop temp1 reti Bei anderweitiger Verwendung von X XL und XH auch noch auf den Stack pushen und poppen. Dabei muß dann natürlich deren Inhalt im SRAM abgelegt werden. Gruß Andi
@Andi, ok auch danke für den Hinweis ;) spart ein wenig mehr Code ;) nur auch dies ist noch nicht wirklich die beantwortung / hilfestellung für meine Frage ;) Wie werte ich den Ringpuffer den ich mit jedem ISR mit einem Zeichen fülle wieder aus ? Gruß Dennis
Ich schätze, Du benötigst 2 mal einen Pointer für den Ring-Buffer. Zum einen einen für die ISR und zum anderen einen für das "Abholprogramm" in der Main. Das Abholprogramm vergleicht zuerst seine Zugriffsadresse mit der Zugriffsadresse der ISR. Sind beide Adressen identisch, sind keine neuen Bytes zum abholen da sind sie unterschiedlich ist mindestens 1 Byte zum abholen da. Genauso die ISR. Die prüft vorher auch ihre Zugriffsadresse mit der vom Abholprogramm als Kontrolle, ob vom vermeintlich noch vollem Buffer mindestens 1 Byte abgeholt wurde oder nicht. Ist die Zugriffsadresse von der ISR um 1 kleiner, mit Berücksichtigung des 8-ter Sprunges, als die vom Abholprogramm, ist der Buffer noch voll ansonsten kann die ISR ein weiteres Byte in den Buffer schreiben. Ich würde an Deiner Stelle erst mal die Zugriffsadressen im SRAM speichern, sonst hast Du irgend wann keinen X- und Y-Pointer mehr für andere Dinge zur Verfügung. Gruß Andi
Ach ja, die Zugriffsadressen sind ja nur 1 Byte groß (0 - 7). Mit 8Bit-Befehlen kannst Du einfache Vergleiche durchführen und wenn Du die konkrete Adresse benötigts einfach die Zugriffsadresse auf den Anfang des Buffers addieren: lds r16,ISRAdr .... .... ldi xl,low(RingBuffer) ldi xh,high(RingBuffer) add xl,r16 clr r16 adc xh,r16 .dseg ISRAdr: .byte 1 RingBuffer: .byte 8 Gruß Andi
@Andi, klingt als währst Du ein wenig skeptisch ;) Hab ich vieleicht das Prinzip allgemein mir selber "VerKompliziert"? Oder ist die Herangehensweise mit dem Flag setzen und in Main überprüfen schon der richtige weg ? Gruß Dennis
Ich bin überhaupt nicht skeptisch! Das mit dem Flag ist vielleicht nicht der falsche Weg. Aber mit für Beide Routinen, ISR-Empfang und Abholprogramm im Main, ist es glaube ich einfacher und effizienter es mit 2 Pointern zu machen. Man kann es auch wie folgt machen: Variablen: 1. Pointer für die ISR = BuffISRAdr (1 Byte) 2. Pointer für das Abholprogramm = BuffMainAdr (1 Byte) 3. Füllstandsanzeige für den Buffer = BuffFill (1 Byte) 4. Der Buffer = Buffer (8 Bytes) Die ISR prüft vor dem ablegen eines Byte BuffFill. Ist BuffFill kleiner als 8 kann das Byte an der Adresse BuffISRAdr + Buffer abgelegt werden, BuffFill um 1 erhöht werden und BuffISRAdr um 1 erhöht werden (bei 8 auf 0 setzen). Ansonsten ist der Buffer voll weil vom Abholprogramm noch nichts abgeholt wurde und das Byte verschwindet dann. Genauso überprüft das Abholprogramm BuffFill. Ist BuffFill ungleich 0 kann mindestens ein Byte abgeholt werden,BuffFill um 1 verringert werden und BuffMainAdr um 1 erhöht werden (bei 8 auf 0 setzen). Bei BuffFill = 0 ist kein Byte zum abholen da. Im Abholprogramm kann das dann in einer Schleife durchgeführt werden bis eine Kopie von BuffFill für die Schleife 0 ist. Die Variablen dafür kann man ja im SRAM speichern und mit LDS und STS darauf zugreifen: .dseg BuffISRAdr: .byte 1 BuffMainAdr: .byte 1 BuffFill: .byte 1 Buffer: .Byte 8 Gruß Andi
@Andi, also das letzte hab ich nun wirklich nicht so ganz verstanden ... :( habe jetzt erfolgreich geschaft Byte für Byte im SRAM abzulegen. Mache in der RX_ISR jetzt folgendes: ldi xl, low(RingBuffer) RingBuffer adresse laden ldi xh, high(RingBuffer) lds temp1, BufferAnzahl Anzahl der Zeichen add xl, temp1 zur Adresse addieren clr temp2 adc xh, temp2 in temp2, udr UDR einlesen st x, temp2 und an aktuelle adr store inc temp1 Dann +1 der Zeichen cpi temp1, 8 vergleichen mit max brne nochok1 Überlauf? clr temp1 dann anzahl auf 0 sts BufferAnzahl, temp1 und storen nochok1: sts BufferAnzahl, temp1 ansonsten store akt. anz. sbr Flags, 1<<USART_RX Flag setzen für Zeichen da Das Speichern in den Ringpuffer funktioniert prinzipiell schon. Ich habe mir mal Peter Danneger seinen Bootloader angeschaut, und finde es sehr interessant wie er die empfangen "Strings" per Sprungtabelle auswertet nur so richtig verstanden hab ich das ganze ganz und gar nicht... war ne lange ratlose nacht gestern... Warum ich das ganze immer noch nicht verstehe ? Keine Ahnung nach so vielem Lesen und Schreiben meines Sources vollkommen durcheinander... arggg... schrei Gruß Dennis P.S.: @Andi, vieleicht erbarmst Du dich noch einmal und versuchst es mir anders zu erklären... thnks.
Hi Dennis, hast du allgemeine Verständnis-Probleme mit Ringspeichern? Guck dir mal diesen Link an, vielleicht hilft er dir: http://www.zeiner.at/c/ringbuffer.html Ich habe diesen jetzt mal mit Abwandlungen für mich übernommen, und es geht, soweit ich das beurteilen kann. Ich brauche ihn, genauso wie du, für meine serielle Schnittstelle. Dort habe ich das Problem, dass ich trotz Hardware-Handshake einige Bytes verliere (der PC reagiert nicht schnell genug auf das Sperren der Handshake-Leitungen), daher mache ich es nun über den Ringbuffer. Gruß Ralf
Hi Ralf, wie ich den Ringpuffer aufbauen muss um zu speichern, hab ich soweit verstanden... nur wie ich diesen dann auswerte, da hängt es bei mir... ein einzelnes Byte auswerten ist ja nicht wirklich ein Problem nur mehrere Bytes auswerten und vor allem den Puffer dann wieder richtig auszulesen. Diese Kombination zwischen auslesen und auswerten, da hängt es irgendwie, das ich einfach nicht weis wie ich es aufbauen soll. Nehmen wir einfach mal an, das ich sage ich möchte die Uhrzeit in einem DS1337 speichern. z.B. Byte C für Uhr einstellen und dann zeit übergeben. (Ist aber nur ein Beispiel für mein Problem) Gruß Dennis
Tja, das mit dem Auswerten ist halt so ne Sache. Kommt auch darauf an, was Du vor hast. Willst Du Deinem Kontroller Befehle in Klartext übergeben brauchst Du komplette Vergleiche von Zeichenketten. Willst Du Byte-Befehle übergeben ist das einfach mit Zahlenvergleichen zu machen und dann halt noch die Parameter (Uhrzeit) in entsprechend gleicher Reihenfolge zu übergeben. Der Buffer ist nur dazu da, damit der Prozessor bei extremer Beschäftigung anderswo möglichst keine Bytes verliert. Und wenn er das doch tut, kann man den Buffer vergrößern. Für die Auswertung von mehreren Bytes brauchst Du ein weiteres Zwischenlager im SRAM mit x Bytes wo das Abholprogramm (GET) die Bytes der Reihe nach hineinschreibt. Diese Größe hängt auch von dem ab, was Du anstellen willst. Gruß Andi
Hi Dennis, jetzt wird mir dein Problem klarer. Wenn ich es richtig verstanden habe, brauchst du das gleiche, was ich für meinen ISP-Programmer realisiert habe: Ich würde erstens mal das AUSLESEN vom AUSWERTEN komplett trennen. Der Ringbuffer ist nur für deine Schnittstelle da, sonst für NIX. Ich habe mir Gedanken zum Datensatz-Aufbau gemacht, den ich für den Programmer verwende. Das sieht bei mir wie folgt aus: Das erste Byte ist immer ein darstellbares Zeichen aus dem ASCII-Satz und dient als "Befehlskennung" Alle weiteren Zeichen des Datensatzes sind immer ASCII-Hex-Zeichen, also "0" - "9" und "A" - "F" und somit Daten. Jeder Befehl wird mit dem CR-Zeichen (Return) abgeschlossen. Ich empfange die Daten und setze sie in einen Ringbuffer, der nur für die serielle Schnittstelle da ist. Aus dem Ringbuffer lese ich die Daten in den "Befehlsbuffer" bis zum CR-Zeichen ein, wobei ich alle Zeichen bis auf das erste dahingehend prüfe, ob es wirklich ASCII-Hex-Zeichen sind. Dann wird aus dem Befehlsbuffer das erste Zeichen (-> Befehlszeichen) gelesen und geprüft, ob der Befehl bekannt ist. Wenn ja, übergebe ich den kompletten Befehls-Buffer der zum Befehl gehörenden Subroutine, die ihrerseits die Auswertung der restlichen Daten vornimmt (passt die Menge der Daten zum Befehl, sind die Daten unsinnig, usw.). Zum Beispiel eine Routine für das Lesen, wobei der Aufbau wie folgt ist: RAAAAMM R als Klartext (ASCII-Zeichen "R") für Read AAAA ASCII-Hex-Zeichen für die Adresse MM ASCII-Hex-Zeichen für die Menge der auszulesenden Datenbytes In deinem Fall heisst das dann wohl, das du beim Befehl "C" die SetClock-Routine aufrufst, die die restlichen Daten im Befehlsbuffer prüft, und wenn sie gültig sind, schreibst du die Uhrzeit in deinen Uhren-IC. Kannst du damit was anfangen? (Nebenbei, wenn es sich einfacher lösen lässt, bin ich für Vorschläge dankbar ;-)) Falls du den entsprechenden Code-Schnipsel haben möchtest, sag Bescheid. Gruß Ralf
@Dennis, der Trick bei meinem Empfangspuffer ist, daß er komplette 256 Byte belegt. Wenn man dann das High-Byte der Adresse konstant hält: ; Receive Interrupt ;------------------------------------------------ URXCint: ldi xh, high(rx_buff) ;set high address byte in ia0, UDR st x+, ia0 reti ergibt sich ein automatisches Umlaufen ohne irgendwelche Tests. Der X-Pointer ist dabei für den Interrupt reserviert, da man ja im Hauptprogramm bequem mit 2 Pointern (Y,Z) auskommt. Und bei der Auswertung wird dann auch immer nur das Low-Byte hochgezählt: exec_command: ldi zl, low( command_table * 2 - 3 ) ldi zh, high( command_table * 2 - 3 ) mov a1, yl ;save command start _coi1: adiw zl, 3 ;skip rjmp + odd zero byte andi zl, 0xFE ;adjust to next word mov yl, a1 clt rjmp _coi3 _coi2: ld a0, y inc yl ;increment low address only ! eor a0, r0 andi a0, 0x5F ;ignore case breq _coi3 set ;not matching _coi3: lpm r0, z+ tst r0 brne _coi2 brts _coi1 ;test next command lsr zh ;byte to word address ror zl ijmp ;jump after command string Somit ist kein extra Umkopieren notwendig. In der command_table stehen die einzelnen Kommandos gefolgt von einem RJMP zu der entsprechenden Funktion. Frag ruhig, wenn Du etwas nicht verstehst. Peter
Aber man könnte es auch noch mittels AND auf eine 2-er-Potenz verkleinern (für andere Zwecke): Z. B. für einen Buffer mit 64 Byte: URXCint: ldi xh, high(rx_buff) ;set high address byte in ia0, UDR st x+, ia0 andi xl,0x3F ;0b00111111 reti Das AND sorgt dafür, das sich der Pointer nur von 0 bis 63 (relative Adresse) bewegt. Bei 32 oder 16 Byte dann "and xl,0x1F" oder "and xl,0x0F" Natürlich muß man auch da aufpassen, das der Buffer keine 256 Byte-Schwelle überschreitet was man mit .org Sicherstellen kann. Gruß Andi
@Andi, URXCint: ldi xh, high(rx_buff) ;set high address byte in ia0, UDR st x+, ia0 andi xl,0x3F ;0b00111111 reti Oh oh oh oh, ganz böses Foul ! "andi xl,0x3F" ändert das SREG, also schleunigst sichern !!! Peter
Ups... ... ist schon klar. War ja nur mal als Beispiel eingeworfen. OK, kostet wieder Rechenzeit, und wie es bei Deiner Routine aussieht, ändert kein Befehl das SREG was wiederum Zeit spart wenn man es nicht sichern (und andere Register) muß. Gruß Andi
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.