hallo zusammen, habe mein Programm soweit fertig bis auf diesen Timer0 (8Bit Timer) beim AT90S8515. Ich brauch den Timer innerhalb einer Empfangsroutine, sprich beim Empfang von Bytes, dort initialisiere ich es ab dem 1.Byte-Empfang... da es nicht unendlich auf verlorene Bytes warten soll... das funktioniert soweit.. .aber beim 256mal tritt dieser Timeout immer wieder auf Habe eine gute Erklärung im Forum gefunden, die passt einwandfrei nur mein Problem ist, dass eben beim 255 der Überlauf auftritt... ich versuche diesen Überlauf (Overflow) zu vermeiden, aber irgendwie bekomme ich es anscheinend nicht hin.... Eigentlich versuche ich im Code, den TCNT0 zurückzusetzen und den Timer zu deaktivieren, sprich dann dürfte es nicht zum Überlauf immer auftreten... -----------Timer initialisieren und Zählregister auf 0 setzen------ Timer0: ldi temp1,0b00000101 ;Vorteiler 1024 einstellen out tccr0,temp1 ldi temp1,1<<TOV0 out TIFR, temp1 clr temp1 out TCNT0, temp1 ;TCNT0 mit 0x00 laden ldi temp1,(1<<toie0) out timsk,temp1 ; Timer0-Überlauf-Int aktivieren -------Unterprogramm-------------------------------------------------- TimerStoppen: ldi temp1,0b00000000 out tccr0,temp1 ;Timer0 wird gestoppt clr temp1 out TCNT0, temp1 ;Zaehler wird auf 0x00 gesetzt ldi temp1,1<<TOV0 out TIFR, temp1 ----------Interrupt-Auftritt-------------------------------------------- TimerV0: ;Auftritt bei Ablauf des Timer0 in STAT,SREG ; Statusregister sichern ldi temp1,1<<TOV0 ;Bitpsition des TOVO-Flags laden out TIFR,temp1 ;TOVO-Flag rücksetzen TimerStoppen2: ldi temp1,0b00000000 ;Timer0 stoppen out tccr0,temp1 ldi temp1,0x00 ;Zählregister TCNT0 mit 0x00 laden out TCNT0, temp1 out SREG,STAT ; Flags wiederherstellen reti ------------------------------------------------------------------------ -- dankeschön für jegliche Hinweise Erläuterung aus dem Forum (--Karl Heinz---) Jetzt zählt also das Timerregister so vor sich hin. Als solches ist das noch nicht sehr aufregend. Interessanter wird die ganze Sache, wenn man weis das dieser Timer bei bestimmten Zählerstanden Aktionen auslösen kann. So eine bestimmter Zählerstand kann zb. ein Overflow sein. Ein 8 Bit Timer kann ja nur bis 255 zählen. Danach findet ein Überlauf (Overflow) statt und der Timer beginnt wieder bei 0. Man kann sich jetzt an diesen Overflow klemmen und einen Programmteil ausfühen lassen, wenn der Overflow eintritt.
Hallo Manuete, das sind nur Auszüge des Programms, richtig? Damit ist leider wenig anzufangen - denn das Problem kann sonstwo liegen. Was auffällt: temp1 sowohl im Interrupt als auch in den anderen Programmteilen zu verwenden, ist nicht gut. Wenn der Überlauf des Timer0 nach 256 Zählschritten genutzt wird, braucht es keine Rücksetzung auf 0 in der Interruptroutine. Im Gegenteil, es wird die Zeit bis zum nächsten Interrupt >256 gesetzt. Wenn der Timer0 mit Vorteiler 1024 betrieben wird, muss man zum Laden von tcnt0 den Timer nicht stoppen. Die Interruptroutine wird bequem innerhalb der 1024 Takte des Vorteilers aufgerufen. Der Timer0 wird im Interrupt gestoppt aber nicht wieder gestartet - geschieht das anderswo im Programm? Alles in allem wird nicht wirklich klar, worum es nun wirklich geht...
Das ist richtig, nur die Auszüge die den Timer0 betreffen.. den ohne ihn läuft das Programm einwandfrei... wobei es ja auch mit dem Timer0 soweit geht... wenn ich zum Beispiel über Docklight statt 11Bytes nur 3Bytes sende und über den Stk500 kommuniziere.. dann bekomme ich eine Antwort dass der Timeout überfällig wurde.. Aber wenn ich jetzt immer die 11Bytes sende über Docklight... dann tritt trotzdem beim 256mal der Timeout auf... was ja net richtig ist, da es keinen Grund dafür gibt... Aber den TCNT0 will ich ja nur innerhalb der Empfangsroutine zählen lassen, da es dort nicht zu lange warten soll... als Kontrolle eben... Ja in der Interruptroutine wirds gestoppt... In der Empfangsroutine wird es immer gestartet, immer mit 1Byte-Empfang...
ausserhalb der Empfangsroutine (sprich auf die 11 Bytes nacheinander) wird der Timer immer gestoppt und der Zähler auf 0x00 gesetzt...
Das Problem muss nicht zwingend im Umfeld des Timer0 liegen. Der Code enthält zwar ein paar überflüssige Anweisungen und hoffentlich wird temp1 nicht noch anderweitig genutzt, aber ansonsten macht die Struktur Sinn. Ich würde mal den Rest des Programmes unter die Lupe nehmen, warum "TimerStoppen" beim 256ten Mal vielleicht nicht bedient wird.
HI;) Doch temp1 benutze ich fast überall als Zwischenspeicher, aber ich lade es immer nach jeder Benutzung davor und danach mit 0x00... das ist doch hoffentlich net so schlimm;) also vielleicht habe ich ja ein paar Verständnisprobleme;) 1.)Habe eine Empfangsroutine --->die erwartet 11 Bytes -->innerhalb dieser Routine werden diese Einstellungen vorgenommen Timer0: ldi temp1,0b00000101 ;Vorteiler 1024 einstellen out tccr0,temp1 ldi temp1,1<<TOV0 out TIFR, temp1 clr temp1 out TCNT0, temp1 ;TCNT0 mit 0x00 laden ldi temp1,(1<<toie0) out timsk,temp1 ; Timer0-Überlauf-Int aktivieren Dann überprüfe ich die Checksumme dieser 11 Bytes ---> die mir später erlaubt etwas (Relais) schalten zu dürfen Nach der Überprüfung lass ich auf meiner Platine Relais schalten Oder bei falscher Checksumme eben nicht. Jenach errechneter Checksumme sende ich entweder zu Docklight oder auch LabView eine Antwort, damit die nächsten 11Bytes (die sind fest) gesendet werden können. Wenn aber bei Schritt 1.) was schief läuft dann springt er eben ansonsten befinde ich mich immer im Empfangsbereitschaft... ----------Interrupt-Auftritt-------------------------------------------- TimerV0: ;Auftritt bei Ablauf des Timer0 in STAT,SREG ; Statusregister sichern ldi temp1,1<<TOV0 ;Bitpsition des TOVO-Flags laden out TIFR,temp1 ;TOVO-Flag rücksetzen TimerStoppen2: ldi temp1,0b00000000 ;Timer0 stoppen out tccr0,temp1 ldi temp1,0x00 ;Zählregister TCNT0 mit 0x00 laden out TCNT0, temp1 out SREG,STAT ; Flags wiederherstellen reti ------------------------------------------------------------------------ -- Die Frage ist jetzt, ich simuliere einen einwandfreien Betrieb und ich bekomme es nicht hin den Timer (TCCR0) und den TCNT0 zu stoppen... weil ich immer wieder in diese Interruptroutine reinfalle;) Das soll ja nur dann vorkommen wenn ich eben zu wenige Bytes empfange...
achso, also TimerStoppen2 ... jenachdem wo ich rausspringe, wenn ich die Empfangsroutine verlasse,nach dem ich meine Bytes empfangen habe.. dann sollte der Timer eben deaktiviert werden und der Zählstand wieder auf 0 gesetzt werden.... zur Sicherheit dachte ich ich dupliziere einfach dieses Label TimerStoppen Wobei es bisher keinen grossen oder bessergesagt überhaupt keinen Unterschied gemacht hat
also ich habe es gerade mit dem STK500 getestet... wenn ich es nicht stoppe dann hängt mein Programm immer in der Timer-Interruptroutine der der Timer dann ständig fällig ist
ist es egal ob ich zuerst TCCR0 deaktiviere und dann TCNT0 auf 0 lade oder muss ich bezüglich das was beachten????????
Schauen wir mal, wie viel Zeit bis zum Interrupt vergeht. Vorteiler = 1024 Zähler = 256 Nach 1024 * 256 = 262144 Takten wird der Interrupt ausgelöst. Welche Taktfrequenz benutzt die CPU? Bei 1 MHz löst der Timer0 nach ca. 262 Millisekunden einen Interrupt aus. Bei 12 MHz sind es nur noch 22 Millisekunden. Welche Baudrate wird benutzt?
Ich gehe normalerweise so vor: clr temp1 out TIMSK,temp1 ; Interrupt abstellen (hier pauschal alles!) out TCCR0,temp1 ; dann timer0 stoppen out TCNT0,temp1 ; dann zähler zurück setzen ldi temp1,(1<<TOV0) out TIFR,temp1 ; vorsorglich anhängiges Interrupt- ; Flag zurück setzen
hi, Taktfrequenz von 4MHZ Baudrate 9600 out TIMSK,temp1 ; Interrupt abstellen (hier pauschal alles!) hmmm den Interrupt muss ich doch nicht abstellen... "Bei 1 MHz löst der Timer0 nach ca. 262 Millisekunden einen Interrupt aus. Bei 12 MHz sind es nur noch 22 Millisekunde" Und er soll ja nicht ständig ein Interrupt auslösen, sondern nur innerhalb des Empfanges, falls sich dieser verzögert für 11 Bytes werden ca 11 Mikrosekunden benötigt... Ich kann bis zu 100ms gewähren, das wäre okay.. Was genau macht dieser Vorteiler, ich benutze ja den 1024.... dann gute nacht und bis morgen süsse Träume an alle
Nun ja, wir sind nun mal auf einer Ursachenforschung, oder nicht? :-) Dazu gehört natürlich - wenn sonst nichts direkt auffälliges ins Auge springt - auch eine Durchkalkulation der Timeout- zeiten. Manchmal hilft es schon zu wissen, wann ganz genau der Interrupt überhaupt ausgelöst wird. Bei 4 MHz Takt, einem Vorteiler von 1024 und einem Timer- Zähler von 256, ergibt sich eine Auslösezeit von ca. 65 Millisekunden (abgerundet). Bei 9600 Baud benötigt die Übertragung eines Bytes inkl. Start- und Stoppbit etwa 1 Millisekunde - nicht 11 Mikro- sekunden. Für 11 Bytes werden also mindestens 11 Milli- sekunden benötigt. Nun sind diese 11 Millisekunden aber sehr akademisch, wenn ein PC mit im Spiel ist. Es hängt sehr davon ab, wie die Daten zusammen gestellt und übermittelt werden. Wird jedes Byte einzeln aufbereitet, ist mit wesentlich längeren Zeiten als 1 Millisekunde zu rechnen. Bei Windows-Rechnern gilt m.W. eine Granulation von 10 Millisekunden, bei Linux- Systemen von 1 Millisekunde. Es ist nicht ungewöhnlich, dass speziell Windows-Rechner von Zeit zu Zeit einmal kurz "Luft holen"; sich mit zeit- aufwendigen Festplattenverwaltungen, Indizierkram, usw. beschäftigen. Der Vorteiler teilt den CPU-Takt von 4 MHz erst einmal durch 1024, bevor er ihn auf den Timer0-Zähler los lässt. Timer0 tickt also mit einer Frequenz um die 3,9 kHz. Und da der Timer seinerseits ein Teiler durch 256 ist, wird der Interrupt (wenn man ihn nicht sperren würde) mit ca. 15 Hz ausgelöst werden, was den bereits erwähnten 65 Millisekunden entspricht. Alles gerundete Zahlen. Vielleicht wäre eine Umstellung auf einen 16-bit-Timer mit kleinerem Vorteiler einen Versuch wert?
>out TIMSK,temp1 ; Interrupt abstellen (hier pauschal alles!) >hmmm den Interrupt muss ich doch nicht abstellen... Nein, in diesem speziellen Fall, wo der Interrupt innerhalb der Interrupt-Routine abgestellt wird nicht. Das Beispiel sollte nur verdeutlichen, wie man (ich) einen Timer ganz allgemein "aufräumt". Die Sperre des Interrupts hält einfach "den Rücken frei", die nachfolgenden Aufräumarbeiten am Timer wirklich ungestört abwickeln zu können. Ich beschäftige mich seit Jahrzehnten mit Assembler- Programmierung - da schleichen sich gewisse Strategien aus der Erfahrung ein, die einem Neuling nicht unmittelbar nachvollziehbar scheinen. :-) Dazu gehörte zum Beispiel, die Interrupt-Festigkeit des EEPROM-Zugriffes im AVR zu hinterfragen, noch bevor die Datenblätter diese Schwachstelle überhaupt aufgenommen hatten. Dazu gehört z.B. auch, die Latenzzeiten eines Interrupts im Zusammenspiel mit der sleep-Anweisung genau zu unter- suchen, wenn man eine Jitter-freie Anwendung benötigt. Und nicht einfach den Datenblättern zu vertrauen. Ein AT90S2313 und ein ATtiny2313 erwiesen sich da schon mal als recht ungleiche Brüder. Dies ist eine Meinungsbekundung und keine Tatsachenbehauptung - muss ich hier vorsorglich hinzufügen. ;-) Kurzum - den Interrupt muss man hier nicht zwingend abschalten, aber wenn man es trotzdem tut, fällt er einem auch nicht unerwartet wegen irgendwelcher übersehener Randbedingungen in den Rücken. Man kann die Anweisung nachträglich dann immer noch auskommentieren.
hello, vielen Dank für die netten Tipps und Erklärungen yep stimmt, 11,46ms für eine Telegrammlänge von 11Bytes (11Byte * 10Bit =110Bit/9600 = 11,46ms) Diese 11Bytes werden aufeinmal über LabView gesendet z.B.: 02FF FFFF FFFF FFFF FF003 Dies wird dann über das UART des AT90S8515 empfangen Beim 1Byteempfang initialisiere und starte den Timer und lade das Zählregister mit 0 um eben zu überprüfen, ob diese 100ms schon rum sind, dann sendet der microcontroller an LabView, dass dieser nochmals diese 11Bytes senden soll, da 1Byte oder jegliches an Bits verloren gegangen ist... Diese Telegrammlänge von 11,46ms zu gewährleisten,und noch mehr und zwar darf es 100ms dauern, so habe ich gedacht, dass ich es über den Timer0 und den Vorteiler von 1024 einstellen kann dass diese Zeit von 100ms gewährleistet Oder muss dies viell. über ein extra Register indem ich die 100ms lade oder einstelle und runterzähle?? Zum Timer1, der scheint mir noch komplizierter zu sein als der Timer0, wobei ich dann halt den Timeout auftritt dort erst denke ich beim 65
uuups die 100ms lassen sich mit dem Timer0 nicht einstellen sondern nur 65ms, das wäre denke ich auch okay das wäre ja fast die 6fache Zeit als die Telegrammlänge von 11,46ms für die 11Bytes
Ich würde nicht darauf vertrauen, dass der PC die 11 Bytes in einem Rutsch aussendet. Das wird schon seinen Grund haben, dass der Timer0 nach 65 Millisekunden zuschlägt. :-) Timer1 als 16-Bit-Zähler ist nicht wirklich komplizierter. Statt einmal temp1 nach TCNT0 zu laden, müssen nacheinander TNCT1L und TNCT1H geladen werden. Das ist der einzige wirkliche Unterschied. Lediglich auf die Reihenfolge muss man aufpassen - steht im Datenblatt, wie das geht. Zwischenvorschlag: Setze doch den Timer0 nicht nur nach dem ersten empfangenen Byte zurück, sondern nach jedem empfangenen Byte. So brauchst Du auf Timer0 nicht verzichten und gibst jedem Byte eine Frist von 65 ms. Auch kein Beinbruch. Am Ende der 11 Bytes dann nicht vergessen, den Interrupt zu sperren...
okay, dankeschön für den Tipp, dann probier ichs mal aus mal schauen was dabei rauskommt
ich glaube das mit dem rücksetzen funktioniert.. nach insgesamt 256 Kommunikationen, sprich 11Bytes übertragungen tritt erst mein Interrupt immer auf... das heisst nach jeder Kommunikation füllt sich anscheinend ein Register den ich nicht auf 0 setze...
muss ich vielleicht den Prescaler zurücksetzen noch in meinem Code... habe es hier im Forum gelesen, anscheinend bezüglich synchronisation "vom Prescaler nimmst, musst Du zusätzlich den Prescaler zurücksetzen, um den Timer wieder zu synchronisieren..."
Hallo Manuete, > muss ich vielleicht den Prescaler zurücksetzen noch in meinem Code... Ich wüsste nicht, dass man beim AT90S8515 den Prescaler gezielt zurück setzen kann. Diese Finesse braucht es, wenn man mehrere Prozesse im "Gleichtakt" betreiben möchte. In diesem Fall ist das nicht erfoderlich. Der nicht zurück gesetzte Vorteiler sorgt gerade mal für eine Unsicherheit von 256 Mikrosekunden (@ 4MHz und Vorteiler=1024), was bei dem Gesamtproblem vernachlässigbar ist. Die Unsicherheit, wann der PC das nächste Byte anliefert, liegt um Größenordnungen höher. Kann dort auch schon mal > 50 Millisekunden liegen, wenn Prozesse höherer Priorität abgearbeitet werden.
hi, also hab alles mögliche versucht, hab jetzt wirklich keine ahnung was ich noch versuchen soll... also zur Problemerinnerung... die Kommunikation erfolgt einwandfrei, nur bei der 256 Kommunikation, sprich wenn ich 256mal je 11Bytes sende tritt das Timeout(021103) Der Timer wird richtig gestoppt und der Zähler wieder mit 0 geladen, ansonsten würde Timeout früher auftreten... Die Zahl 256 ist bemerkenswert... warum tritt es nur nach 256mal, und das immer wieder?? Irgendwo lädt sich ein Register im AT90S8515, das mit dann den TimerInterrupt aufruft, was er eigentlich nicht machen soll;) Das ist mein Code, vielleicht ein wenig gewöhnungsbedürftig, aber für einen Anfänger ganz okay;) .include "8515def.inc" .def STAT = R16 .def Position= R17 .def Wert_Y = R18 .def ZwiSpa = R19 .def Pos_UART =R22 .def SchlZaY = R23 .def schlZaX = R24 .def temp1 = R25 .EQU nss = PB4 .EQU fqu = 4000000 ; Quarzfrequenz des AVR ;.equ fqu = 3686000 ;STK500 .EQU fbd = 9600 ; Baudrate des UART .EQU bddv = (fqu/(16*fbd))-1 ; Baudraten-Teiler .org $0000 rjmp Init ; Sprung zur Initialisierung reti ; Rücksprung aus Externer Interrupt0 reti ; Rücksprung aus Externer Interrupt1 reti ; Rücksprung aus Timer/Counter1 Capture Event reti ; Rücksprung aus Timer/Counter1 Compare Match A reti ; Rücksprung aus Timer/Counter1 Compare Match B reti ; Rücksprung aus Timer/Counter1 Overflow rjmp TimerV0 ; Sprung auf Routine für Timer/Counter0 Overflow reti ; Rücksprung aus Serial Transfer complete reti ; Rücksprung aus UART, Rx Complete reti ; Rücksprung aus UART, Tx Complete reti ;********************************************************* Reset: rjmp Init Init: ldi R20,High(RAMEND) out SPH,R20 ldi R20,LOW(RAMEND) out SPL,R20 ldi R29,$02 ;High Byte Adresse (Y) ldi R28,$20 ;Low Byte Adresse (Y) ldi temp1,0b00000011 ;PD0, PD1 gesetzt out PortD,temp1 ;PortD ldi temp1, 0b00000010 ;PD0 als Eingang und PD1 als Ausgang out DDRD, temp1 ldi temp1,$70 ;SCK=0,MISO=PullUP,MOSI=1,/SS=1 out PortB,temp1 ;Latch=1,Bit 2=Pull Up,Led1,Led=0 ldi temp1,$B0 ;SCK,MOSI,/SS=OUTPUT,REST=INPUT out DDRB,temp1 ;Datenrichtung PortB Konfigurieren ldi emp1,$50 ;SPIE=0,SPE=1;DORD=0,MSTR=1,CPHA=0 out Spcr,temp1 ;Cpha=0,Cpol=0,f(SCK)=f(Sys)/4 sbi PortB,PB3 ;595 enable ein sei ;Interrupts freigeben Tab_0_setzen: ldi R29,$02 ;High Byte Adresse (Y) ldi R28,$20 ;Low Byte Adresse (Y) Loop5: ldi temp1,0x00 ;temp mit 0x00 laden st Y+,temp1 ;Speichern auf Speicherplatz Y (0220) inc schlZaY ;inkrementiere schlZaY cpi schlZaY,11 ;vergleiche schlZaY mit 11 brne Loop5 ;springen, wenn SchlaZaY nicht gleich 11 ldi temp1,0x00 ;Zwischenspeicher temp1 mit 0x00 laden ldi schlZaY,0x00 ;Schleifenzaehler schlZaY mit 0x00 laden ldi Pos_UART,0x00 ;Position des UART Pos_UART mit 0x00 laden SPI: ldi R29,$02 ;High Byte Adresse (Y) ldi R28,$21 ;Low Byte Adresse (Y) ldi schlZaY,0x00 ;Schleifenzaehler schlZaY mit 0x00 laden LOOP3: ld ZwiSpa,Y+ ;Byte zur Übertragung aus Speicher Y cbi PortB,nss ;/ss=aktiv(log.0) out SPDR,ZwiSpa ;Datenbyte ausgeben spi1: sbis SPSR,SPIF ;Skip,wenn Übertragung beendet rjmp spi1 inc schlZaY ;inkrementiere schlZaY cpi schlZaY,8 ;vergleiche schlZaY mit 8 brne Loop3 ;springen, wenn SchlaZaY nicht gleich 8 sbi portB,nss ;/ss=inaktiv(log1) ldi schlZaY,0x00 ;Schleifenzaehler schlZaY mit 0x00 laden ;wenn über UART empfangen wurde und über SPI die Relais geschalten wurden ;dann sende Antwort an LabView cpi Pos_UART,1 breq LabView brne UART LabView: rcall CheckSumOK UART: ldi temp1,bddv ; Baudrate des UART einstellen out UBRR,temp1 sbi UCR,RXEN ;Receiver freigegeben sbi UCR,TXEN ;Trasmitter freigegeben Tab_1_setzen: ldi R29,$02 ;High Byte Adresse (Y) ldi R28,$20 ;Low Byte Adresse (Y) Loop55: ldi temp1,0x00 ;temp1 mit 0x00 laden st Y+,temp1 ;Speichern auf Speicherplatz Y(0220) inc schlZaY ;inkrementiere schlZaY cpi schlZaY,11 ;vergleiche schlZaY mit 11 brne Loop55 ;springen, wenn SchlaZaY nicht gleich 11 ldi temp1,0x00 ldi schlZaY,0x00 ldi schlZaX,0x00 EmpfangenS: ldi R29,$02 ;High Byte Adresse (Y) ldi R28,$20 ;Low Byte Adresse (Y) ldi SchlZaY,0x00 ldi temp1,0x00 ldi Position,0x00 cbi USR, RXC ;RXC-Flag loeschen falls gesetzt ldi temp1,0x00 out TIMSK,temp1 ldi temp1,0b00000000 out tccr0,temp1 ;Timer0 wird gestoppt ldi temp1,0x00 out TCNT0, temp1 ;Zaehler wird auf 0x00 gesetzt ldi temp1,1<<TOV0 ;Bitpsition des TOVO-Flags laden out TIFR,temp1 ;TOVO-Flag rücksetzen Empfangen: sbis USR,RXC ;warten bis ein Byte empfangen wurde, rjmp Empfangen ;Byte steht im UDR-Register bereit Weiter2: cpi Position,0x01 ;vergleiche ob Fehler aufgetreten ist breq EmpfangenS ;springe bei Gleichheit auf neues EmpfangenS FrameError: sbic USR,FE ;Framing Error Flag,überprüfen rjmp EmpfangenS in temp1,UDR ;(empfangenes Byte) nach temp1 kopieren st Y+,temp1 ;empfangenes Byte auf Speicherplatz Y (0220) inc SchlZaY ;inkrementiere schlZaY ;beim ersten Byte-Empfang wird Timer0 initialisiert und gestartet ;springe bei Gleichheit auf das Label Weiter das den Timer aufruft cpi SchlZaY,1 breq Weiter brne Weiter3 Weiter: rcall Timer0 Weiter3: ldi temp1,0x00 out TCNT0,temp1 cpi SchlZaY,11 brne Empfangen ldi Pos_UART,1 ;Position des UART mit 1 laden ldi schlZaY,0x00 ;Schleifenzaehler Y mit 00 laden ldi schlZaY,0x00 ;Schleifenzä Ymit 00 laden ldi temp1,0x00 out TCNT0,temp1 out TCCR0,temp1 out TIMSK,temp1 rjmp Checksumme ;auf Checksumme springen zur Byte Ueberprüfung Timer0: ldi temp1,(1<<toie0) out timsk,temp1 ;Timer/Counter-Interruptmaske aktivieren ldi temp1,0b00000101 ;Vorteiler 1024 einstellen out tccr0,temp1 ;Timer/Counter0 Control-Register einstellen ldi temp1,0x00 out TCNT0,temp1 ret Checksumme: ldi ZwiSpa,0x00 ldi temp1,0x00 ldi SchlZaX,0x00 ldi R29,$02 ldi R28,$29 ld ZwiSpa,-Y ;Lade Wert -X in Zwischenspeicher ZwiSpa Loop7: ld temp1,-Y eor ZwiSpa,temp1 ;Ergebnis wird in ZwiSpa zwischengespeichert inc SchlZaX cpi SchlZaX,7 ;insgesamt 7Verknüfungen brne Loop7 ldi R28,$29 ld temp1,Y ;empfangene CS laden cp ZwiSpa,temp1 ;Errechnete CS und empfangene CS vergleichen brne CheckSumFalse ;springe bei Ungleichheit auf Falsche CS rjmp SPI ;Relativer Sprung zur SPI CheckSumOK: ;3 Bytes zurücksenden, ldi SchlZaY,0x00 ldi temp1,0x00 sendSTX1: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendSTX1 ldi temp1,0x02 ;STX (Start of Text) out UDR,temp1 ;Daten in den Puffer schreiben und damit senden inc SchlZaY ;Schleifenzaehler SchlZaY um 1 inkrementieren sendOK: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendOK ldi temp1,0xFF ;lade 0xFF für in Ordnung der Checksumme out UDR,temp1 inc SchlZaY ;Schleifenzaehler SchlZaY um 1 inkrementieeren sendETX1: ;ETX (End of Text) sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendETX1 ldi temp1,0x03 ;ETX out UDR,temp1 inc SchlZaY ;inkrementiere SchlZaY um 1 cpi SchlZaY,3 ;vergleiche schlZaY mit 3 brne CheckSumOK ;springen, wenn SchlaZaY nicht gleich 3 rjmp EmpfangenS CheckSumFalse: ;3 Bytes zurück ldi SchlZaY,0x00 ldi temp1,0x00 sendSTX0: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendSTX0 ldi temp1,0x02 ;STX (Start of Text) out UDR,temp1 ;Daten in den Puffer schreiben und damit senden inc SchlZaY sendFalse: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendFalse ldi temp1,0x00 ;lade 0x00 für nicht in Ordnung der Checksumme out UDR, temp1 inc SchlZaY sendETX0: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendETX0 ldi temp1,0x03 ;ETX out UDR, temp1 inc SchlZaY ;inkrementiere schlZaY cpi SchlZaY,3 ;vergleiche schlZaY mit 3 brne CheckSumFalse ;springen, wenn SchlaZaY nicht gleich 3 rjmp EmpfangenS ;springe zum EmpfangenS TimerV0: ;Auftritt bei Ablauf des Timer0 in STAT,SREG ; Statusregister zwischenspeichern in STAT Register ldi temp1,0x00 out TIMSK,temp1 ldi temp1,0b00000000 out tccr0,temp1 ;Timer0 wird gestoppt ldi temp1,0x00 out TCNT0, temp1 ;Zaehler wird auf 0x00 gesetzt ldi temp1,1<<TOV0 ;Bitpsition des TOVO-Flags laden out TIFR,temp1 ;TOVO-Flag rücksetzen ByteFalse: ldi SchlZaY,0x00 ldi temp1,0x00 sendSTX02: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendSTX02 ldi temp1,0x02 ;STX (Start of Text) out UDR, temp1 ;Daten in den Puffer schreiben und damit senden inc SchlZaY sendFalse11: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendFalse11 ldi temp1,0x11 ;lade 0x11 für den Timeout/ Empfangsfehler out UDR, temp1 inc SchlZaY sendETX03: sbis USR,UDRE ;Warten bis UDR für das nächste Byte bereit ist rjmp sendETX03 ldi temp1,0x03 ;ETX (End of Text) out UDR, temp1 inc SchlZaY ;inkrementiere schlZaY cpi SchlZaY,3 ;vergleiche schlZaY mit3 brne ByteFalse ;springen, wenn SchlaZaY nicht gleich 3 ldi Position,0x01 out SREG,STAT ;Statusregister wiederherstellen reti ;Rücksprung in das Hauptprogramm
Testkommunikation: 19.09.2007 10:22:20,863; 021F315E2843C2FB3B1903 11Bytes werden gesendet 19.09.2007 10:22:21,375: 02FF03 3Bytes als Antwort 19.09.2007 10:22:21,394; 02CC22E2712D9FD70A1203 19.09.2007 10:22:21,905: 021103--------------------> 19.09.2007 10:22:21,915; 02A91E043CAC173A383603 19.09.2007 10:22:22,425: 02FF03 ....... ....... ....... 19.09.2007 10:24:36,151: 02FF03 19.09.2007 10:24:36,160; 0274020BF0BBE639A34A03 19.09.2007 10:24:36,671: 021103--------------------> 19.09.2007 10:24:36,680; 0242ADC4456EAA656FA003 19.09.2007 10:24:37,191: 02FF03
Hallo Manuete, ändere LabView: rcall CheckSumOK in LabView: rjmp CheckSumOK und probier das Programm noch mal aus. Wenn es läuft erkläre ich Dir, warum. Vor "Loop5" würde ich gerne ldi SchlZaY,0x00 sehen. Viel Glück!
woooooooooooooooow, ich glaube es scheint zu funktionieren, lasse es gerade laufen... meinen Test... und bis jetzt sind keine Timeouts aufgetreten,ich glaub das einfach nicht....der hammer.. und das lag nur an diesem rcall und rjmp, mit rcall, ruft man doch ein Unterprogramm auf und mit rjmp springt man auf eine Stelle im Programm viiiiiiiiiiiiiiiiiiiiiiiiiiiiiielen Dank, du bist ein Engel;)
Manuete wrote: > mit rcall, ruft man doch ein Unterprogramm auf Richtig, aber man braucht dann auch am Ende des Unterprogramms ein "ret", das die gespeicherte Rücksprungadresse wieder vom Stack holt, sonst läuft der Stack über. Da der 90S8515 512 Bytes SRAM hat (und dementsprechend auch eine maximale Stacktiefe von 512 Bytes) und eine Rücksprungadresse zwei Bytes benötigt, gibts alle 256 Unterprogrammaufrufe einen Stack-Überlauf... > und mit rjmp springt man auf eine Stelle im Programm Genau. Und dabei gibts im Gegensatz zum (r)call keinen Rücksprung an die aufrufende Stelle...
ooooooooohhh ja,stimmt ret: Rücksprung aus einem Unterprogramm ja beim Interrupt habe ich darauf geachtet und reti verwendet;) ich weiss gar net warum ich rcall überhaupt verwendet habe... okay,sehe aber was die Auswirkungen sind... und was ist geschickter oder besser, rjmp oder rcall... oder sind sie gleich??
Hallo Manuete, Du hättest uns viel Zeit ersparen können, wenn das Listing von Anfang an "auf dem Tisch" gelegen hätte. ;-) Die Vermutung, dass es gar nicht am Timer0-Überlauf liegt, sondern anderweitig im Programm, stand sehr früh auf der Agenda. Dein Programm enthält manche überflüssige Anweisung und ließe sich auch sonst überschaubarer gestalten. Das ist aber eine Sache der Routine und des Geschmacks. Entscheidend ist, dass es läuft. Daran herumfeilen kann man dann immer noch. Zu überdenken wäre z.B., dass eine Zeitüberschreitung an einer Stelle (oder gar mehreren - habe das in nicht in die Tiefe untersucht) erst nach dem Eintreffen von Daten über UART erkannt wird. Es braucht also einen Anstoß von außen, damit das Programm eine Zeitüber- schreitung signalisiert. Vielleicht ist das auch so beabsichtigt.
ich könnte doch das hier dann löschen beim TimerInterrupt, oder ist das schon so ok?? TimerV0: ;Auftritt bei Ablauf des Timer0 ldi temp1,0x00 out TIMSK,temp1 ldi temp1,0b00000000 out tccr0,temp1 ;Timer0 wird gestoppt ldi temp1,0x00 out TCNT0, temp1 ;Zaehler wird auf 0x00 gesetzt ldi temp1,1<<TOV0 ;Bitpsition des TOVO-Flags laden out TIFR,temp1 ;TOVO-Flag rücksetzen
ooohhh man, ich war der festen Überzeugung das ich anderweitig keine Fehler habe, bis ich alle Varianten des TimerÜberlaufs 100mal ausprobiert habe und ich meine Nerven ausgekostet habe;) Aber vielen Dank für deine/eure Geduld und eure Hilfe... Den Teil deiner Aussage habe ich leider nicht verstanden, was meinst du mit eine Zeitüberschreitung?? "Zu überdenken wäre z.B., dass eine Zeitüberschreitung an einer Stelle (oder gar mehreren - habe das in nicht in die Tiefe untersucht) erst nach dem Eintreffen von Daten über UART erkannt wird. Es braucht also einen Anstoß von außen, damit das Programm eine Zeitüber- schreitung signalisiert. Vielleicht ist das auch so beabsichtigt" der Mikrocontroller reagiert auf z.B.: 02FF FFFF FFFF FFFF FF00 03 02FF03-------> für richtige Checksumme und schaltet Steuerung frei 02FF FFFF FFFF FFFF FFFF 03 020003-------> für falsche Checksumme und wartet auf neues Telegramm 020000 021103-------> für Timeout, zu wenige Bytes, und wartet auf neue Telegramm nur hier 0200 0000 0000 0000 0003 0000 02FF03021103 --->hier antwortet er mit richtig und Timeout
es geht eigentlich nur um die Übertragungszeit von LabView zum UART des Mikrocontrollers... das soll nur gewährleistet sein, und Fehler eben abzufangen... also ein sicheres Übertragungsprotokoll... und ich denke das ist okay so;)
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.