Forum: Compiler & IDEs Bekomme USART nicht initialisiert!


von Thomas (Gast)


Lesenswert?

Hallo ihr!
Hab ein Problem, das Doppelregister UCSRC wird nicht gesetzt.
Ich habe ein Pollin Platine und diesen Programm-code.
Wenn ich im Einzelstep-Betrieb durch den Code gehe, dann wird nie das
UCSRC Register gesetzt.
Hat vielleicht jemand eine Idee warum?
Danke schonmal vorab...

#define F_CPU 16000000UL  //CPU Takt vorgeben
#include <avr/interrupt.h>
#include <avr/io.h>
//#include <lcd_func.h>
#include <util/delay.h>

void usart_init(void);  //Funktion USART Initialisieren

void uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE)));  /* warten bis Senden moeglich */

    UDR = c;                      /* sende Zeichen */
}

void uart_puts (unsigned char *s)
{
    while (*s)
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
        uart_putc(*s);
        s++;
    }
}

//Hauptprogramm
int main (void)
{
unsigned char string[8]= "Hallo";
usart_init();    //USART Initialisieren
uart_puts(string);

while(1);
return 0;
}

//Funktion zur Initialisierung des USART
//Baudrate=9600, Datenbits=8Datenbits
//kein Parrity, 1Stopbit, asynchron
void usart_init(void)
{
unsigned int baud = 0x0067;
//Baudrate=9600; 16Mhz/(16*9600)-1=103,17=0x67

//UCSRC = 0x80;
//UCSRC = UCSRC | 0xFF;

UBRRH=(unsigned char)(baud>>8);    //High Byte der Baudrate
UBRRL=(unsigned char)baud;      //Low Byte der Baudrate
// Aktivieren von receiver und transmitter
UCSRB = (1<<RXEN)|(1<<TXEN);

UCSRC = (1<<URSEL);
    // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Lass das Register einfach in Ruhe.  Dessen Voreinstellung ist genau
das, was du willst.

von Thomas (Gast)


Lesenswert?

Ja, laut der Anleitung musste die Voreinstellung stimmen.
Stimmt aber leider nicht, das Register ist bei mir auf 0x00.

von Falk B. (falk)


Lesenswert?

@  Thomas (Gast)

>Ja, laut der Anleitung musste die Voreinstellung stimmen.
>Stimmt aber leider nicht, das Register ist bei mir auf 0x00.

Und genau das brauchst du ja!

MFG
Falk

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Du kannst das nicht lesen, weil du dann immer nur das Alternativregister
(ist ja ein Doppelregister) liest!  Tu dir und uns einen Gefallen und
glaube dem Datenblatt, dass die Voreinstellung OK ist und mach einfach
weiter an dieser Stelle.

von Falk B. (falk)


Lesenswert?


von Thomas (Gast)


Lesenswert?

Mit diesem Programm müsste mir der Hyperterminal doch eigentlich das 
Hallo ausgeben, oder?
von RS232 über Nullmodemkabel an PC und die Hyperterminal-Einstellungen 
wie bei USART.

von Falk B. (falk)


Lesenswert?


von Holger K. (krulli) Benutzerseite


Lesenswert?

Thomas wrote:
> von RS232 über Nullmodemkabel an PC und die Hyperterminal-Einstellungen
> wie bei USART.
Wenn Du das Pollinbrett hast, dann brauchst Du ein Verlängerungskabel 
(1:1) und kein Nullmodemkabel.

von Werner (Gast)


Lesenswert?

1
UBRRH = 0;
2
UBRRL = 7; //47=9k6, 7= 57k6, 3=115k2 bei 7.3728 MHz Quarz
3
UCSRB = 1<<RXEN | 1<<TXEN ;
4
UCSRC = 1<<URSEL | 1<<UCSZ1 | 1<<UCSZ0; //8N1

So geht's, wenn du das UCSRC Register unbedingt nochmal selber setzten 
willst.

von Thomas (Gast)


Lesenswert?

Ich muss euch nochmal nerven.
Bekomme nur ein Zeichen (ein großes C mit Punkt drüber) auf dem 
Hyperterminal dargestellt, wenn ich beim Hyperterminal eine Baudrate 
tiefer als bei USART_init.
Benutze einfaches serielles Verlängerungskabel, Flusssteuerung aus.
Hatte dein Eingang TX RX vom MAX232 schon überbrückt, dann bekomme ich 
das Echo vom Hyperterminal zurück.
Was mache ich falsch? Wo muss so ein externer Quarz ran?

Danke...

von Falk B. (falk)


Lesenswert?

@ Thomas (Gast)

>Bekomme nur ein Zeichen (ein großes C mit Punkt drüber) auf dem
>Hyperterminal dargestellt, wenn ich beim Hyperterminal eine Baudrate
>tiefer als bei USART_init.

Warum tiefer? Sie muss GLEICH sein.

>Benutze einfaches serielles Verlängerungskabel, Flusssteuerung aus.
>Hatte dein Eingang TX RX vom MAX232 schon überbrückt, dann bekomme ich
>das Echo vom Hyperterminal zurück.

D.h. dein Kabel + MAX sind OK. Bleiubt nur noch der uC.

>Was mache ich falsch? Wo muss so ein externer Quarz ran?

An den uC. Und dann auch die AVR Fuses so setzen, dass der auch 
verwendet wird.

MFg
Falk

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas wrote:

> Was mache ich falsch?

Meine gerade aus der Reparatur gekommene Kristallkugel behauptet, dass
du noch mit dem internen RC-Oszillator (1 MHz bei Vcc = 5 V) arbeitest
statt mit einem Quarz.

von Karl H. (kbuchegg)


Lesenswert?

Thomas wrote:

> Was mache ich falsch? Wo muss so ein externer Quarz ran?

Wo sind denn jetzt die ganzen Experten, die noch vor ein
paar Tagen behauptet haben mit dem internen Takt gäbe es
bei UART überhaupt keine Probleme?

Bin schon neugierig wie ihr diesen Fall jetzt lösen wollt.

von Michael Wilhelm (Gast)


Lesenswert?

>Bin schon neugierig wie ihr diesen Fall jetzt lösen wollt.

Mit konstanter Umgebungstemperatur und kalibriertem Oszillator. ;-)

