Hi,
ich hab ein Probelem, ich arbeite gerade dass tutorial durch, und habe
eine frage zur UART Ausgabe... Ich will testweise einfach nur ein x
ausgeben. Ich habe den ATMega8 und hab auch schon ins Datenblatt
geschaut, komme aber nicht weiter..
Hier mein Code
#ifndef F_CPU
#define F_CPU 4000000UL
#endif
#define BAUD 9600UL
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
#error Systematischer Fehler der Baudrate grösser 1% und damit zu
hoch!
#endif
#include <avr/io.h>
#include <stdint.h>
void uart_init()
{
UCSRB |= (1<<TXEN);
UCSRC |= (1<<URSEL)|(3<<UCSZ0);
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;
}
int main(void)
{
uart_init();
while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich
*/
{
}
UDR = 'x';
}
Vielen Dank schonmal
Bitte.
Michael Kuehn wrote:
> Hi,> ich hab ein Probelem, ich arbeite gerade dass tutorial durch, und habe> eine frage zur UART Ausgabe... Ich will testweise einfach nur ein x> ausgeben. Ich habe den ATMega8 und hab auch schon ins Datenblatt> geschaut, komme aber nicht weiter..>> Hier mein Code
Vielleicht hülft's, die Frage auch zu stellen ;-)
Und wo genau ist das Problem?
Du kannst die AVR Checkliste abarbeiten. da steht einiges
Hilfreiches zu UART Problemen und mehr drin.
Ich habe bei deinem Code derzeit nur den Verdacht, dass es Probleme mit
der Taktquelle gibt. Die Definition von F_CPU deutet auf eine externe
Taktquelle hin, die natürlich 1. vorhanden und richtig angeschlossen
sein muss und 2. per richtig eingestellte AVR Fuses ggf. zum
Schwingen gebracht werden muss. Erst dann hat die Angabe F_CPU eine
Chance im folgenden Quellcode richtig interpretiert zu werden.
In deinem Code wird auch nur ein einzelnes x gesendet. Stelle das doch
mal auf "Dauerfeuer" um:
1
intmain(void)
2
{
3
uart_init();
4
for(;;)
5
{
6
while(!(UCSRA&(1<<UDRE)))/* warten bis Senden moeglich */
1) In den AVR-Sheets wird UBRRx vor UCSRx gesetzt. Warum änderst du
dieses Prozedere?
2) Schreibe hier korrekter, klarer und kürzer
1
UCSRx=...
anstatt
1
UCSRx|=...
3) AFAIK sollte man eine Toleranz von +/- 0.2 % einhalten. Ob dein Prog
richtig rechnet (sieht zumindest mal so aus), kannst zB hier
gegenkontrollieren:
http://www.gjlay.de/helferlein/avr-uart-rechner.html
Hier noch ne funktionierende init-Funktion:
Das Problem ist, dass ich das gesendete Zeichen nicht auf der seriellen
Schnittstelle empfange, sondern nur kryptischen Muell...
#define F_CPU 3686400
#include <avr/io.h>
#include <stdint.h>
#include <inttypes.h>
void USART_Init()
{
unsigned int baud = 1200;
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
UCSRB = (1<<RXEN)|(1<<TXEN);
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}
void USART_Transmit()
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'x';
}
int main ()
{
USART_Init();
for(;;)
{
USART_Transmit();
}
}
Das ist falsch:
unsigned int baud = 1200;
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
So kannst du die Baudrate nicht setzen. Im Datenblatt ist eine Tabelle,
in der steht, welche Werte bei welcher Baudrate in die Register UBRRL
und UBRRH müssen. Und im AVR GCC Tutorial ist eine Formel, die die Werte
aus der Wunschbaudrate und der Taktrate berechnet und sogar meldet, wenn
ein zu grosser Baudratenfehler auftreten würde.
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
^^^^
Warum hast du das dazu genommen? Das erfordert eine andere Einstellung
im Terminalprogramm auf dem PC (dem Empfänger): 2 Stoppbits!
Im allerersten Posting hattest du #define F_CPU 4000000UL und jetzt hast
du #define F_CPU 3686400. Hast du inzwischen die externe Taktquelle
gewechselt (anderer Quarz?). Wenn du eine externe Taktquelle hast
(welche?), kannst du mal die Fuses auslesen, einen Screenshot machen und
hier anhängen. Ich möchte nachsehen, ob die Taktquelle richtig
eingestellt ist.
So,
das mit den 2 Stoppbits, ist ok, dass habe ich bewusst gewählt und auch
im Terminalprogramm eingestellt.
Der Takt, wird ja von extern vorgegeben, über einen Quarz der mit
3,6864MHz läuft...
Wie kann ich die Fuses auslesen? Ich benutze AVRStudio4 und das myavr
Board
Für 2400baud kann ich die Register so setzen?
UBRRH = 0x50; //2400
UBRRL = 0x0f;
gemäß Tabelle Datenblatt
Michael Kuehn wrote:
> UBRRH = 0x50; //2400> UBRRL = 0x0f;
Nee. Ich lese im Datenblatt Tabelle 61 den Wert 95. Damit wäre die
Zeile:
UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen
UBBR = 0x5F; // Alternativ
Oder:
UBRRH = 0; // Selbst 2 8-Bit Zugriffe machen
UBRRL = 95;
Alternativ:
UBRRH = 0; // Selbst 2 8-Bit Zugriffe machen
UBRRL = 0x5F;
> Ich benutze AVRStudio4 und das myavr Board
Die Angabe hilft bereits. Wenn der originale AVR drauf ist, brauchst du
keine Fuses einzustellen. Das ist dann wohl schon ab Entwickler/Verkauf
gemacht. Jedenfalls sehe ich keinen Fuses-Einstellschritt in der
myAVR-Doku.
Stefan B. wrote:
> UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen> UBBR = 0x5F; // Alternativräusper
Wie soll das denn gehen???
&UBRRH = 0x40
&UBRRL = 0x29
Fällt was auf...?
Michael Kuehn wrote:
> #define BAUD 9600UL
Michael Kuehn wrote:
> unsigned int baud = 1200;
Michael Kuehn wrote:
> Für 2400baud kann ich die Register so setzen?
Etwas unentschlossen. Steht das Terminal immer noch richtig?
Flusskontrolle aus?
Johann L. wrote:
> Stefan B. wrote:>> UBRR = 95; // 16-Bit Zugriff dem Compiler überlassen>> UBBR = 0x5F; // Alternativ>> *räusper*>> Wie soll das denn gehen???>> &UBRRH = 0x40> &UBRRL = 0x29>> Fällt was auf...?
Nein auf Anhieb nicht. Habe ich das Makro für den 16-Bit Zugriff auf das
UBRR IO-Register falsch geschrieben?
ADD: Ah, jetzt ja ;-)
Beim Atmega8 liegen die beiden 8-Bit IO-Register nicht nebeneinander im
Speicher. Wahrscheinlich habe ich das falsch von anderen IO-Registern
übertragen (ADC?). Es gibt kein einzelnes UBRR Register. Man muss
getrennt mit UBRRL und UBRRH arbeiten. Danke, ich glaube das werde ich
nimmer vergessen, rotwerd ;-)
Stefan B. wrote:
> ADD: Ah, jetzt ja ;-)>> Beim Atmega8 liegen die beiden 8-Bit IO-Register nicht nebeneinander im> Speicher. Wahrscheinlich habe ich das falsch von anderen IO-Registern> übertragen (ADC?). Es gibt kein einzelnes UBRR Register. Man *muss*> getrennt mit UBRRL und UBRRH arbeiten. Danke, ich glaube das werde ich> nimmer vergessen, rotwerd ;-)
Ich hab's net ausprobiert, aber eigentlich müsste der Compiler
warnen/der Linker mackern, daß er UBRR nicht kennt, wenn man diesen
Zugriff versucht.
Kann mir nämlich kaum vorstellen, daß das Makro in den Headern drinne
ist (zumindest nicht für ATmega8).
Keine Ahnung, warum Atmel das so seltsam gemacht hat, zudem zusammen mit
UBSRC als Shadow. Ist wohl ein Silicon-Hack das...
Jepp, ADC packt man besser via 16-Bit-Zugriff an, zumal die Reihenfolge
auf lo/hi nicht egal ist.
Jetzt hast du mich mit runtergelassenen Hosen erwischt: Ich habe es
nämlich auch nicht im Compiler ausprobiert, sondern einfach
hingeschrieben. Wie gesagt, was falsch im Kopp drin ist, kommt nur durch
Fehlermachen (und einen der es merkt) raus.