Forum: Mikrocontroller und Digitale Elektronik UART Probleme mit AT90CAN128


von Simon (Gast)


Lesenswert?

Hallo zusammen,
ich habe ein STK501 mit einem AT90Can128 Controller.
Zur inbetriebnahme meines UARTS Habe ich mal das Tutorial genutzt, 
möchte beim drücken einer Taste auf dem Board das Zeichen x an mein 
Terminalprogramm des PC`s senden.
Habe einen 4 MHz Quarz und auch die Fuse Bits dementsprechend 
eingestellt. Lieder bekomme ich beim drücken der Taste immer nur Müll am 
Terminalprogramm raus, wie bsp. zwei Zeilen voller yyyyyyy
Woran kann das noch liegen?? Mache schon den ganzen Tag daran rum und 
bekomme es einfach nicht zum rennen...
Bin verzweifelt....
Hier ist der Code:

#include <stdint.h>
#include <avr/io.h>

#define F_CPU 3686400     /* Quarz mit 3.6864 Mhz */

int main (void)
{

//Port A und B initialisieren um Taster und LED`s zu steuern.
DDRB= 0xff;    //Ganzen Port B als Ausgang setzten
DDRA= 0x00;    //Ganzen Port A als Eingang setzten
PORTA= 0xff;  //Pull ab Widerstände für gesamten Port A aktiv



//USART Contollregister initialisieren siehe S.197 Datenblatt
                     /* USART-Init 19200 Baud bei 4MHz für AT90CAN128 */
UBRR1H  = 0;                           // Highbyte ist 0
UBRR1L  = 12;                // Lowbyte ist 12 ( dezimal ) ergibt 19,2k 
bei 4Mhz Clocktakt
UCSR1B |= ( 1 << TXEN1 );    // UART TX einschalten (Sendebereit machen)
UCSR1C |= ( 0 << UMSEL1 )|(0<<UPM1)|(0<<USBS1)|( 3<<UCSZ1 );  // 
Asynchron modus Character Size 8-bit,2 Stopbit, kein Parity


  while (1)
  {

  if (!(PINA & (1<<PA0)) )  //Wenn PIN 0 von Port A 0 ist dann....
    {


      // setzte Pin4 an Port B (LED)
      PORTB |= (1<<PB4);
    while (!(UCSR1A & (1<<UDRE1)))  /* warten bis Senden moeglich 
solange UDRE1 flag 0 ist */
       {
    asm volatile ("nop");            }

      UDR1 = 'x';   /* schreibt das Zeichen x auf die Schnittstelle */
    }

      else
      {
        PORTB &= ~(1<<PB4);
      }

  }
}

Kann mir da irgendwer helfen? Wäre wirklich froh darüber. Viel kann es 
nicht sein, da wenn ich die Taste drücke empfange ich ja was, leider 
aber nur scheiss....
Vielen Dank schon mal

von Jörg X. (Gast)


Lesenswert?

"#define F_CPU 3686400 " -- das stimmt zwar nicht, aber wenn du das 
korrigierst, kannst du es auch benutzen (s.u.)

die Schleifen, in denen du auf ein bestimmtes Bit wartest, kannst du 
leer lassen:
1
while( !(UCSR1A & (1<<UDRE1)))
2
    ;
3
#ifndef F_CPU
4
#    define F_CPU 4000000UL //korrekten Wert eintragen!
5
#endif
6
#define BAUD((rate)) (F_CPU/(16*rate) -1)
7
UBRR1H = BAUD(19200)>>8;
8
UBRR1L = BAUD(19200);
9
// ... (0<<x) hat keine Auswirkungen
10
// 3<<UCSZ1 ist definitiv falsch, 
11
// UCSR1C |= ( 3<<UCSZ0 ); // 'korrigiert'
12
UCSR1C |= ((1<<UCSZ1)|(1<<UCSZ0)); // korrekt und besser lesbar ;)
Für '8N1' brauchst du eigentlich nichts extra einzustellen, das sind die 
Defaults nach dem Reset ("Initial Value" im Datenblatt)

hth. Jörg

von Simon (Gast)


Lesenswert?

Hallo Jörg,

vielen dank für deine Antwort!
Leider haben die Änderungen auch nicht den gewünschten Erfolg gebracht, 
ich habe immer noch komische Zeichen im Terminalprgram!
Mir ist auch nicht ganz klar, warum ich die Baudrate über deine Rechnung 
angeben soll und nicht einfach über UBRR1 = 12;
Das müsste doch normal bei 4Mhz 19200 Baud ergeben!?!?
Wo könnte der Fehler jetzt noch liegen? Das ist echt zum verzweifeln, 
kann doch so schwer nicht sein!
Danke
Gruß
Simon