MW

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger wrote:

> Wo sind denn jetzt die ganzen Experten, die noch vor ein
> paar Tagen behauptet haben mit dem internen Takt gäbe es
> bei UART überhaupt keine Probleme?

Es gibt nur ein einziges Problem damit, vermute ich mal: er schwingt
einfach mal nicht auf 16 MHz...

von Thomas (Gast)


Lesenswert?

So, funktioniert. Externer Quarz war der Schlüssel zur Lösung.
Nachdem ich die Fusebits gesetzt hab ging es.

Ich danke euch alle...
nochmal ne frage zum internen Clock, auf welcher Frequenz läuft der beim 
Atmega32. Hab irgendwo 1Mhz gelesen. Ist das richtig?

Danke nochmal!

von Gast (Gast)


Lesenswert?

default clock source -> 1MHz
Internal Calibrated RC Oscillator Operating Modes -> 1/2/4/8MHz

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Gast wrote:

> Internal Calibrated RC Oscillator Operating Modes -> 1/2/4/8MHz

Beim ,,alten'' RC-Oszillator, das waren da noch vier verschiedene
Oszillatoren, und automatisch kalibriert wurde nur der erste
davon.

Die neueren AVRs (das beginnt beim ATmega88 & Co.) haben nur noch
einen RC-Oszillator, und der wird automatisch vorkalibriert (in
der Regel für einen Betrieb bei Vcc = 5 V).  Der Oszillator selbst
läuft dort mit 8 MHz, allerdings ist im Auslieferungszustand die
CKDIV8-Fuse gesetzt, die den clock prescaler auf 1:8 voreinstellt,
sodass er effektiv auch wieder mit 1 MHz startet.

von Thomas (Gast)


Lesenswert?

Mein Display funktioniert jetzt jedoch nicht mehr, sobald ich auf 
externen Quarz umschalte. Kann das an den Delay Schleifen liegen, das 
dort jetzt eine andere Zeit rein muss?

von Falk B. (falk)


Lesenswert?

Ja.

von Thomas (Gast)


Lesenswert?

warum gebe ich dann die Frequnenz vom µC vor, wenn die sowieso abhängig 
ist von intern oder externen Quarz?

