Bekomme USART nicht initialisiert!

Gast #759433
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);
}
Gast #759599
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.
Gast #759726
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...
#759758
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
#759866
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.
Gast #760567
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!
Moderator Persönliche Seite #760703
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.
Gast #760896
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...
Moderator Persönliche Seite #760914
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.
Persönliche Seite #760952
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...
Gast #760954
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!
Persönliche Seite #760962
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.
Gast #761064
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?
Moderator Persönliche Seite #761075
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.
#761085
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.
Gast #761883
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
}
Moderator Persönliche Seite #761934
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren