Forum: Mikrocontroller und Digitale Elektronik ATMega644 UART


von Hans-Peter (Gast)


Lesenswert?

Hallo zusammen,

ich benutze einen ATMega644 und will daten vom ADC über den UART Senden.
Leider kommt da nichts an. Mit einem ATMega32 funktioniert es ohne 
Probleme d.h. dass mein Terminal Programm richtig geschrieben ist und 
der Fehler am uC liegt. Die Register hab ich auch angepasst, sodass es 
eigentlich auf dem AtMega644 funktionieren sollte.

Hier der Code:

#ifdef F_CPU
#undef F_CPU
#define F_CPU 16000000UL
#endif

#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>




// Diese Beispiel zeigt die Anwendung des ADC eines ATmega169
// unter Verwendung der internen Referenzspannung von nominell 1,1V.
// Zur Anpassung an andere AVR und/oder andere Referenzspannungen
// siehe Erläuterungen in diesem Tutorial und im Datenblatt

/* ADC initialisieren */
void ADC_Init(void)
{
  // die Versorgungsspannung AVcc als Referenz wählen:
  //ADMUX = (1<<REFS0);
  // oder interne Referenzspannung als Referenz für den ADC wählen:
  ADMUX = (1<<REFS1) | (1<<REFS0);

  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
  // schon auf 0, also single conversion
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man 
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu 
lassen" */

  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der 
Konvertierung warten
  }
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */
  (void) ADCW;
}

/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung 
warten
  }
  return ADCW;                    // ADC auslesen und zurückgeben
}


void USART_Init( unsigned int baud )
  {
    /*Set baud rate*/
    UBRR0H = (unsigned char)(baud>>8);
    UBRR0L = (unsigned char)baud;
    /* Enable receiver and transmitter*/
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
    /* Set frame format: 8data, 2stop bit*/
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
  }


  void USART_Transmit( unsigned char data )
  {
    /* Wait for empty transmit buffer*/
    while
     ( !( UCSR0A & (1<<UDRE0)) );
    /* Put data into buffer, sends the data*/
    UDR0 = data;
  }

  void uart_puts( char *s )
  {
    /* while *s != '\0' so unequally "string-end characters (terminator) 
*/
    while (*s)
    {
      USART_Transmit(*s);

      s++;
    }
  }


void main(void)
{
  USART_Init(0x67);
  char String[16] = {"Test "};
  short ADCWert;
    ADC_Init();
  while(1)
  {
    ADCWert = ADC_Read(4);

    sprintf(String,"Test: %i\n", ADCWert);
    uart_puts(String);
    //USART_Transmit(S);
        _delay_ms(1000);
  }

}

von Hans-Peter (Gast)


Lesenswert?

muss ich die Baudrate neu berechnen?
am Quarz hab ich aber nichts geändert.
der ATMega32 läuft bis zu 16Mhz
der AtMega644 läuft bis zu 20 Mhz

Ich betreibe den Controller mit 16Mhz

von Mein grosses V. (vorbild)


Lesenswert?

Hans-Peter schrieb:
> muss ich die Baudrate neu berechnen?

Nein.
Aber diese Einstellungen:

1
UCSR0B = (1<<RXEN0)|(1<<TXEN0);

werden in UCSR0A gemacht.

von (prx) A. K. (prx)


Lesenswert?

Hans-Peter schrieb:
> USART_Init(0x67);

0x67 = 103 => 16 MHz / (16*104) = ~6 kHz.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Also ich verstehe weder vorbild noch prx.

von (prx) A. K. (prx)


Lesenswert?

S. Landolt schrieb:
> Also ich verstehe weder vorbild noch prx.

Ich auch nicht. ;-)
Tippfehler im Taschenrechner.

Allerdings war ein Hex-Angabe an dieser Stelle arg verdächtig.
Wer macht denn sowas?

: Bearbeitet durch User
von Bastian W. (jackfrost)


Lesenswert?

Kannst du einen String senden , ohne das du den ADC initialisierst und 
die Messung startest ?

Gruß JackFrost

von Hans-Peter (Gast)


Lesenswert?

Muss ich nur diese Einstellungen ändern?
UCSR0A = (1<<RXEN0)|(1<<TXEN0);

hat leider auch nichts gebracht

#ifdef F_CPU
#undef F_CPU
#define F_CPU 16000000UL
#endif

#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>




// Diese Beispiel zeigt die Anwendung des ADC eines ATmega169
// unter Verwendung der internen Referenzspannung von nominell 1,1V.
// Zur Anpassung an andere AVR und/oder andere Referenzspannungen
// siehe Erläuterungen in diesem Tutorial und im Datenblatt