#define F_CPU 16000000UL  //CPU Takt vorgeben
#include <util/delay.h>    //Header für delay

Mit der 16 x fachen Zeit (vorher 1Mhz intern, jetzt 16Mhz extern)
in delay geht es aber leider auch nicht.

Danke euch...

von Johannes M. (johnny-m)


Lesenswert?

An den Parametern der _delay_XX-Aufrufe wird gar nichts geändert! Nur 
die Taktfrequenz muss richtig angegeben werden. Wenn die stimmt, dann 
stimmen auch die Wartezeiten.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Kann aber natürlich sein, dass dein Display einfach mal langsamer
ist als die Annahmen, die der Code gemacht hat (vielleicht braucht
der Controller einfach mehr Zeit, als der originale HD44780
spezifiziert hatte).  Solange deine Delays alle auf Grund des
falschen Taktes 16x so lange waren, hat's dann noch funktioniert,
nun nicht mehr.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Auch muss man die maximalen Werte bei der _delay_ms und _delay_us 
Funktion beachten.

Die Maximalwerte sind nämlich von der F_CPU abhängig und wenn die 
eigenen Werte diese überschreiten, gibt es keine "Funktionsgarantie" 
mehr.

Unter Umständen muss man also ein _delay_ms(LANGEZEIT) in mehrere 
_delay_ms(KURZEZEIT) aufteilen.

Bei einem Wechsel von 1 MHz auf 16 MHz ist es nahezu sicher, dass hier 
im Quellcode nachgearbeitet werden muss. Der Maximalwert bei 16 MHz ist 
nur 1/16-tel des Wertes bei 1 Mhz...

von Thomas (Gast)


Lesenswert?

Ging mit 16-fach auch nicht.
Also, habe das FuseBit auf 16MHz externen Quarz eingestellt,
danach ging das Display nicht mehr.
Hab jetzt in der Header von delay die 1Mhz durch 16Mhz ersetzt

#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for <util/delay.h>"
#define F_CPU 16000000UL     //   <-----Hier
#endif

In meinen Programmkopf steht trotzdem noch mein CPU Takt

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

Leider funktioniert es aber immernoch nicht. Habe auch spassighalber
mal die Delays verlängert. Auch keine Änderung!

von Johannes M. (johnny-m)


Lesenswert?

Stefan "stefb" B. wrote:
> Auch muss man die maximalen Werte bei der _delay_ms und _delay_us
> Funktion beachten.
...Steht aber auch alles in der erwähnten Dokumentation...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

Das hat nur eine Wirkung, wenn F_CPU nicht anderswo definiert ist. Wenn 
F_CPU anderswo definiert ist, wird der dortige Wert genommen.

Anderswo kann heissen in den Projekteinstellungen (project 
configuration) von AVR Studio oder im Makefile, wenn du mit WinAVR 
arbeitest oder AVR Studio mit einem externen Makefile arbeitest.

Benutze mal nur

#define F_CPU 16000000UL

und achte auf Warnungen bzgl. Redefinition von F_CPU bzw. ob das LCD 
jetzt funktioniert.

Wenn du den LCD Code in einem extra *.c File hast, achte darauf, dass 
dort auch die richtige F_CPU ankommen muss! Es nutzt nix das im main.c 
zu setzen und im lcd.c wegen fehlendem F_CPU einen anderen Defaultwert 
zu benutzen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Johannes M. wrote:
> Stefan "stefb" B. wrote:
>> Auch muss man die maximalen Werte bei der _delay_ms und _delay_us
>> Funktion beachten.
> ...Steht aber auch alles in der erwähnten Dokumentation...

Für 2008 habe ich mir vorgenommen, einmal am Tag das RTFM zu vermeiden 
;-)

von Thomas (Gast)


Lesenswert?

So läuft wieder mit den alten Delay Einstellungen.
Nur in der Header von delay die neue Frequenz eingestellt.
Muss jedoch den Optimierungsgrad auf von Os auf O0 (keine Optimierung) 
stellen. Andere Optimierungsgrade gehen auch nicht.
Leider wird mein Programm dadurch zu groß.

Kann ich da noch was dran ändern?
Warum wird die Delay Funktion mit Optimiert?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Deine Zeiten sind zu kurz für dein Display!

