Forum: Mikrocontroller und Digitale Elektronik UART zwischen 2 atmega16


von Daniel D. (dannpower)


Lesenswert?

Moin,
ich versuche eine LED, die an dem einen µC angeschlossen, durch den 
anderen µC zu steuern. Problem ist, dass er anscheinend zwar sendet aber 
der andere µC nichts empfängt. Vielleicht kann mir ja jemand von euch 
helfen.

Die µC sind so verbunden:
TX----------RX

Code:
Sender:

#define F_CPU 1000000UL
#include <avr/io.h>

int main(void)
{
//Buttons und LED definieren
      DDRD |= (1<< PD6);
      DDRB &= ~(1<<PINB0);
      PORTB |=(1<<PINB0);

      int UBRR_Value = 25;
      UBRRH = (unsigned char) (UBRR_Value>>8);
      UBRRL = (unsigned char) UBRR_Value;

      UCSRB |= (1<<TXEN);
      UCSRC |= (1<<USBS) | (3 << UCSZ0);


  /* Replace with your application code */


  while (1) {

  if (!(PINB & (1<<PINB0))){ // wenn button gedrückt wird

    while(! (UCSRA & (1<<UDRE))); //warte auf senden
    UDR=0b11110000; //sende
    PORTD ^=(1<<PIND6); // toggle led

  }
  }
}

Empfänger:

#define F_CPU 1000000UL
#include <avr/io.h>



int main(void)
{
    DDRB |= (1<<PB0);
      int UBRR_Value = 25; //baud = 2400 |||| UBBR = ( 1,000,000 / 16 * 
2400) -1 = 25.0416667 = 25
      UBRRH = (unsigned char) (UBRR_Value>>8);
      UBRRL = (unsigned char) UBRR_Value;


      UCSRB |= (1<<RXEN);
      UCSRC |= (1<<USBS) | (3 << UCSZ0);
    unsigned char receiveData;
    while(1)
    {
      while(!(UCSRA & (1<<RXC))); //Warten
      receiveData=UDR; //emfange byte

      if (receiveData == 0b11110000) PORTD^=(1<<PD6); // wenn byte = 
true dann toggle LED
    }
  }

von Stefan F. (Gast)


Lesenswert?

Mach mal eine LED an die serielle Verbindung. Flackert sie?

Hast du GND von beiden µC miteinander verbunden?

Hast du bei beiden µC die CLK_DIV8 Fuse und die anderen Fuses zur Wahl 
der Taktquelle gleich eingestellt?

Verwendest du einen R/C Oszillator? Das wäre keine gute Idee, die sind 
zu ungenau.

von holger (Gast)


Lesenswert?

Schalte PD6 doch mal auf Ausgang;)

von Daniel D. (dannpower)


Lesenswert?

Hab ich gemacht, funktioniert irgendwie trotzdem nicht

Danke erstmal für die schnelle Antwort.
1.Die LED flackert sobald ich den Button betätige.
2.Ja die beiden µC sind miteinander auf GND verbunden
3.Ich bin noch Anfänger und weiß nicht genau was du mit CLK_DIV8 Fuse 
meinst.
4.Nein benutze ich nicht.

: Bearbeitet durch User
von Daniel D. (dannpower)


Lesenswert?

Also ich hab jetzt etwas am Code geändert und zwar:

    while(!(UCSRA & (1<<RXC))); //Warten
      receiveData=UDR; //emfange byte
      switch(receiveData)
      {
        case 0b11110000:
        PORTD &= ~(1<<PD6);

        break;
        default:
        PORTD |= (1<<PD6);
        zustand=1;
        break;
      }
      if (zustand==1)
      {
        _delay_ms(1000);
        zustand=0;
        PORTD &= ~(1<<PD6);
      }

Jetzt empfängt er zwar etwas, aber es ist noch nicht das richtige.
Die LED geht durch die default case an und nach 1 sec wieder aus, wie 
oben im Programm beschrieben.

von S. Landolt (Gast)


Lesenswert?

>  UCSRC |= (1<<USBS) | (3 << UCSZ0);
Diese Zeile ist falsch, es fehlt das URSEL. Und ob man der Veroderung 
trauen darf? Aus dem Datenblatt:
"Doing a read access to the UBRRH or the UCSRC Register is a more 
complex operation. However, in most applications, it is rarely necessary 
to read any of these registers."

Vermutlich ist es nicht die Fehlerursache, aber ich würde es trotzdem 
korrigieren.

von Stefan F. (Gast)


Lesenswert?

Wenn du nicht weisst, was eine Fuse ist, dann verwendest du die R/C 
Oszillatoren. Und die sind für UART Kommunikation nicht genau genug.

von B.eng (Gast)


Lesenswert?

Mit nicht genau genug wäre ich vorsichtig. Es handelt sich um 2400 baud. 
Das kriegt man auch noch hin mit bit-banging. Ich denke eher, dass die 
Clockselection nicht die gleiche ist auf beiden Controllern. Clkdiv8 
wurde ja schon erwähnt.

von S. Landolt (Gast)


Lesenswert?