/* ADC initialisieren */
void ADC_Init(void)
{
  // die Versorgungsspannung AVcc als Referenz wählen:
  //ADMUX = (1<<REFS0);
  // oder interne Referenzspannung als Referenz für den ADC wählen:
  ADMUX = (1<<REFS1) | (1<<REFS0);

  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
  // schon auf 0, also single conversion
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man 
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu 
lassen" */

  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der 
Konvertierung warten
  }
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */
  (void) ADCW;
}

/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung 
warten
  }
  return ADCW;                    // ADC auslesen und zurückgeben
}


void USART_Init( unsigned int baud )
  {
    /*Set baud rate*/
    UBRR0H = (unsigned char)(baud>>8);
    UBRR0L = (unsigned char)baud;
    /* Enable receiver and transmitter*/
    UCSR0A = (1<<RXEN0)|(1<<TXEN0);
    /* Set frame format: 8data, 2stop bit*/
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
  }


  void USART_Transmit( unsigned char data )
  {
    /* Wait for empty transmit buffer*/
    while
     ( !( UCSR0A & (1<<UDRE0)) );
    /* Put data into buffer, sends the data*/
    UDR0 = data;
  }

  void uart_puts( char *s )
  {
    /* while *s != '\0' so unequally "string-end characters (terminator) 
*/
    while (*s)
    {
      USART_Transmit(*s);

      s++;
    }
  }


void main(void)
{
  USART_Init(0x67);
  char String[16] = {"Test "};
  short ADCWert;
    ADC_Init();
  while(1)
  {
    ADCWert = ADC_Read(4);

    sprintf(String,"Test: %i\n", ADCWert);
    uart_puts(String);
    //USART_Transmit(S);
        _delay_ms(1000);
  }

}

von (prx) A. K. (prx)


Lesenswert?

Mein grosses V. schrieb:
> Aber diese Einstellungen:
> werden in UCSR0A gemacht.

Nein.

von Mein grosses V. (vorbild)


Lesenswert?

S. Landolt schrieb:
> Also ich verstehe weder vorbild noch prx.

Ja, ich verstehe mich selbst auch nicht.

Hans-Peter schrieb:
> Muss ich nur diese Einstellungen ändern?
> UCSR0A = (1<<RXEN0)|(1<<TXEN0);

Bloß nicht. Mach das wieder rückgängig. Das war ein Fall von geistiger 
Umnachtung.

von Hans-Peter (Gast)


Lesenswert?

leider versteh ich deine antwort nicht.
was muss ich nun tun?

von Bastian W. (jackfrost)


Lesenswert?

Versuch mal das, ohne den ADC ob du dann was gesendet bekommst :
1
#ifdef F_CPU
2
#undef F_CPU
3
#define F_CPU 16000000UL
4
#endif
5
6
#include <avr/io.h>
7
#include <inttypes.h>
8
#include <util/delay.h>
9
10
11
12
13
// Diese Beispiel zeigt die Anwendung des ADC eines ATmega169
14
// unter Verwendung der internen Referenzspannung von nominell 1,1V.
15
// Zur Anpassung an andere AVR und/oder andere Referenzspannungen
16
// siehe Erläuterungen in diesem Tutorial und im Datenblatt
17
18
/* ADC initialisieren */
19
void ADC_Init(void)
20
{
21
  // die Versorgungsspannung AVcc als Referenz wählen:
22
  //ADMUX = (1<<REFS0);
23
  // oder interne Referenzspannung als Referenz für den ADC wählen:
24
  ADMUX = (1<<REFS1) | (1<<REFS0);
25
26
  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
27
  // schon auf 0, also single conversion
28
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
29
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
30
31
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man 
32
liest
33
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu 
34
lassen" */
35
36
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung
37
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der 
38
Konvertierung warten
39
  }
40
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
41
     Wandlung nicht übernommen. */
42
  (void) ADCW;
43
}
44
45
/* ADC Einzelmessung */
46
uint16_t ADC_Read( uint8_t channel )
47
{
48
  // Kanal waehlen, ohne andere Bits zu beeinflußen
49
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
50
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
51
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung 
52
warten
53
  }
54
  return ADCW;                    // ADC auslesen und zurückgeben
55
}
56
57
58
void USART_Init( unsigned int baud )
59
  {
60
    /*Set baud rate*/
61
    UBRR0H = (unsigned char)(baud>>8);
62
    UBRR0L = (unsigned char)baud;
63
    /* Enable receiver and transmitter*/
64
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
65
    /* Set frame format: 8data, 2stop bit*/
66
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
67
  }