Glaub's doch endlich, statt mit trial&error hier irgendwas
zusammenzuwurschteln.

Ermittle doch bitte mal einfach systematisch, welche der Zeiten du
vergrößern musst, damit das Display wieder ,,spielt''.  U. U. ist es
nur eine einzige Zeit, an der du was drehen musst, z. B. die für den
E-Impuls.

von Johannes M. (johnny-m)


Lesenswert?

Thomas wrote:
> So läuft wieder mit den alten Delay Einstellungen.
> Nur in der Header von delay die neue Frequenz eingestellt.
> Muss jedoch den Optimierungsgrad auf von Os auf O0 (keine Optimierung)
> stellen.
Die Funktionen aus der delay.h funktionieren aber nur mit 
eingeschalteter Optimierung korrekt. Dass es bei Dir jetzt funktioniert, 
liegt mit Sicherheit daran, dass durch die abgeschaltete Optimierung die 
Zeiten viel länger sind, als eingestellt.

von Thomas (Gast)


Lesenswert?

Die delay Zeiten sind lang genug.
Hab den Grund jetzt raus gefunden. Und zwar frage ich ab einer betimmten 
Stelle bei der Display init nur noch das Busy ab. Dazu werden die Werte 
von PINB gelesen. Wenn das Display jedoch noch nicht fertig ist, gehe 
ich in eine Schleife und Frage immer wieder Busy ab. Jedoch wird der 
Wert an PINB nicht mehr aktualisert. Er bleibt in der Schleife hängen.

Hab es schon mit volatile PINB versucht. Klappt aber auch nicht. Werd 
weiter suchen...

#define PINB* (volatile unsigned char*)0x16

//Funktion fragt das Busy des Display2 ab, ob Display bereit ist
//neue Befehle zu verarbeiten
void dis2_ready(void)
{
volatile unsigned char a=0;
unsigned char busy=1,status;
DDRB=0xF0;      //B0-B3 Eingänge, B4-B7 Ausgänge
while (busy)      //Schleife solange Busy=1
{
  PORTB = 0x00;    //EN2=0, RS=0, R/W=0
  PORTB = PORTB | 0x10;  //R/W=1
  PORTB = PORTB | 0x80;  //EN2=1
  a=PINB;      //PORTB lesen, High Nibbel 1
  PORTB = PORTB &~ 0x80;  //EN2=0
  status = (a<<4) & 0xF0;  //4x shifting links
  PORTB = PORTB | 0x80;  //EN2=1
  a = PINB & 0x0F;    //PORTB lesen, low Nibbel 2
  PORTB = PORTB &~ 0x80;  //EN2=0
  status = status | a;
  if ((status & 0x80)==0x00)
    busy=0;    //Busy=0 Abbruch
}

von Karl H. (kbuchegg)


Lesenswert?

Leg da

>  PORTB = PORTB | 0x80;  //EN2=1
>  a=PINB;      //PORTB lesen, High Nibbel 1

mal eine kleine Pause dazwischen und gib dem Display
ein bischen Zeit auf deinen Leseversuch zu reagieren
und die Daten auf den Bus zu legen

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger wrote:

> ... mal eine kleine Pause dazwischen und gib dem Display
> ein bischen Zeit auf deinen Leseversuch zu reagieren
> und die Daten auf den Bus zu legen

Jaja, da bin ich seinerzeit auch drüber gestolpert bei meiner
LCD-Bibliothek. ;-)  Das ist ein AVR-Feature (ist so dokumentiert):
Das Sampeln der Eingangsdaten an PINx erfolgt vor dem Aktivieren
der Ausgangsdaten von PORTx.  Gesampelt wird auf der steigenden
Taktflanke des CPU-Taktes, aber die Ausgangsregister werden erst mit
der fallenden Flanke aktualisiert.  Das LCD müsste also einige 100 ns
vorher bereits ahnen, dass es jetzt das BUSY-Bit ausgeben soll...

Ein einzelner NOP (oder jeder beliebige andere Befehl) dazwischen
genügt.

Mit ausgeschalteter Optimierung geht es, weil die PORTx- und PINx-
Aktivitäten dann über LDS/STS in mehreren Befehlen realisiert werden.

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.