> Mit nicht genau genug wäre ich vorsichtig. Es handelt sich um 2400 baud.
Der alte Irrtum; bei einem relativen Fehler ist die absolute 
Geschwindigkeit egal.

von Flip B. (frickelfreak)


Lesenswert?

S. Landolt schrieb:
> bei einem relativen Fehler ist...

Fehler ist jedoch in etwa relativ zum takt und nicht zur baudrate. Bitte 
nachdenken. Die margen Steigen mit sinkender Baudrate.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Vielleicht haben Sie mich falsch verstanden: wenn ich um 10 % daneben 
liege, dann gilt das für 2400 Bd ebenso wie für 115.2 kBd.

von B.eng (Gast)


Lesenswert?

Das mit dem Fehler will ich ja gar nicht abstreiten. Einzelne bytes 
müssten aber trotzdem lesbar bleiben. Das nicht alles passt ist klar. 
Taktunterschied bedeutet, das beide beide Controller ausseinander 
laufen. Sie müssten sich bei 2400 baud aber irgendwann auch wieder 
treffen. Und dann stimmen die bytes für eine gewisse Zeit. Mit höherer 
Baudraten sinkt die Zeit, in der beide "synchron" sind.

von S. Landolt (Gast)


Lesenswert?

Das sehe ich anders: der interne RC-Oszillator schwankt im wesentlichen 
in Abhängigkeit von Betriebsspannung und Temperatur; beides wird sich im 
µs-Bereich nur wenig ändern.
Allerdings stimme ich mit Ihnen insofern überein, dass ich ebenfalls den 
Fehler nicht an dieser Stelle vermute.

von Walter S. (avatar)


Lesenswert?

B.eng schrieb:
> Und dann stimmen die bytes für eine gewisse Zeit.

ist nicht richtig, es handelt sich um eine asynchrone Übertragung, dabei 
wird bei jedem Startbit neu synchronsiert

von Stefan F. (Gast)


Lesenswert?

Die serielle Übertragung versagt, sobals ein Bit im falschen Moment 
abgetastet wird.

Die Abtastung beginnt mit der Mitte des Startbits. Dann kommen in der 
Regel 8 Datenbits und ein Stopbit. Das sind 9 Abtastungen nach dem 
Startbit.

Wenn die beiden Kommunikationspartner in ihrer Taktfrequenz um mehr als 
10% auseinander liegen, tastet der Empfänger mindestens das Stopbit 
(oder noch mehr Bits) zum falschen Zeitpunkt ab. Je höher die 
Abweichung, umso mehr Bits werden verfälscht.

Der R/C Oszillator hat typischerweise weniger als 10% Abweichung von der 
Soll-Frequenz, aber bei zwei R/C Oszillatoren sind bis zu 20% Abweichung 
vorstellbar, wenn der eine zu schnell läuft und der andere zu langsam.

Abgesehen davon, hatte ich auch mal einen Chip erwischt, der mehr als 
10% Abweichung unter den im Datenblatt angegebenen Bedingungen hatte. 
Der nächste Chip aus der selben Tüte war viel besser. Sowas kommt vor.

Die Baudrate spielt dabei keine Rolle. Wenn die Taktfrequenz des µC um 
10% abweicht, dann weicht auch die Baudrate um 10% ab. Denn die wird von 
der Taktfrequenz abgeleitet.

Ich erinnere daran:
> int UBRR_Value = 25; //baud = 2400
> // UBBR = ( 1,000,000 / 16 * 2400) -1 = 25.0416667 = 25

Du kannst die tatsächliche Taktfrequenz messen und dann die "1,000,000" 
in deiner Berechnung dementsprechend anpassen. Oder du kalibrierst die 
R/C Oszillatoren.

von Mein grosses V. (vorbild)


Lesenswert?

Stefan U. schrieb:
> Der R/C Oszillator hat typischerweise weniger als 10% Abweichung von der
> Soll-Frequenz, aber bei zwei R/C Oszillatoren sind bis zu 20% Abweichung
> vorstellbar, wenn der eine zu schnell läuft und der andere zu langsam.

Ja, aber nur wenn der eine bei 1,8V in der Kühltruhe und der andere bei 
5V im Backofen betrieben wird.

von Stefan F. (Gast)


Lesenswert?

Nein, dann ist die Abweichung mit Sicherheit noch viel größer.

Laut Datenblatt darf die Taktfrequenz für 3V bei 25°C bis zu + und - 10% 
abweichen. Macht zusammen bis zu 20%.

Wie gesagt habe ich in der Praxis auch schonmal mehr als 10% Abweichung 
erlebt, bei 3.3V und ungefähr 25°C. Was dem Datenblatt auch nicht 
widerspricht.

von Mein grosses V. (vorbild)


Lesenswert?

Stefan U. schrieb:
> Laut Datenblatt darf die Taktfrequenz für 3V bei 25°C bis zu + und - 10%
> abweichen. Macht zusammen bis zu 20%.

Blödsinn.

Calibrated Internal RC Oscillator