68
69
70
  void USART_Transmit( unsigned char data )
71
  {
72
    /* Wait for empty transmit buffer*/
73
    while
74
     ( !( UCSR0A & (1<<UDRE0)) );
75
    /* Put data into buffer, sends the data*/
76
    UDR0 = data;
77
  }
78
79
  void uart_puts( char *s )
80
  {
81
    /* while *s != '\0' so unequally "string-end characters (terminator) 
82
*/
83
    while (*s)
84
    {
85
      USART_Transmit(*s);
86
87
      s++;
88
    }
89
  }
90
91
92
void main(void)
93
{
94
  USART_Init(0x67);
95
  char String[16] = {"Test "};
96
  short ADCWert;
97
  //  ADC_Init();
98
  ADCWert = 123;
99
  while(1)
100
  {
101
    //ADCWert = ADC_Read(4);
102
103
    sprintf(String,"Test: %i\n", ADCWert);
104
    uart_puts(String);
105
    //USART_Transmit(S);
106
        _delay_ms(1000);
107
  }
108
109
}

Wenn dann was kommt stimmt mit deinem ADC Teil was nicht

von (prx) A. K. (prx)


Lesenswert?

Und wenn dann immer noch nichts kommt, stimmen entweder Hardware oder 
Controller-Takt nicht.

: Bearbeitet durch User
von Hans-Peter (Gast)


Lesenswert?

leider kein Erfolg :-(
Trotzdem Danke mal, ich werde glaub ne Nacht drüber schlafen...

von Bastian W. (jackfrost)


Lesenswert?

Hast du die CKDIV8 Fuse beim Atmega644 gelöscht ? Wenn nein dann läuft 
der ja nur mit 2 MHz

Gruß JackFrost

: Bearbeitet durch User
von Hans-Peter (Gast)


Lesenswert?

Hallo zusammen,

nun kommen Daten an der Seriellen Schnittstelle an.
Allerdings werden mir diese als nichtlesbare Zeichen dargestellt.
Ich habe die Taktrate wie beschrieben auf 2 MHz gesetzt.
den UART habe ich wie folgt initilaisiert:
USART_Init(0xc);
das bedeutet dass er nun mit 2 Mhz läuft.

weiter komme ich allerdings nicht.
Kann mir sonst noch jemand sagen was ich beachten sollte?

vielen Dank im voraus.

hier mein code:
#ifdef F_CPU
#undef F_CPU
#define F_CPU 2000000UL
#endif

#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>




// Diese Beispiel zeigt die Anwendung des ADC eines ATmega169
// unter Verwendung der internen Referenzspannung von nominell 1,1V.
// Zur Anpassung an andere AVR und/oder andere Referenzspannungen
// siehe Erläuterungen in diesem Tutorial und im Datenblatt

/* ADC initialisieren */
void ADC_Init(void)
{
  // die Versorgungsspannung AVcc als Referenz wählen:
  //ADMUX = (1<<REFS0);
  // oder interne Referenzspannung als Referenz für den ADC wählen:
  ADMUX = (1<<REFS1) | (1<<REFS0);

  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
  // schon auf 0, also single conversion
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu
lassen" */

  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der 
Konvertierung warten
  }
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */
  (void) ADCW;
}

/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung 
warten
  }
  return ADCW;                    // ADC auslesen und zurückgeben
}


void USART_Init( unsigned int baud )
  {
    /*Set baud rate*/
    UBRR0H = (unsigned char)(baud>>8);
    UBRR0L = (unsigned char)baud;
    /* Enable receiver and transmitter*/
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
    /* Set frame format: 8data, 2stop bit*/
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
  }


  void USART_Transmit( unsigned char data )
  {
    /* Wait for empty transmit buffer*/
    while
     ( !( UCSR0A & (1<<UDRE0)) );
    /* Put data into buffer, sends the data*/
    UDR0 = data;
  }

  void uart_puts( char *s )
  {
    /* while *s != '\0' so unequally "string-end characters (terminator)
*/
    while (*s)
    {
      USART_Transmit(*s);

      s++;
    }
  }


void main(void)
{
  USART_Init(0xc);
  char String[16] = {"Test "};
  short ADCWert;
  //  ADC_Init();
  ADCWert = 123;
  while(1)
  {
    //ADCWert = ADC_Read(4);

    sprintf(String,"Test: %i\n", ADCWert);
    uart_puts(String);
    //USART_Transmit(S);
        _delay_ms(1000);
  }

}

von Bastian W. (jackfrost)


Lesenswert?

