Hallo,
Ich versuche Zeichen an das Hyperterminal zu senden. Dazu soll der
Interrupt für "Zeichen gesendet" ausgenutzt werden. Leider wird der
Interrupt nicht ausgelöst.
Mein Programm sieht wie folgt aus:
Ich suche den Feler jetzt schon seit 3 Tagen und ich komme einfach nicht
drauf :-(
.INCLUDE <m8def.inc>
.def temp = R16 ; für Interrupt
.def ZEICHEN = R17
;------------------------------------------------------
; Peripherie initialisieren
;------------------------------------------------------
.equ F_CPU = 7273800 ; Systemtakt in Hz
.equ BAUD = 9600 ; Baudrate
; Berechnungen
.equ UBRR_VAL = ((F_CPU+BAUD*8)/(BAUD*16)-1) ; clever runden
.equ BAUD_REAL = (F_CPU/(16*(UBRR_VAL+1))) ; Reale Baudrate
;------------------------------------------------------
; Start Adresse 0000 /Interruptvektoren
;------------------------------------------------------
.org 0x000
rjmp Init ; Interruptvektoren überspringen
.org UTXCaddr ; UART Transmit Complete Interrupt
rjmp serout
;------------------------------------------------------
; INITIALIZE
;------------------------------------------------------
INIT:
;Stack Pointer setzen
ldi temp,high(RAMEND)
out SPH,temp
ldi temp,low(RAMEND)
out SPL,temp
; Baudrate einstellen
ldi temp, HIGH(UBRR_VAL)
out UBRRH, temp
ldi temp, LOW(UBRR_VAL)
out UBRRL, temp
; Frame-Format: 1 Stop-Bits, 8 Bit
ldi temp, (1<<URSEL)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0)
out UCSRC, temp
sbi UCSRB,TXEN ; Sender aktivieren
sbi UCSRB,TXCIE ; Interrupt für "senden fertig" aktivieren
sei ; globale Interruptfreigabe
sbi UCSRA,TXC ; Initialisierung des Interrupts
;------------------------------------------------------
; HAUPTSCHLEIFE
;------------------------------------------------------
Hauptschleife:
rjmp Hauptschleife
;------------------------------------------------------
; Subroutinen / ISRs
;------------------------------------------------------
serout:
lpm ; Erstes Byte des Strings nach R0 lesen
mov ZEICHEN,R0
adiw ZL, 1 ; Adresse des Z-Pointers um 1 erhöhen
tst R0 ; Inhalt von R0 auf Bull testen
brbc 1,sprung_b
ldi ZL, LOW(Daten*2) ; Adresse des ersten Strings in den
ldi ZH, HIGH(Daten*2) ; Z-Pointer laden
sprung_b:
out UDR, ZEICHEN ; Zeichen auf UART ausgeben
reti
;------------------------------------------------------
; Datenbereich
;------------------------------------------------------
Daten:
.db 0x12, 0x12
.db 0x20, 0x20
.db 0x63, 0x63
.db 0x58, 0x00
@ pacer (Gast) >Ich versuche Zeichen an das Hyperterminal zu senden. Dazu soll der >Interrupt für "Zeichen gesendet" ausgenutzt werden. Leider wird der >Interrupt nicht ausgelöst. >Mein Programm sieht wie folgt aus: >Ich suche den Feler jetzt schon seit 3 Tagen und ich komme einfach nicht >drauf :-( Ich glaube du hast einige wesentliche Dinge noch nicht verstanden. AVR-Tutorial: UART Interrupt > sei ; globale Interruptfreigabe Bis hier hin alles OK. > sbi UCSRA,TXC ; Initialisierung des Interrupts Was soll das? Dieser Befehl löscht ein anstehendes Interrupt-Bit. > ;------------------------------------------------------ > ; HAUPTSCHLEIFE > ;------------------------------------------------------ >Hauptschleife: >rjmp Hauptschleife Kannst du mir sagen, wo hier Zeichen gesendet werden? >serout: Du verwechselst die Funktionalität von UDRE und TXC Interrupt! MFG Falk
Danke für deine Hilfe Das Tutorial habe ich mir schon angeschaut, leider wird in den Beispielen der Interrupt nicht verwendet. Stimmt, das setzten des Bits löscht das Interruptflag. Hab ich mich wohl verlesen. Die Daten werden in der Interruptroutine ausgegeben, deswegen ist das Hauptprogramm leer. Nur muss ich zumindest einmal den Interrupt auslösen. Vielleicht könnte ich ja ein Leerzeichen senden wenn es losgehen soll, oder irgendetwas anderes?!
@ pacer (Gast) >Nur muss ich zumindest einmal den Interrupt auslösen. Vielleicht könnte >ich ja ein Leerzeichen senden wenn es losgehen soll, Das geht. MFG Falk
.equ F_CPU = 7273800 ; Systemtakt in Hz Da ist aber ein Zahlendreher drin....
Stimmt, so ganz klar ist mir der Unterschied zwischen UDRE und TXC nicht klar. Ich bin einfach davon ausgegangen, dass UDRE bedeutet, dass das Zeichen übermittelt wurde, unabhängig vom Status des Schieberegisters TXE bedeutet, dass das Zeichen übermittelt wurde und das Schieberegister kein neues Zeichen enthält.
Ups, stimmt, die Frequenz ist tatsächlisch falsch, hat aber bis jetzt trotzdem funktioniert ;-) ich werde das aber trotzdem verbessern, danke für den Tip
habe mein Programm wie folgt geändert:
Die Null für die Initialisierung kommt an, nur ein Interrupt wird immer
noch nicht ausgelöst.
Ich hab keinen Plan was ich noch tun soll...
-------------------------------------------------------------------
.include "C:\PROGRA~1\VMLAB\include\m8def.inc
.def temp = R16 ; für Interrupt
.def ZEICHEN = R17
;------------------------------------------------------
; Peripherie initialisieren
;------------------------------------------------------
.equ F_CPU = 7372800 ; Systemtakt in Hz
.equ BAUD = 9600 ; Baudrate
; Berechnungen
.equ UBRR_VAL = ((F_CPU+BAUD*8)/(BAUD*16)-1) ; clever runden
.equ BAUD_REAL = (F_CPU/(16*(UBRR_VAL+1))) ; Reale Baudrate
;------------------------------------------------------
; Start Adresse 0000 /Interruptvektoren
;------------------------------------------------------
.org 0x000
rjmp Init ; Interruptvektoren überspringen
.org UTXCaddr ; UART Transmit Complete Interrupt
rjmp serout
;------------------------------------------------------
; INITIALIZE
;------------------------------------------------------
INIT:
;Stack Pointer setzen
ldi temp,high(RAMEND)
out SPH,temp
ldi temp,low(RAMEND)
out SPL,temp
; Baudrate einstellen
ldi temp, HIGH(UBRR_VAL)
out UBRRH, temp
ldi temp, LOW(UBRR_VAL)
out UBRRL, temp
; Frame-Format: 1 Stop-Bits, 8 Bit
ldi temp, (1<<URSEL)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0)
out UCSRC, temp
sbi UCSRB,TXEN ; Sender aktivieren
sbi UCSRB,TXCIE ; Interrupt für "senden fertig" aktivieren
sei ; globale Interruptfreigabe
ldi ZEICHEN, '0'
out UDR, ZEICHEN ;Initialisierung
;------------------------------------------------------
; HAUPTSCHLEIFE
;------------------------------------------------------
Hauptschleife:
rjmp Hauptschleife
;------------------------------------------------------
; Subroutinen / ISRs
;------------------------------------------------------
serout:
lpm
mov ZEICHEN,R0
adiw ZL, 1
tst R0
brbc 1,sprung_b
ldi ZL, LOW(Daten*2)
ldi ZH, HIGH(Daten*2)
sprung_b:
out UDR, ZEICHEN
reti
;------------------------------------------------------
; Datenbereich
;------------------------------------------------------
Daten:
.db 0x12, 0x12
.db 0x20, 0x20
.db 0x63, 0x63
.db 0x58, 0x00
@ pacer (Gast) >habe mein Programm wie folgt geändert: >Die Null für die Initialisierung kommt an, nur ein Interrupt wird immer >noch nicht ausgelöst. >Ich hab keinen Plan was ich noch tun soll... U.a. SIMULIEREN! > ldi ZEICHEN, '0' > out UDR, ZEICHEN ;Initialisierung Hier fehlt eine Initialisierung des Z-Pointers. Der kann sonstwohin zeigen. > brbc 1,sprung_b Diesen Befehl nutz man praktisch NIE! Versuch mal lieber brne sprung_b Sollte zwar das gleiche sein, aber naja. MfG Falk
okay, funktioniert doch. Eigentlich ist das Programm aus verschiedenen Tutorials zusammengestrickt. Der Teil mit dem Befehl bcrc ist zB aus dem AVR-Tutorial. Den Z-Pointer brauche ich ja nur für den Datenbereich, bei einer Zuweisung muss ich ja nix tun. Müsste also korrekt sein. Simulieren tue ich mit VMLAB. Wollte aber noch mall fragen ob ich das jetzt mit UDRE und TXC richtig verstanden habe?! Gruß, pacer
@ pacer (Gast) >okay, funktioniert doch. E Und woran lags? >Wollte aber noch mall fragen ob ich das jetzt mit UDRE und TXC richtig >verstanden habe?! >>Ich bin einfach davon ausgegangen, dass UDRE bedeutet, dass das Zeichen >>übermittelt wurde, unabhängig vom Status des Schieberegisters Diese Formulierung ist nicht sehr glücklich. Übersetz doch einfach den Namen ins Deutsche UDRE, UART Data Register Empty. Das Datenregister des UARTs ist leer. D.h. es kann neue Daten aufnehmen. Und dabei geht es um das Zwischenregister, mit dem die Senderichtigung gepufferet wird, praktisch ein kleiner FIFO. >TXE bedeutet, dass das Zeichen übermittelt wurde und das Schieberegister >kein neues Zeichen enthält. Ja, diesen Interrupt nutzt man aber nur selten, z.B. bei Halbduplexkommunikation mit RS485, um den Tranceiver (Z.B. MAX485) von Senden auf Empfangen umzuschalten. MFG Falk
Hallo, ich schreibe zur Zeit ein Programm in Assembler für den ATMega162. Zur Simulation benutze ich das Programm VMLab. Bei der Simulation mit der seriellen Schnittstelle habe ich Probleme. Für den Interrupt nutze ich das Bit UDRIE1 im Register UCSR1B. Die Daten liegen im Ausgabepuffer im Datenbereich und werden in der Interruptroutine über einen Zeiger gelesen und in das Register UDR1 geschrieben. Sobald die Daten in den Ausgabepuffer geschrieben wurden wird das Bit UDRIE1 gesetzt. Es wird sofort ein Interrupt ausgelöst und die Daten über die serielle Schnittstelle versendet. Am Ende der Interruptroutine wird das Bit UDRIE1 gelöscht. Nachdem ein neuer Datenblock geschrieben wurde und das Bit UDRIE1 gesetzt wurde, wird kein Interrupt ausgelöst. Kann hier der Fehler bei VMLab liegen, da alle Flags richtig angezeigt werden? Gruß Manfred
@ Manfred (Gast) >Für den Interrupt nutze ich das Bit UDRIE1 im Register UCSR1B. >Die Daten liegen im Ausgabepuffer im Datenbereich und werden in der Was heisst "im Ausgangspuffer" ? Du meinst ein allgemeines Array. >Interruptroutine über einen Zeiger gelesen und in das Register UDR1 >geschrieben. >Sobald die Daten in den Ausgabepuffer geschrieben wurden wird das Bit >UDRIE1 gesetzt. >Es wird sofort ein Interrupt ausgelöst und die Daten >über die serielle Schnittstelle versendet. Am Ende der Interruptroutine >wird das Bit UDRIE1 gelöscht. Wozu das? UDIE bleibt im Normalfall solange gesetzt, bis das letzte Zeichen in UDR1 geschrieben wurde. >Nachdem ein neuer Datenblock geschrieben wurde und das Bit UDRIE1 >gesetzt wurde, wird kein Interrupt ausgelöst. >Kann hier der Fehler bei VMLab liegen, da alle Flags richtig angezeigt >werden? Ja, kann ein Fehler sein. MfG Falk
@Falk Die Daten, die über die serielle Schnittstelle gesendet werden sollen befinden sich als Block im internen RAM. Das letzte Zeichen ist null. In der Interruprroutine wird bei jedem Aufruf ein Zeichen gelesen und in das Register UDR1 geschrieben. Falls null gelsen wird, wird dieses Zeichen nicht in das Register UDR1 geschrieben, aber das Bit UDRIE1 gelöscht. Dieses Bit wird erst wieder gesetzt, nachdem ein neuer Block in das interne RAM geschrieben wurde. Da die erste Übertragung funktioniert und dann nicht mehr, vermute ich einen Fehler bei VMLab. Gruß Manfred
@ Manfred (Gast) Genau so meinte ich das. >Da die erste Übertragung funktioniert und dann nicht mehr, vermute ich >einen Fehler bei VMLab. Ja. Simulation ist nur die halbe Wahrheit. Probiers aus. MfG Falk
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.