von tex (Gast)


Lesenswert?

hast Du ggf noch den 1:8 Clock-Teiler gesetzt? Der ist von Hause aus 
immer aktiv.

von Simon (Gast)


Lesenswert?

Mhh gute Frage,

jedenfalls habe ich Ihn nicht bewust ausgeschaltet. Wie schalte ich den 
Timer aus? Ist das ein Register? Oder Muss man das im M-File machen?
Gruß
Simon

von tex (Gast)


Lesenswert?

... ich klicke einfach das Häkchen raus ... Umpf. Ist ein Fuse-Bit!

von _CH_ (Gast)


Lesenswert?

Hallo,

>hast Du ggf noch den 1:8 Clock-Teiler gesetzt? Der ist von Hause aus
>immer aktiv
in diese "Falle" bin ich auch schon mal getappt.
Warum hat der eigentlich den 1:8 standardmäßig aktiviert - macht ja 
nicht wirklich Sinn, oder?

Gruß,
Christian

von tex (Gast)


Lesenswert?

Kompatibilät zu 103 glaube ich

von Simon (Gast)


Lesenswert?

Ist der Teiler aktiviert wenn das Häkchen gesetzt ist oder wenn es 
gelöscht ist?? Ist immer so en Scheiss mit den Null aktiven Fuses...???

von tex (Gast)


Lesenswert?

wenn Du das AVR-Studio benutzt, ist der Teiler aktiv, wenn das Häkchen 
gesetzt ist

von Simon (Gast)


Lesenswert?

Funktioniert trotzdem nicht, so ein Scheiss!!
Ich hätte nicht gedacht das es so ein Problem ist ein Zeichen auf eiem 
UART auszugeben :-(

von _CH_ (Gast)


Lesenswert?

der Controller läuft aber schon mit externem Quarz und nicht mir dem 
standardmäßigem RC-Oszillator oder? (Fuses!)

von _CH_ (Gast)


Lesenswert?

sorry, wer lesen kann ist im Vorteil. Hast du ja gemacht.

von tex (Gast)


Lesenswert?

Ist es auch nicht.
Vielleicht suchst Du das Problem an der falschen Stelle
ggf ein daueraktiver Watchdog (fuse gesetzt) ohne WD-Routine
ein defekter XX232, oder die Cmos version mit Elkos statt keramischen 
Kondensatoren, oder ein nicht Cmos-XX232 mit Cmos-Beschaltung ...
hast Du z.B. mal die echte Frequenz an deinem CAN128 gemessen? Du kannst 
dazu den Takt an einen Port (PD7??) weiterleiten.

von Simon (Gast)


Lesenswert?

Ja hab ich gemacht, hat genau 3,7 Mhz, das passt alles...
Ist ein externer 4Mhz Quarz.
Was mich auch wundert ist das nach dem beschreiben des
UCSR1C |= (( 1<<UCSZ11 )|(1<<UCSZ10));
Registers werden auch die UBRR1H flags 9 und 10 beschrieben?!?!
Ich setzte sie einfach in der nächsten Zeile mit
UBRR1H  = 0;
wieder zurück, sonst passt ja meine Datenrate mit 19.2k bei 4 MHz nicht, 
dazu muss ich ja nur UBRR1L mit 12 beschreiben siehe:
UBRR1L  = 12;

Irgendwas stimmt mit dem Takt nicht oder mein Code hat einen morts Bug..

Please help me!
Danke

von tex (Gast)


Lesenswert?

nein es ist PC7

<< Ist immer so en Scheiss mit den Null aktiven Fuses...??? >>

Dieses Statement macht mich mistrauisch. Woher weisst Du, dass Du 
überhaupt die Richtige Einstellung für die Clock hast?

von tex (Gast)


Lesenswert?

3,7 Mhz? Was genau soll da noch aus der seriellen Schnittstelle 
rauskommen?

von Jörg X. (Gast)


Lesenswert?

- Warum ich die Rechnung in den Code schreibe? -- Warum soll ich denn 
den Registerwert ausrechen, wenn der Compiler das doch selber kann (das 
muss der  nicht  AVR ausrechnen)
- Die CKDIV8 -Fuse ist von Haus ausprogrammiert, damit der µC bei jeder 
erlaubten KOmbination aus Spannung und Takt losläuft, sonst könnte man 
den evtl. nicht ISP-Programmieren

- Bist du sicher, dass der AVR mit 4Mhz läuft? (Woher kommen die: 
STK-500, Quarz, internerRC-Oszillator...)
- Benutzt du die richtige Serielle schnittstelle?

hth. Jörg

kannst du mal das aktulle Programm posten ? (möglichst in [c ] [/c 
]-Tags(ohne Leerzeichen ;) ))

