Forum: Mikrocontroller und Digitale Elektronik Probleme mit Uart (Atmega88)


von horst (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Hab mir soeben ein Programm zum Testen für den Uart geschrieben. 
Allerdings will der µC kein Zeichen ausgeben. Ich befürchte schon das 
ich irgendetwas falsch gemacht oder vergessen habe.

Kann mir da jemand helfen?

(Programm im Anhang)

von Karl H. (kbuchegg)


Lesenswert?

1
USART_Init:
2
  ; Set baud rate
3
  sts UBRR0H, r17
4
  sts UBRR0L, r16

Aha. Und welche Werte stehen in R16 bzw. R17 zum Zeitpunkt, an dem du 
die USART_Init aufrufst?

von spess53 (Gast)


Lesenswert?

>.def temp    = r16            ; Register für kleinere Arbeiten
>.def zeichen = r17            ; in diesem Register wird das Zeichen an die

>    ldi r16, 'A'

>sts UBRR0H, r17
> sts UBRR0L, r16

Was denn nun? temp/zeichen oder r16/r17?

Entscheide dich für eine Variante. So wirst du früher oder später, 
eher früher, Probleme bekommen.

MfG Spess

von oldmax (Gast)


Lesenswert?

Hi
Ich hab dir mal die Initialisierung angehängt, die ich für meinen 
Atmega8 immer nehme. Wichtig ist, das du auch den 16 MHz Takt hast, also 
einen Quarz. Ich kenn den Atmega48 nicht, aber er soll ja zum Atmega8 
kompatibel sein. Die folgenden Zeilen hast du vermutlich wie ich auch 
aus dem Tutorial entnommen.
1
;***********************************************************************
2
;* Die folgenden Zeilen definieren Constanten. Diese Werte werden  *
3
;* nur einmal vom  Compiler zugewiesen und dann nicht mehr verändert.  *
4
;***********************************************************************
5
.EQU   F_CPU  = 1600000    ; Systemtakt in Hz
6
.EQU   BAUD  = 9600      ; Baudrate ; Berechnungen
7
.EQU   UBRR_VAL  = ((F_CPU+BAUD*8)/(BAUD*16)-1)    ; clever runden
8
.EQU   BAUD_REAL= (F_CPU/(16*(UBRR_VAL+1)))   ; Reale Baudrate
9
.EQU   BAUD_ERROR= ((BAUD_REAL*1000)/BAUD-1000)    ; Fehler in Promille 
10
11
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))    ; max. +/-10 Promille Fehler  
12
.error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
13
.endif
Du darfst hier nicht davon ausgehen, das du mit
.EQU   F_CPU  = 1600000
den Systemtakt setzt, sondern den mußt du über die Fuses setzen. Aber 
den externen Takt nicht vergessen, sonst ist es Essig mit weiteren 
Zugriffen auf den µC.
Die Initialisierung erfolgt dann bei mir wie folgt:
1
;---------------- Serielle Schnittstelle parametrieren ------------------
2
;***********************************************************************
3
;* Die Parametrierung ist mit dem Koppelpartner abzustimmen.    *
4
;***********************************************************************
5
INIT_UART:  
6
  LDI  Reg_A, HIGH(UBRR_VAL)    ; Baudrate einstellen
7
  OUT  UBRRH, Reg_A
8
  LDI  Reg_A, LOW(UBRR_VAL)
9
  OUT  UBRRL, Reg_A
10
  ; Frame-Format: 8 Bit
11
   LDI  Reg_A, (1<<URSEL)|(3<<UCSZ0)
12
  OUT  UCSRC, Reg_A
13
   SBI  UCSRB, TXEN    ; TX aktivieren
14
  SBI  UCSRB, RXCIE                ; Interrupt bei Empfang    
15
  SBI  UCSRB, RXEN                 ; RX (Empfang) aktivieren
16
RET
Den Interrupt für den Empfang brauchst du ja noch nicht freigeben, wenn 
du es aber tust, dann muß auch eine ISR existieren, oder zumindest ein 
RETI hinter
1
.org URXCaddr  JMP int_rxc  ; USART Receive Complete Interrupt Vector Address
Die Senderoutine ist jedenfalls einfach:
1
;------------- serielle Ausgabe  -----------------------
2
3
SerOut:  SBIS  UCSRA,UDRE  ; Warten Freigabe UDR 
4
  RJMP  SerOut
5
      OUT  UDR, Send_Byte    ; Register Send_byte enthält die Daten 
6
RET
Deine Sendesequenz ist
1
     ldi r16, 'A'
2
     sts UDR0, r16
