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.