von Johannes M. (johnny-m)


Lesenswert?

> ...werden auch die UBRR1H flags 9 und 10 beschrieben?!?!
Wer?

von tex (Gast)


Lesenswert?

probier mal UBRR1L  = 11 !

von _CH_ (Gast)


Lesenswert?

>3,7 MHz... das passt alles... Ist ein externer 4Mhz Quarz.
widerspricht sich meiner Meinung nach, lässt aber auf 3.6864 Mhz Quaz 
schließen...

von Simon (Gast)


Lesenswert?

Hallo nochmal, ja wie gesagt ich verwende ein STK501 Board. Auf dem STK 
500 also dem unteren Teil ist ein 4Mhz Quarz gesteckt. Wenn ich am Pin 7 
messe, messe ich 3,7 Mhz.
Externen Clock habe ich über die Fuses auf
Ext. Cristal Osc. 3-8 Mhz Startuptime 65ms gestellt, den Teilerfaktor 
austeschaltet.
Der aktuelle Code sieht so aus:

#include <stdint.h>
#include <avr/io.h>

#ifndef F_CPU
#define F_CPU 4000000UL     /* Quarz mit 3.6864 Mhz */
#endif

int main (void)
{

//Port A und B initialisieren um Taster und LED`s zu steuern.
DDRB= 0xff;    //Ganzen Port B als Ausgang setzten
DDRA= 0x00;  //Ganzen Port A als Eingang setzten
PORTA= 0xff;  //Pull ab Widerstände für gesamten Port A aktiv

//USART Contollregister initialisieren siehe S.197 Datenblatt

/* USART-Init 19200 Baud bei 4MHz für AT90CAN128 */


UBRR1L  = 12;                         // Lowbyte ist 12 ( dezimal ) 
ergibt 19,2k bei 4Mhz Clocktakt
UCSR1B |=  (1 << TXEN1);    // UART TX einschalten (Sendebereit machen)
UCSR1C |= (( 1<<UCSZ11 )|(1<<UCSZ10));  // Asynchron modus Character 
Size 8-bit,1 Stopbit, kein Parity
UBRR1H  = 0;     //UBRR1H auf 0 zurücksetzten

  while (1)
  {

    if (!(PINA & (1<<PA0)) )  //Wenn PIN 0 von Port A 0 ist dann....
    {

           PORTB |= (1<<PB4);    // setzte Pin4 an Port B (LED)


    while (!(UCSR1A & (1<<UDRE1)));  /* warten bis Senden moeglich

              UDR1 = 'x';


    }

      else
      {
        PORTB &= ~(1<<PB4);
      }


  }
}


Liegts am Code, am Quarz, an den Fuses?!?!

Danke für eure Hilfe!!!!!

von tex (Gast)


Lesenswert?

Eben, und dafür muss UBRR1L  = 11 sein.

von Jörg X. (Gast)


Lesenswert?

3,7MHz -- Ist der Takt vom stk-500, jaa auch dem must du wohl sagen, 
dass du einen Quarz benutzen willst, und NEIN 3,7 Mhz sind nicht ok, 
wenn man 4 haben will ;) .
Die Sache mit den UBRRnH Bits steht unter "Known Issues" (dt. bekannte 
Fehler) in der Doku des SIMULATORs! (AVR-Studio-help), hat also keine 
Auswirkungen auf den AVR.
In der AVR-Studio Software heißt Haken: Programmierte (aktive) Fuse, 
igorier einfach mal, ob das jetzt 0 oder 1 heißt.

von Simon (Gast)


Lesenswert?

Also was stimmt jetzt??
Soll ich
#define F_CPU 4000000UL
schreiben oder
#define F_CPU 3700000UL
Wie soll ich dem dem sagen das ich einen 4 Mhz Quarz gesteckt 
habe??Zumindest steht das auf dem Quarzgehäuse.
Das Problem liegt sicher an dem Takt, ich denke der Code wäre sonst ok 
oder?

von Simon (Gast)


Lesenswert?

Jipiiiiiii!!!!!!
Es geht fast, ich hab jetzt das
UBRR1L mit 11 beschrieben und jetzt kommt mein Zeichen an!!!!!
Leider aber bestimmt 80 mal wenn ich die Taste drücke.
Wie bekomme ich das jetzt hin, das es nur einmal ankommt???

Hey voll cool, vielen Dank für euer aller Hilfe, echt Top, ihr habt mir 
einen riesen Gefallen getan. Bin gerade an meiner Diplomarbeit und dreh 
noch durch mit dem UART...
Vielleicht gibts jetzt noch nen Trick das ich nur ein Zeichen bekomme!!
Vielen Dank

Gruß
Simon

von Johannes M. (johnny-m)


Lesenswert?

Crystal Oscillator ist nicht gleich Crystal! Außerdem musst Du afaik 
einen Jumper umstecken, um einen Quarz im STK500 nutzen zu können.

von Johannes M. (johnny-m)


Lesenswert?

Simon wrote:
> Vielleicht gibts jetzt noch nen Trick das ich nur ein Zeichen bekomme!!
> Vielen Dank
Der Trick heißt "eindeutige Tasterzustandsauswertung" bzw. 
"Tastenentprellung". Da gibts hier tausende Threads zu (gib mal 
"Entprellung" in die Suche ein).

von Jörg X. (Gast)


Lesenswert?

such nach "enprellung", in der Codesammlung und in den AVR-tutorials

bei dem #define F_CPU gehört DIE Frequenz hin, mit der der AVR 
tatsächlich läuft, natürlich ;)

hth. Jörg

von _CH_ (Gast)


Lesenswert?

>Vielleicht gibts jetzt noch nen Trick das ich nur ein Zeichen bekomme!!
den Taster kürzer drücken

von Simon (Gast)


Lesenswert?

Tip Top, werd mal schauen ob ich das mit der entprellten Taste 
hinbekomme. Man kann sich kaum vorstellen das die kleinen Taster so 
prellen können :-)

von Johannes M. (johnny-m)


Lesenswert?

Das hat in Deinem Fall primär gar nichts mit dem Prellen zu tun, sondern 
mit Deiner Abfrage. Du fragst nur ab, ob die Taste gedrückt ist. Und 
wenn das der Fall ist, dann wird gesendet, bis die Taste wieder 
losgelassen wurde. Und selbst bei einem "schnellen" Drücken ist der 
Kontakt mindestens einige zig ms geschlossen. Das reicht auf jeden Fall 
für mehrere Zeichen aus. Deshalb auch der Hinweis auf "eindeutige 
Tasterzustandsauswertung". Und dazu genügt es i.d.R. schon, bei der 
Abfrage des Tasterzustandes den jeweils aktuellen Zustand zu speichern 
und beim nächsten mal die Aktion nur dann durchzuführen, wenn der Taster 
gedrückt ist, aber im vorherigen Zyklus nicht gedrückt war (also beim 
letzten Mal 1 und jetzt 0). Alle anderen Zustände werden ignoriert.

von Simon (Gast)


Lesenswert?

Hey Jonny
Stimmt, da hast Du auch wieder recht.
Mal sehen ob eine solche Abfrage hin bekommen, hab eben auch noch nicht 
wirklich viel µC programmiert.
Falls Du eine solche Abfrage gerade aus dem Ärmel schütteln kannst, 
kannst Du sie gerne posten :-)

von Johannes M. (johnny-m)


Lesenswert?

Hab doch schon alles beschrieben. Du musst nur jedes Mal, wenn Du den 
Taster abfragst, den Zustand des Tasters speichern (also ne 1 für "nicht 
gedrückt" und ne 0 für "gedrückt"). Und senden tust Du nur dann, wenn 
der gespeicherte alte Zustand (von der jeweils vorhergehenden Abfrage) 1 
und der aktuelle 0 ist. Das geht z.B. mit einer UND-Verknüpfung des 
alten Zustandes mit dem invertierten neuen Zustand (1 & !0 == 1, alle 
anderen Kombinationen ergeben 0). Für das Speichern und Vergleichen 
brauchste halt eine Variable. Der Rest ist basic (damit meine ich 
NICHT die Programmiersprache!)

von Simon (Gast)


Lesenswert?

Funktioniert bestens :-)
Danke

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.