Wie du siehst, wartest du nicht ab, bis der Wert vom UART auch als 
"versendet" gemeldet wird. des weiteren ist UDR im EA-Bereich und muß 
mit "Out" angesprochen werden.
Zumindest ist das beim Atmega8 so.
Gruß oldmax

von horst (Gast)


Angehängte Dateien:

Lesenswert?

OK danke soweit...

Ich hab mal das ganze überarbeitet, assemblieren lässt es sich zwar aber 
ich bekomm noch immer keine Zeichen??

Mit dem Beispielprogramm vom Atmega8 (AVR_Tutorial) Funktioniert es.

Aber mit meinem Atmega88 bekomm ich es einfach nicht hin.
Außerdem versteh ich nicht ganz warum es UCSR0A, UCSR0B und UCSR0C gibt, 
kann ich mir da irgendeinen aussuchen?

(Code im Anhang)

von oldmax (Gast)


Lesenswert?

Hi
Wie wär es mal mit dem Datenblatt ? Kann ich zwar auch auf machen und 
dir dann alles vorlesen, doch ich glaub, du hast dann bestimmt eine 
weitere Frage und ich muß dann weiterlesen....
Gruß oldmax

von spess53 (Gast)


Lesenswert?

Hi

> TX Aktivieren

>    lds temp, UCSR0C,
>    sbrs temp, TXEN0

Da wird nix aktiviert. TXEN0 befindet sich im Register UCSR0B.

>serout:
>    lds temp, UCSR0C
>    sbrs temp, UDRE0

Ähnlichr Fall: UDRE0 ist im Register UCSR0A.

>Außerdem versteh ich nicht ganz warum es UCSR0A, UCSR0B und UCSR0C gibt,
>kann ich mir da irgendeinen aussuchen?

Nein. Die Bits in den Registern UCSR0A, UCSR0B und UCSR0C haben 
unterschiedliche Funktionen.

Tu dir einen Gefallen und lies das Datenblatt. Dort sind sogar Beispiele 
in Assembler drin.

MfG Spess

von Stefan E. (sternst)


Lesenswert?

spess53 schrieb:
>> TX Aktivieren
>
>>    lds temp, UCSR0C,
>>    sbrs temp, TXEN0
>
> Da wird nix aktiviert. TXEN0 befindet sich im Register UCSR0B.

Und selbst wenn es das richtige Register wäre ...

sbrs = Skip if Bit in Register is Set
und nicht etwa "Set Bit in Register"
(außerdem würde in dem Fall dann auch immer noch das Zurückschreiben 
fehlen)

von spess53 (Gast)


Lesenswert?

Hi

>Und selbst wenn es die richtigen Register wären ...

Ich weiss. Aber der TO hat primär erst einmal ein absolutes 
Verständnisproblem mit der Funktion der einzelnen Register und der darin 
enthaltenen Bits.

MfG Spess

von horst (Gast)


Angehängte Dateien:

Lesenswert?

Als erstes habe ich versucht das Programm von Atmega8 zu ändern.. ohne 
Erfolg
Dann habe ich einige Codebeispiele aus google zusammengestöbseln.. ohne 
Erfolg

Jetzt habe ich mir das Datenblatt angesehen (etwas spät aber doch) und 
auch die Beispielcodes angepasst, da ich ja IN/OUT nicht verwenden kann. 
Warum auch immer das im Datenblatt so geschrieben ist.

USART_Transmit:
    ldi temp, UCSR0A
    sbis temp, UDRE0
    rjmp USART_Transmit
    sts UDR0, temp

Bei sbis bekomm ich einen I/O Fehler, warum?
Ich kann mit sbis im register UCSR0A nicht direkt kontrollieren ob das 
bit 5 (udre0) gesetzt ist. Deshalb auch der umweg über ein Register.

Keine Ahnung aber irgendwie steh ich total auf der Leitung, kann mir 
jemand helfen?

Wenn ich es mit sbrs versuche funktioniert das assemblieren, aber am pc 
tut sich nix?

von spess53 (Gast)


Lesenswert?

Hi

>Bei sbis bekomm ich einen I/O Fehler, warum?

'sbis' kann nur auf IO-Register zugreifen. 'temp' ist aber ein Register 
aus r0...r31, auf das man mit 'SBRS' zugreift.

MfG Spess

von horst (Gast)


Lesenswert?

spess53 schrieb:
> Ich weiss. Aber der TO hat primär erst einmal ein absolutes
> Verständnisproblem mit der Funktion der einzelnen Register und der darin
> enthaltenen Bits.

