Hi. µC: mega164p Ich möchte TX aktivieren: sbi UCSR0B,TXEN0 Fehler: error: Operand 1 out of range: 0xc1 In m164Pdef.inc steht: ... .equ UCSR0B = 0xc1 ; MEMORY MAPPED ... Ich vermute, ich kann mit sbi nicht UCSR0B bearbeiten. Wieso ist das so? Wie kann ich denn nun das TXEN Bit in UCSR0B setzen? Vielen Dank für deine Hilfe. Chris
Hi Chris, nur die unteren Adressen sind direkt erreichbar (mit z.B. sbi), bei den höheren ("memory mapped") bleibt Dir nur der Umweg; z.B. lds register, UCSR0B sbr register, TXEN0 sts UCSR0B, register Gruß Fred
sbi Set Bit in I/O Register kann nicht funktionieren, da UCSR0B memory mapped ist. Welchen Befehl sollte ich denn dann verwenden? Das lustige ist halt, dass ich den Beispiel Code aus der AVR Referenz Seite 177 von 436 genommen habe. Dort wird der Befehl out verwendet. out Out Port funktioniert aber auch nicht. Sollte ich also die Adresse UCSR0B einfach direkt laden?
Hi, nimm den Code, den ich oben hingeschrieben habe, dann wird's gehen! Gruß Fred
@fredhs Ja, hast recht. Es funktioniert nun. DANKE! Mich wundert es aber wirklich, wieso die dann so ein Beispiel auf Seite 177 von http://www.atmel.com/dyn/resources/prod_documents/doc8011.pdf bringen. Das ist doch falsch!?
Hi Chris, schau mal auf das Kleingedruckte unter dem Code-Beispiel. Dort wirst Du auf S. 8 verwiesen, wo steht: "... For I/O registers located in extended I/O map, "IN", "OUT", "SBIS", "SBIC", "CBI", and "SBI" instructions must be replaced with instructions that allow access to extended I/O. Typically "LDS" and "STS" combined with "SBRS", "SBRC", "SBR", and "CBR"." Gruß Fred
Hinten im Datenblatt gibt's das "Register summary", da sind zwei dicke schwarze Linien in der Tabelle: da, wo man mit sbi, sbis, etc. zugreifen kann, und da, wo man mit in/out zugreifen kann... Oberhalb der zweiten Linie ( bei "SREG"), gehen nur noch STS/LDS (ST, STD,...) Zugriffe. hth. Jörg PS.: die meisten PDF-Reader haben eine Such-Funktion, falls es zu mühsam ist, die Tabelle von Hand durchzugehen ;)
Vielen Dank euch! Jetzt ist mir so Einiges klarer geworden. :-) Das Programm funktioniert zwar trotzdem noch nicht, aber ich bin schon mal einen Schritt weiter. ;-) Es werden einfach keine Daten "Test!" am PC im Programm Hyperterminal angezeigt. Es kommt aber ein "echo". Also die Buchstaben die ich eintippe, erscheinen auch im Hyperterminal. Ich vermute, es stimmen die Einstellungen für USART noch nicht. Hast du eine gute Idee, wie man USART Übertragungen debuggen kann? Hier das Prg.: .include "m164Pdef.inc" .def temp = r16 ; Register für kleinere Arbeiten .def zeichen = r17 ; in diesem Register wird das Zeichen an die ; Ausgabefunktion übergeben .equ F_CPU = 16000000; Systemtakt in Hz .equ BAUD = 9600; Baudrate ; Berechnungen .equ UBRR_VAL2 = 103; Siehe Referenz Seite 197 von 436 .equ UBRR_VAL = ((F_CPU+BAUD*8)/(BAUD*16)-1); clever runden .equ BAUD_REAL = (F_CPU/(16*(UBRR_VAL+1))); Reale Baudrate .equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000); Fehler in Promille .if ((BAUD_ERROR>10) || (BAUD_ERROR<-10)); max. +/-10 Promille Fehler .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!" .endif ; Stackpointer initialisieren ldi temp, LOW(RAMEND) out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ; UCSR0C Frame-Format ist standardmäßig auf async USART, ; keine Parität, 1 Stoppbit, 8 Datenbits initialisiert. ;lds temp,UCSR0C ;cbr temp,UPM00 ;cbr temp,UPM01 ;sts UCSR0C,temp// Set frame format: keine Parität ; Bautrate wie oben definiert setzen ldi temp,UBRR_VAL2 sts UBRR0H,temp ldi temp,LOW(UBRR_VAL2) sts UBRR0L,temp ; TX und RX aktivieren lds temp,UCSR0B sbr temp,TXEN0 ;sbr temp,RXEN0 sts UCSR0B,temp loop: ldi zeichen, 'T' rcall serout ; Unterprogramm aufrufen ldi zeichen, 'e' rcall serout ; Unterprogramm aufrufen ldi zeichen, 's' rcall serout ; ... ldi zeichen, 't' rcall serout ldi zeichen, '!' rcall serout ldi zeichen, 10 rcall serout ldi zeichen, 13 rcall serout rjmp loop serout: lds temp,UCSR0A sbrs temp,UDRE0; Warten bis UDR für das nächste Byte bereit ist rjmp serout sts UDR0, zeichen ret ; zurück zum Hauptprogramm
Hallo Chris, den Atmega164 habe ich nicht im Kopf und die Details Deiner Initialisierung nicht mit dem Datenblatt verglichen. Oft sind es Kleinigkeiten -- eine ist mir aufgefallen: ldi temp, high(UBRR_VAL2) ; !!!!!!!!!!!! sts UBRR0H,temp Es können durchaus auch noch andere Details inkorrekt sein. Dickes Lob an Dich für die Parametrisierung! Gruß Fred
Ohh, hast recht. Die beiden Zeilen hab ich gleich mal gelöscht. Da ich ja nur den Wert 103 schreiben möchte, bleibt UBRR0H = 0. Läuft trotzdem noch nicht. Ich probier mal weiter ... ;-)
Hallo Chris, wenn die Initialisierung stimmen sollte und es trotzdem nicht läuft (und auch schon vorher): verifizier mal, dass über die Fuse-Bits tatsächlich der externe Quarz als Oszillator ausgewählt ist (und nicht der interne, vielleicht zudem noch mit CKDIV8). Gruß Fred
Mit folgendem C Code funktionierts ja. Dieser Code gibt für viele Eingabe den darauffolgenden Buchstaben im Alphabet aus. D.h. die Fuses usw. müssten alle passen. #include <avr/io.h> #define USART_BAUDRATE 9600 #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) int main (void) { char ReceivedByte; UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register for (;;) // Loop forever { while ((UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been recieved and is ready to be read from UDR ReceivedByte = UDR0; // Fetch the recieved byte value into the variable "ByteReceived" while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it UDR0 = ReceivedByte+1; // Echo back the received byte+1 back to the computer } } Jetzt versuche ich das im Assembler nachzuprogrammieren. Jetzt kommt mir grad eine Idee. Ich nehm einfach mal das Programm als Assemblercode her und schau, was da anders ist. Ob das klappt!? :-)
Hi Chris, Glück gehabt, dass es geht, denn Du solltest zuerst das Hreg, dann das Lreg schreiben (wie in Deinem Assembler-Programm); also UBRR0H = (BAUD_PRESCALE >> 8); UBRR0L = BAUD_PRESCALE; Oder ganz einfach: UBRR0=BAUD_PRESCALE; //!! Gruß Fred
@Fred Mensch, super! Danke für deinen Tipp! Ich glaube das ist es. Ich hab jetzt grad mal das C Prg disassembled und den code aufgespielt. Der code anbei läuft natürlich. Dein Tipp und dies hat mich schließlich zu dem Problem geführt. LDS R24,0x00C1 ;Load direct from data space ORI R24,0x18 ;Logical OR with immediate STS 0x00C1,R24 ;Store direct to data space ; (0xC2) UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes LDS R24,0x00C2 ;Load direct from data space ORI R24,0x06 ;Logical OR with immediate STS 0x00C2,R24 ;Store direct to data space ; (0xC4) UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register LDI R24,0x67 ;Load immediate STS 0x00C4,R24 ;Store direct to data space ; (0xC5) UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register STS 0x00C5,R1 ;Store direct to data space ; while (((0xC0) UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been recieved and is ready to be read from UDR LDS R24,0x00C0 ;Load direct from data space SBRS R24,7 ;Skip if bit in register set RJMP PC-0x0003 ;Relative jump ; ReceivedByte = (0xC6) UDR0; // Fetch the recieved byte value into the variable "ByteReceived" LDS R25,0x00C6 ;Load direct from data space ; while (((0xC0) UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it LDS R24,0x00C0 ;Load direct from data space SBRS R24,5 ;Skip if bit in register set RJMP PC-0x0003 ;Relative jump ; (0xC6) UDR0 = ReceivedByte+1; // Echo back the received byte+1 back to the computer SUBI R25,0xFF ;Subtract immediate STS 0x00C6,R25 ;Store direct to data space RJMP PC-0x000D ;Relative jump RJMP PC-0x0000 ;Relative jump DANKESCHÖN!
Kurz und bündig: .include "m164Pdef.inc" .def temp = r16 ; Register für kleinere Arbeiten .def zeichen = r17 ; in diesem Register wird das Zeichen an die ; Ausgabefunktion übergeben .equ F_CPU = 16000000; Systemtakt in Hz .equ BAUD = 9600; Baudrate ; Berechnungen .equ UBRR_VAL2 = 103; Siehe Referenz Seite 197 von 436 .equ UBRR_VAL = ((F_CPU+BAUD*8)/(BAUD*16)-1); Clever runden .equ BAUD_REAL = (F_CPU/(16*(UBRR_VAL+1))); Reale Baudrate .equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000); Fehler in Promille .if ((BAUD_ERROR>10) || (BAUD_ERROR<-10)); max. +/-10 Promille Fehler .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!" .endif // Turn on the transmission and reception circuitry LDS temp,UCSR0B ;Load direct from data space ORI temp,0x18 ;Logical OR with immediate STS UCSR0B,temp ;Store direct to data space // Load the baud rate value into the low byte of the UBRR register LDI temp,UBRR_VAL2 ;Load immediate STS UBRR0L,temp ;Store direct to data space loop: ldi zeichen,'T' rcall serout ; Unterprogramm aufrufen ldi zeichen,'e' rcall serout ; Unterprogramm aufrufen ldi zeichen,'s' rcall serout ; ... ldi zeichen,'t' rcall serout ldi zeichen,'!' rcall serout ldi zeichen,10 rcall serout ldi zeichen,13 rcall serout rjmp loop serout: LDS temp,UCSR0A ;Load direct from data space SBRS temp,UDRE0 ;Skip if bit in register set RJMP serout ;Relative jump sts UDR0,zeichen ret ; zurück zum Hauptprogramm
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.