Hallo zusammen, ich habe mich zum ersten Mal an den Timer0 gewagt und schon funktioniert es nicht mehr. Ich habe ein einfach Testprogramm geschrieben, welches auf dem STK500 abläuft. Tasten 0-3 werden auf den entsprechenden LEDs ausgegeben. Im Hintergrund läuft der Timer0 mit Overflow-Interrupt. Bei Interrupt werden die Tasten 4-7 abgefragt und auf den LEDs ausgegeben. Ausserdem sollen Zeichen über die RS232 Schnittstelle gesendet werden. Aber er bleibt irgendwo hängen. Wenn ich die folgenden 2 Zeilen ausdokumentiere, sendet er zwar etwas, aber es funktioniert nicht richtig: sbis UCSRA,UDRE ;HIER LIEGT DAS PROBLEM rjmp USART_Transmit Ich habe das komplette Programm unten eingefügt. Die Routine zum Senden funktioniert alleine wunderbar. Ich habe sie schon mehrfach verwendet. Aber irgendetwas scheint den Befehl oben zu beeinflussen - aber ich habe keine Ahnung was. Ich hoffe, jemand kann mir den Fehler sagen, den ich da eingebaut habe. :-) Im Voraus vielen Dank. Gruß Markus .INCLUDE "m16def.inc" .DEF akku = r16; .DEF temp = r17; .DEF seku = r18; .DEF send = r19; .CSEG rjmp start .ORG $012 rjmp timer0 .ORG $030 start: ldi akku,LOW(RAMEND); out SPL,akku; ldi temp, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse out SPH, temp ldi akku,$ff ;PortB als Ausgang out DDRB,akku ldi akku, 0b010 ;Timer0 Einstellungen out TCCR0, akku in akku, TIMSK ori akku, 0b00000001 out TIMSK, akku rcall USART_Init ;Initialisierung USART sei abfrage: in akku, PINA ;SW0 - SW3 auf LED0 - LED3 ausgeben andi akku, 0b00001111 ori akku, 0b11110000 out PORTB, akku rjmp abfrage timer0: cli ;Interrupts ausschalten taste: in akku, PINA ;SW4 - SW7 auf LED4 - LED7 ausgeben andi akku, 0b11110000 ori akku, 0b00001111 out PORTB, akku rcall zeichen ;Zeichen senden cpi akku, 0b11111111 brne taste ;schleife, wenn taste weiterhin gedrückt sei ;Interrupts einschalten reti USART_Init: ;set baud rate ldi r17,0 ldi r16, 23 out UBRRH, r17 out UBRRL, r16 ;Enable receiver and transmitter ldi r16, (0<<RXCIE) | (0<<RXEN) | (1<<TXEN) out UCSRB,r16 ;set frame format: 8data, 1stop bit ldi r16, (1<<URSEL) | (0<<USBS) | (3<<UCSZ0) out UCSRC,r16 ret USART_Receive: sbis UCSRA, RXC rjmp USART_Receive in send, UDR out PORTB, temp ret USART_Transmit: sbis UCSRA,UDRE ;HIER LIEGT DAS PROBLEM, bei ausdokumentieren funktioniert es, aber nicht richtig rjmp USART_Transmit out UDR,temp ret zeichen: ldi temp, 0x81 rcall USART_Transmit ldi temp, 0x82 rcall USART_Transmit ret
Ein AVR hat nur einen Registersatz, daher dürfen durch Interrupts keine Register verändert werden, wenn das nicht ausdrückliche Absicht ist. Hier werden beispielsweise "akku" und "temp" durch einen Interrupt vernichtet. Und in SEI/RETI ist SEI zwar nicht schädlich aber überflüssig, das macht der RETI gleich mit.
Ersteinmal vielen Dank für die superschnelle Antwort. .-) In meinem Fall ist es doch egal, ob "akku" und "temp" vernichtet werden. Oder? Ich lade doch temp und rufe danach gleich "USART_Transmit" auf. Davor und danach ist es mir doch egal, was in den beiden Registern steht. Oder habe ich da einen Denkfehler?
-cli und sei brauchst du in der ISR nicht -zumindest das SREG muss in der ISR gesichert werden
Was passiert, wenn zwischen in akku, PINA ;SW0 - SW3 auf LED0 - LED3 ausgeben und andi akku, 0b00001111 "akku" per Interrupt einen anderen Wert kriegt? Bei deinem Code zwar garnichts, weil im Interrupt exakt das gleiche steht wie im Hauptprogramm (was übrigens auch nicht allzu viel Sinn ergibt), aber es ist saumässig schlechter Stil und man stolpert später garantiert drüber. Genauso sollte man in Interrupts generell keine längeren Pausen einlegen. Also sollte man in einem Timer-Interrupt nichts auf UART ausgeben, weil da eine Warteschleife drin steckt.
Wenn ich mir dein Programm anschaue würde ich sagen du hast 3,6 MHz und sendest mit 9600 Baud. d.h. ein Zeichen zu senden dauert 1ms. Aus einer Timerroutine Aktionen auszulösen die 1ms und länger dauern würde ich als Denkfehler bezeichnen. Setze im Timerinterrupt ein Flag und polle dieses im Hauptprogramm. Timerinterrupt {setze Flag} Hauptprogramm: 1. wenn Flag gesetzt senden/empfangen/Tasten abfragen 2. zu 1.
@A.K. ich weiß, dass das Programm nicht besonders sinnvoll ist. Soll ja auch nur ein Testprogramm sein. Ich möchte das weiterentwickeln, damit es mir mal eine 5x4-Matrixtastatur auswertet. Der Kniff (in meinen Augen ist dabei), dass wenn die Taste gedrückt wird ein Befehl gesendet werden soll und wenn die Taste losgelassen wird soll wieder ein anderer Befehl gesendet werden (GO-STOP). Deswegen habe ich versucht, das ganze über einen Timer zu lösen. @Wolfram + A.K. danke für die (Lösungs-)Hinweise. Da ich bisher noch nichts mit Flags gemacht habe, werde ich mich mal damit auseinandersetzen. @Wolfram deine Vermutungen stimmen: 3,6 Mhz und 9600 Baud
Nur zur Klarstellung: Deine Programmstruktur geht prinzipiell du schaltest in der Timerroutine ja die Interrupts aus, sobald du mit dieser Struktur aber größere Programme schreiben willst wirst du grosse Probleme bekommen, also gewöhn dir das erst gar nicht an. >;Enable receiver and transmitter >ldi r16, (0<<RXCIE) | (0<<RXEN) | (1<<TXEN) damit schaltest du NUR den Tranceiver ein >ldi r16, (0<<RXEN) | (1<<TXEN) schaltet Receiver und Transceiver ein BTW: Überprüf mal in den FUSES das wirklich der externe Takt benutzt wird
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.