Poste mal die Fuse Einstellung von dem Atmega

von Hans-Peter (Gast)


Lesenswert?

0b10011001
ich hoffe das das soweit OK ist.
Oder welche Fuses meinst du?

von Bastian W. (jackfrost)


Lesenswert?

Die Fuses vom Controller, wo du die Taktquelle, Brownout usw einstellst.

https://www.mikrocontroller.net/articles/AVR_Fuses

Hast du an den was geändert ? Mit was programmierst du ? Was für einen 
ISP Programmer hast du ?

Gruß JackFrost

von Hans-Peter (Gast)


Lesenswert?

ich programmiere mit Eclipse, linux und USB Programmer AVR MK2

von Hans-Peter (Gast)


Lesenswert?

hab ein Fehler gemacht.
Das sind die Hfuses:0b10011001
und das sind die Lfuses: 0b1100010

von Bastian W. (jackfrost)


Lesenswert?

Nach dem http://www.engbedded.com/fusecalc/ läuft der Atmega644 mit dem 
internen RC Oszillator und ohne die CKDIV8 Fuse. Damit solltest du den 
Wert für die Baudrate mit 8 MHz berechnen.

Gruß JackFrost

von Fred R. (fredylich)


Lesenswert?

Hallo,

von C Programmierung der ATMEGA - Controller habe ich mich schon vor ein 
paar Jahren verabschiedet.
Somit nur ein Hinweis: Unterschied der 32 hat nur einen Hardware Uart 
der 644 zwei. Somit ist es zwingend nötig den Controller zu sagen 
welcher frei gegeben wird.
Mit Bascom sehr einfach im Header einzustellen.
Beispiel:
$baud = 19200     ‚ ist 1
$baud1 = 19200   ‚ ist 2

Was auch immer wieder missachtet wird der 644 kann mit 20 M getaktet 
werden aber nur stabil mit Betriebsspannung 3,3 Volt.
Kommen „wüste“ Zeichen zum Terminal an,ist es erst mal ein Zeichen, UART 
hat Verbindung aufgebaut nur die Baudrate ist nicht synchron 
eingestellt.

Mit freundlichen Grüßen

von Wolfsente (Gast)


Lesenswert?

Fred R. schrieb:
> Was auch immer wieder missachtet wird der 644 kann mit 20 M getaktet
> werden aber nur stabil mit Betriebsspannung 3,3 Volt.

Datenblatt sagt was anderes.

– ATmega644: 0 - 10MHz @ 2.7V - 5.5V, 0 - 20MHz @ 4.5V - 5.5V

von Thomas Z. (thozei)


Lesenswert?

Fred R. schrieb:
> der 644 zwei

Der 644 hat EINEN UART.
Der 644P hat zwei.

--Thomas

von fredylich (Gast)


Lesenswert?

Wolfsente schrieb:
> Fred R. schrieb:
>> Was auch immer wieder missachtet wird der 644 kann mit 20 M getaktet
>> werden aber nur stabil mit Betriebsspannung 3,3 Volt.
>
> Datenblatt sagt was anderes.
>
> – ATmega644: 0 - 10MHz @ 2.7V - 5.5V, 0 - 20MHz @ 4.5V - 5.5V

Hallo,

ja die Wortwahl „missachtet“ ist wohl falsch gewählt.
Kenne Datenblatt und diese Info hat mich auch viele Nerven und Zeit 
geraubt. Im Nachhinein sieht man den Widerspruch. Schon die Bezeichnung 
von 0 bis xx ist doch schon sehr missverständlich. Mit 0 Takt wird wohl 
nichts mehr funktionieren.
Hatte das gleiche Problem mit Uart Controller und Terminal. Haben 
einfach keine synchrone Baudrate bekommen. Obwohl das Programm „sauber“ 
abgearbeitet wurde. Nur durch Zufall den Controller mit 3,3 Volt 
betrieben und siehe da alles bestens. Als nächsten Versuch den Takt auf 
8 M eingestellt. Nun ist es Wurst ob 3,3 Volt oder 5,0 Volt, es 
funktionier halt. Ich nenne es mal in meiner Rhetorik “ Der Controller 
war übertaktet“
Zu meiner Entschuldigung für Antwort(ist ja sehr wichtig für einige in 
diesem Forum) bin nur ein Amateur und sehr ausdauernd bei Fehlersuche. 
Also „basteln“ und probieren hat mehr Erfolg, als nur die Antwort zu 
bekommen „siehe Datenblatt“. Die meiste machen es wie auch ich.
Somit wollte ich nur meine praktischen Erfahrungen vermitteln.

MfG

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.