Stimmt allerdings, da ich beim Atmega8 einfach die im AVR-Tutorial 
verwendeten Codeabschnitte mit den Registern abgeschrieben habe.

Da muss ich mir wohl das Datenblatt des Atmega88 genau durchlesen. Aber 
dennoch verstehe ich nicht warum die Codebeispiele mit IN und OUT 
angegeben sind?

von spess53 (Gast)


Lesenswert?

Hi

>dennoch verstehe ich nicht warum die Codebeispiele mit IN und OUT
>angegeben sind?

Du hast recht, die sind falsch. Ich nehme an, die sind etwas gedankenlos 
von älteren Datenblättern übernommen worden.

Bei älteren oder kleineren AVRs liegen die (meisten) IO-Register in dem 
Bereich, den Befehle in, out und eingeschränkt cbi, sbi, sbis und sbic 
adressieren können.

Im Datenblatt deines AVRs gibt es ein 'Register Summary'. Dort sind die 
Adressen der IO-Register enthalten. Bei Fehlermeldungen kannst du da 
nachsehen ob der Befehl zu dem benutzten Register passt.

MfG Spess

von horst (Gast)


Lesenswert?

spess53 schrieb:
> Im Datenblatt deines AVRs gibt es ein 'Register Summary'. Dort sind die
> Adressen der IO-Register enthalten. Bei Fehlermeldungen kannst du da
> nachsehen ob der Befehl zu dem benutzten Register passt.

Danke, das wusste ich auch nicht, aber sehr hilfreich!

Hast du meinen letzten Code angeguckt und irgendwas auffälliges gefunden 
warum mein Code noch immer nicht funktioniert?

von spess53 (Gast)


Lesenswert?

Hi

>Hast du meinen letzten Code angeguckt

Bis eben nicht

>und irgendwas auffälliges gefunden
>warum mein Code noch immer nicht funktioniert?

Was mir sofort auffällt, da (<<<<<<<) fehlt  ein 'ret'

>    rjmp USART_Transmit
>    sts UDR0, temp
     ret                 <<<<<<<<<

>ende:
>    rjmp ende

MfG Spess

von Stefan E. (sternst)


Lesenswert?

1
    ldi temp, 'T'
2
    rcall USART_Transmit
3
...
4
USART_Transmit:
5
    ldi temp, UCSR0A
6
    sbis temp, UDRE0
7
    rjmp USART_Transmit
8
    sts UDR0, temp
Es könnte von Vorteil sein, wenn man das Register mit dem zu sendenden 
Zeichen nicht vor dem eigentlichen Senden für was anderes benutzt.

von horst (Gast)


Lesenswert?

Super, Danke!

Peinlicher Fehler

von horst (Gast)


Angehängte Dateien:

Lesenswert?

Hier das aktuelle Programm.
Bis jetzt noch immer kein Erfolg :(

Fuses geprüft.. einfach alles. Es kommt nicht einmal Datenmüll :/

von spess53 (Gast)


Lesenswert?

Hi

>USART_Transmit:
    ldi temp2, UCSR0A    !!!!!!!!!!!!!!!!!
    sbrs temp2, UDRE0
    rjmp USART_Transmit
    sts UDR0, temp
    ret

Du willst den Inhalt von UCSR0A, nicht die Adresse.

->     lds temp2, UCSR0A
       ^^^

MfG spess

von horst (Gast)


Lesenswert?

Sehr Gut!
Jetzt bekomm ich Datenmüll =)

Aber es ist schon ein Anfang...

Ich habe lt. Engbedded AVR Fuse Calculator folgende Fuse Einstellungen 
vorgenommen: -U lfuse:w:0x7f:m -U hfuse:w:0xdf:m -U efuse:w:0x01:m 
(letzte Quarzauswahl in der Liste)

Die Baudrate beträgt am µC und PC 9600
Der Quarz und Takt 8Mhz

von horst (Gast)


Angehängte Dateien:

Lesenswert?

Meine Aktuelles Programm wieder im Anhang

Scheinbar werden alle Zeichen missintrerpretiert, da nicht einmal der 
Zeilenumbruch als solches erkannt wird.

Die Fuses Einstellungen müssten stimmen oder?

von Stefan E. (sternst)


Lesenswert?

horst schrieb:
> Die Fuses Einstellungen müssten stimmen oder?

Nein. CKDIV8!

von horst (Gast)


Lesenswert?

Juhu!!

Vielen Dank an alle! Jetzt funktioniert es!

Verwendete Fuses: -U lfuse:w:0xff:m -U hfuse:w:0xdf:m -U efuse:w:0x01:m

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.