mikrocontroller.net

Forum: Compiler & IDEs Bekomme USART nicht initialisiert!


Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);
}

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lass das Register einfach in Ruhe.  Dessen Voreinstellung ist genau
das, was du willst.

Autor: Thomas (Gast)
Datum:

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Holger Krull (krulli) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Werner (Gast)
Datum:

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

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

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Bin schon neugierig wie ihr diesen Fall jetzt lösen wollt.

Mit konstanter Umgebungstemperatur und kalibriertem Oszillator. ;-)

MW

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Gast (Gast)
Datum:

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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 
;-)

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.