The Calibrated Internal RC Oscillator provides a fixed 1.0, 2.0, 4.0, or 
8.0 MHz clock. All frequencies are nominal values at 5V and 25⋅C.
[...]
At 5V, 25⋅C and 1.0, 2.0, 4.0 or 8.0 MHz Oscillator frequency selected, 
this calibration gives a frequency within ± 3% of the nominal frequency.

Stefan U. schrieb:
> Wie gesagt habe ich in der Praxis auch schonmal mehr als 10% Abweichung
> erlebt, bei 3.3V und ungefähr 25°C.

Ja, ja.

von Georg G. (df2au)


Lesenswert?

Daniel D. schrieb:
> case 0b11110000:
>         PORTD &= ~(1<<PD6);

Wenn das "richtige" Zeichen kommt, machst du die LED aus. Sollte sie 
nicht den Zustand wechseln?

von S. Landolt (Gast)


Lesenswert?

Vorab: mir ist klar, dass eine Stichprobe von 18 Stück nicht besonders 
aussagekräftig ist; mir ist auch klar, dass es Daniel D. in seinem 
speziellen Fall nicht unbedingt weiterhilft; um sicher zu sein, müsste 
er messen oder auf Quarz umstellen.

Trotzdem, da es mich interessierte, eben gemessen, ATmega16A-PU, der 
interne 1 MHz-RC-Oszillator:
(1339):
125.07, 124.26, 125.20, 125.56
(1340):
126.60, 126.80, 126.33, 126.16, 126.26, 126.72, 126.35,
126.55, 126.87, 126.75, 126.24, 125.81, 126.06, 126.75

jeweils *8 in kHz.

Vorausgesetzt, Daniels Controller stammen aus der gleichen Charge, 
vermute ich nach wie vor sein Problem an anderer Stelle.

von Mein grosses V. (vorbild)


Lesenswert?

S. Landolt schrieb:
> Vorausgesetzt, Daniels Controller stammen aus der gleichen Charge,
> vermute ich nach wie vor sein Problem an anderer Stelle.

Ja. Und zwar genau hier:

S. Landolt schrieb:
>>  UCSRC |= (1<<USBS) | (3 << UCSZ0);

Solange das URSEL-Bit nicht gesetzt ist, landet dieser Wert im 
UBRRH-Register.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

>> Laut Datenblatt darf die Taktfrequenz für 3V bei 25°C bis zu + und - 10%
>> abweichen. Macht zusammen bis zu 20%.

> Blödsinn.

Ich habe das dem Datenblatt des ATmega328 entnommen. Siehe Anhang.

In welchem Datenblatt hast diese völlig anderen Angaben gefunden?

von Stefan F. (Gast)


Lesenswert?

>> if (receiveData == 0b11110000) PORTD^=(1<<PD6);

> Wenn das "richtige" Zeichen kommt, machst du die LED aus.

Nein. Schau richtig hin und zittiere richtig.

von Georg G. (df2au)


Lesenswert?

Stefan U. schrieb:
> zittiere richtig.

Ich zittere nicht. Sieh dir den Code von gestern, 18:30 an, den der TO 
geschrieben hat.

von Mein grosses V. (vorbild)


Lesenswert?

Stefan U. schrieb:
> In welchem Datenblatt hast diese völlig anderen Angaben gefunden?

Atmega16. Um den geht es hier doch.

Stefan U. schrieb:
> Ich habe das dem Datenblatt des ATmega328 entnommen

Das ist einer der neueren Controller. Der Atmega16 gehört noch zur alten 
Generation, wie auch der Atmega8.

Die alten Controller haben mehrere Oszillatoren für die internen 
Frequenzen, die mit den CKSEL0..3 eingestellt werden. Sie haben keine 
CKDIV8-Fuse und auch kein Clock Prescale Register(CLKPR).
Die Oscillator Accuracy liegt bei 3%.

Die 10% der Atmega48..328, wie auch der 164..1284, gelten für den 
gesamten Spannungs- und Temperaturbereich(1,8 - 5,5V; -40 - 85°C).

Bei der werkskalibrierten Einstellung bei 3V/25°C beträgt die 
Abweichung, wie bei der User-Kalibrierung, 1%. Die User-Kalibrierung 
lässt sich natürlich auch unter jeder anderen Betriebsbedingung 
durchführen. Deswegen beträgt diese über den gesamten Bereich 1%.

Das lässt sich alles sehr schön nachprüfen, indem man den Timer2 mit 
Uhrenquarz im CTC laufen lässt und den entsprechenden Ausgang auf den 
ICP des Timer1 gibt und dann z.B. eine quarzgetaktete Sekunde schältet 
und sich dann ansieht, was der Timer1 mit internem Oszillator dabei 
rausbekommt. Verändert man dann mit Föhn, Kältespray und LNT die 
Bedingungen, erkennt man schnell die Tendenzen, die bei allen 
Controllern gleich sind.

DÜ per UART funktioniert deswegen auch bei den 328ern und Co. 
grundsätzlich bei 3V/25°C/1%. Beim 16er und Co. nur zufällig, da die 
Toleranz bei 5V/25°C 3% beträgt, was für DÜ grundsätzlich zu hoch ist.

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.