Forum: Mikrocontroller und Digitale Elektronik mega164p: sbi UCSR0B,TXEN0; Operand 1 out of range


von Chris (Gast)


Lesenswert?

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

von Fred S. (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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?

von Fred S. (Gast)


Lesenswert?

Hi,

nimm den Code, den ich oben hingeschrieben habe, dann wird's gehen!

Gruß

Fred

von Chris (Gast)


Lesenswert?

@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!?

von Fred S. (Gast)


Lesenswert?

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

von Jörg X. (Gast)


Lesenswert?

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 ;)

von Chris (Gast)


Lesenswert?

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

von Fred S. (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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 ... ;-)

von Fred S. (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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!? :-)

von Fred S. (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

@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!

von Chris (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.