Forum: Mikrocontroller und Digitale Elektronik UART von Mega32 auf Mega168 anpassen


von Martin (Gast)


Lesenswert?

Hallo,

ich bin gerade dabei einen C-Code für den Atmega32 auf einen Atmega168A 
anzupassen.

Ich habe die Register und Bitnamen dem Datenblatt angepasst, der 
Compiler gibt keine Warnung und keinen Fehler zurück. Ich verwende genau 
wie beim Mega32 einen externen 8MHz Quarz.

Nun funktioniert meine UART Übertragung nicht. Mit dem Mega32 
funktioniert es prima. Ich nutze das Pollin-Evaluationsboard Version 
2.0.1 und gehe davon aus, dass die Beschaltung stimmt.

Gibt es irgendwelche Stolperfallen bzw. Tricks die bei der Portierung 
der UART-Routine vom Mega32 zum Mega168A zu beachten sind?

Hatte jemand von euch bereits das Problem?

MFG Martin

von Stefan (Gast)


Lesenswert?

Hast Du eventuell die beiden Ports vertauscht?

Ansonsten habe ich neben den anderen register-Namen noch diese 
Unterscheidung in meinen Programmen, damit sie auf beiden Chips laufen:

        // framing format 8N1
        #ifdef URSEL
            UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
        #else
            UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
        #endif

von Martin (Gast)


Lesenswert?

@Stefan: Habe jetzt die Änderungen ebenfalls so angelegt, dass es mit 
beiden µCs laufen sollte.

Mit dem Atmega32 läufts super - ich empfange die richtigen Daten im 
Hterm. Aber mit dem 168 wills nich laufen :-(

Könntest du mir eventuell deinen Code bzw. einen UART-Auszug zur 
Verfügung stellen, damit ich meinen Fehler suchen kann ?

von Thomas E. (thomase)


Lesenswert?

Stefan schrieb:
> #else
>
>             UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
>
>         #endif

Der Atmega168 hat kein UCSRC-Register.

mfg.

von Martin (Gast)


Lesenswert?

Hallo Thomas,

ja das hab ich auch in meinem Code berücksichtigt. Bei mir ist es:
1
 UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);

Trotzdem will es einfach nicht laufen..

von Oliver J. (skriptkiddy)


Lesenswert?

Zeig bitte den kompletten Code.

von g457 (Gast)


Lesenswert?

> Gibt es irgendwelche Stolperfallen [..] die [..] zu beachten sind?

Größte Stolperfalle ist wie üblich, den Code nicht oder nicht 
vollständig zu zeigen. Passiert leider immer wieder. Die zweitgrößte 
Stolperfalle ist eine ungenaue Fehlerbeschreibung wie

> Nun funktioniert meine UART Übertragung nicht.

HTH und nix für ungut

von Thomas E. (thomase)


Lesenswert?

Martin schrieb:
> ja das hab ich auch in meinem Code berücksichtigt.
Das würde auch gar nicht kompilieren und stammt ja auch nicht von dir. 
Aber es ist einfach nur schlampig und der Compiler verzeiht keine 
Schlamperei.

Martin schrieb:
> UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
Da liegt dein Fehler auch nicht. Das ist die mit Abstand unwichtigste 
Einstellung. Denn der Registerwert ist der gleiche wie nach Reset.

Für eine normale UART-Übertragung müssen beim 168er nur das 
UCSR0B-Register und die Baudrate eingestellt werden. Evtl. noch das U2X0 
in UCSR0A zur Baudratenverdoppelung.

mfg.

von Martin (Gast)



Lesenswert?

Hallo,

danke an alle die sich bisher die Mühe gemacht haben, zu antworten.

Die UART-Übertragung ist mittlerweile kein Problem mehr. Es war vielmehr 
das Problem mit der Umleitung von printf.

Anbei habe ich den angepassten Quellcode (stammt ursprünglich aus dem 
Artikel Versenden von SMS mittels Mobiltelefon).

Ich habe in den Code noch den Beschleunigungssensor BMA020 eingebunden, 
was aber nichts mit dem Problem zutun haben sollte, dieser funktioniert 
einwandfrei.

Ich programmiere im AVRStudio 5 und habe "optimize -O1" für die delay.h 
eingestellt.

Der Code wird, je nach Device-Einstellung (ATmega32 oder ATmega168A) im 
AVRStudio, fehler- und warnungsfrei übersetzt.

Wenn ich mir das ganze im Hterm betrachte, dann sehe ich mit dem 
ATmega168A gar nichts. Mit dem Mega32 werden die Daten richtig 
übertragen (siehe Bild: Original_fdevopen_M32).

Wie der Bildname vermuten lässt, habe ich dann die Stdio-Umleitung mit 
fdevopen gegen die stdout-Variante aus dem AVR-GCC-Tutorial ersetzt.

1
 //in sms.c
2
    uart_init();
3
    fdevopen (uart_sendc, uart_receive);
1
 // in uart.c
2
    int uart_sendc(char c, FILE *dummy)
3
    {
4
    while (!(UCSRA & (1<<UDRE))) {}  // warten bis Senden möglich 
5
    UDR = c;                         // Zeichen senden   
6
    return (0);
7
    }
8
    ...
9
    int uart_receive(FILE *dummy)
10
    {
11
        ...
12
    }

Neue Variante:
1
 // in main.c
2
    int uart_sendc(char c, FILE *stream);   
3
4
    static FILE mystdout = FDEV_SETUP_STREAM( uart_sendc, NULL,     
5
    _FDEV_SETUP_WRITE );
6
7
    ...
8
    
9
    uart_init();
10
    stdout = &mystdout;
1
 //in uart.c
2
    int uart_sendc(char c, FILE *stream)
3
    {
4
    if( c == '\n' )
5
        uart_sendc( '\r', stream );
6
 
7
    loop_until_bit_is_set( UCSRA, UDRE );
8
    UDR = c;
9
    return 0;
10
    }
11
    ...
12
    int uart_receive(FILE *stream)
13
    {
14
        ...
15
    }

Das Ergebnis der neuen Variante ist, dass es tadellos mit dem Mega32 
funktioniert (siehe Bild SMSAlarm_stdout_M32), jedoch nichts mit dem 
Mega168 zu sehen ist.

Schiebe ich jetzt den folgenden Teil in die sms.c -> sms_init()
1
  //sms.c
2
     int uart_sendc(char c, FILE *stream);
3
     static FILE mystdout = FDEV_SETUP_STREAM( uart_sendc, NULL,    
4
     _FDEV_SETUP_WRITE );
5
6
     ...
7
 
8
     void sms_init(void){
9
  // Initialisierung der seriellen Schnittstelle Asynchron
10
  uart_init();
11
  // öffnet Kanal für printf
12
  stdout = &mystdout;
13
  //fdevopen (uart_sendc, uart_receive);
14
15
     ...

dann erhalte ich mit dem Mega168 erste Lebenszeichen in Hterm (siehe 
Bild SMSAlarm_stdout_M168A). Die Daten werden aber immer noch nicht 
korrekt übertragen.

Jetzt meine Fragen :-)

Kann das sein, dass in dem Original-Code veraltete Stellen sind, die auf 
dem Mega168 Probleme bereiten?

Oder kommt mein Compiler nicht mit dem Code klar?

Wenn ich die Funktionen:

uint8_t sms_check_nr(char* telnr_in)
SMS_MSG sms_state_machine(void)
uint8_t sms_cmdset(uint8_t dat)

auskommentiere, dann sehen die Daten im Hterm schon ganz in Ordnung aus. 
Das Problem ist jetzt, dass die Nachrichten, die den Funktionen 
sms_send() und sms_display_text() übergeben werden, nicht berücksichtigt 
werden :-(

Ich bin bald am verzweifeln und hoffe jemand von euch kann mir da 
weiterhelfen.

In der SMSALARM_angepasst_M168.zip ist der aktuelle C-Code der von mir 
bis hier hin geschrieben bzw. abgeändert wurde.

Gruß Martin

von Martin (Gast)


Lesenswert?

Hallo,

ich glaube ich konnte die Probleme nun noch weiter eingrenzen:

Kann es sein, dass ich mit strlen(nachricht) und printf Probleme beim 
compilieren kriege?

Ich vermute, dass durch das Strlen im folgenden Code-Stück Probleme 
auftauchen:
1
   ...
2
3
   void sms_display_text(char* nachricht)
4
   {  
5
      char tmp[20]="";
6
      uint8_t i;
7
      uint8_t cnt_txt=0;
8
9
      UCSRB &= ~(1 << RXCIE);    // UART Receive ISR ausstellen
10
      uart_clear();
11
    
12
      cnt_txt = strlen(nachricht);
13
      printf("AT^SSTK=%02i,0\r\n",cnt_txt+13+1);  // 13 Header, 1 't' 
14
                                                  // vor nachricht
15
      gets(tmp);
16
      printf("D0");  // Text String Tag
17
      printf("%02X",cnt_txt+13+1-2);  // Länge des PDU String - 1
18
19
   ...

Kann sich das bitte mal jemand anschauen?

Gruß Martin

von Karl H. (kbuchegg)


Lesenswert?

Martin schrieb:

> Kann es sein, dass ich mit strlen(nachricht) und printf Probleme beim
> compilieren kriege?

Ich denke eher, dass du noch Fehler im Progamm hast, die dir vorher 
nicht aufgefallen sind, bzw. die sich nicht bemerkbar gemacht haben.
'Funktioniert auf einem Mega8' ist KEIN Beweis für ein fehlerfreies 
Programm.


Warum gehst du nicht schrittweise vor?

Teste doch erst mal nur die UART allein. Verkabel sie mit deinem PC und 
schreib dir ein Testprogramm welches die UART für sich alleine testet, 
indem sie endlos zb ein Zeichen an den PC schickt.


int main()
{
  uart_init();

  while( 1 )
    uart_putc( 'x', NULL );
}

und dann geht es weiter, indem du sukzessive Teile aus deinem 
vorhandenen Programm übernimmst. WObei es nicht schaden kann, wenn man 
über den jeweiligen Teil noch mal drüber liest und gezielt nach 
Problemstellen sucht.

Gegen 'ich bin bald am verzweifeln' hilft nur systematisches Vorgehen. 
Was nicht funktioniert: planlos herumprobieren weil man denkt: dort hat 
es ja auch funktioniert. Immer daran denken: Durch testen kann man nicht 
die Abwesenheit von Fehlern feststellen sondern immer nur die 
Anwesenheit. Nur weil ein Programm scheinbar funktioniert, heißt das 
nicht, dass es fehlerfrei wäre.

von Martin (Gast)


Lesenswert?

Die UART und printf-Umleitung funktionieren jetzt.

Ich habe dasselbe Programm auf dem Mega168 und dem Mega32. Nur der 
Inhalt der strings, die von sms_display_text() und sms_send() 
(Mega168)gesendet werden stimmen nicht mit denen vom Mega32 überein.

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Ich krieg's einfach nicht hin :-(

Meine letzte Aussage muss ich leider zurückziehen, die Übertragung eines 
einzelnen Zeichens über UART funktioniert, nur die Umleitung will nicht 
so wie ich will.

Mit
1
fdevopen(uart_sendc,uart_receive)

funktioniert es auf dem Mega32 und das Handy empfängt die Daten, aber 
auf dem Mega168 gehts nicht. Sobald ich die Variante aus dem 
AVR-GCC-Tutorial nehme, tut sich etwas am Mega168, aber nicht so wie es 
sein soll.
1
// in main.c
2
    int uart_sendc(char c, FILE *stream);   
3
4
    static FILE mystdout = FDEV_SETUP_STREAM( uart_sendc, NULL,     
5
    _FDEV_SETUP_WRITE );
6
7
    ...
8
    
9
    uart_init();
10
    stdout = &mystdout;
1
 //in uart.c
2
    int uart_sendc(char c, FILE *stream)
3
    {
4
    if( c == '\n' )
5
        uart_sendc( '\r', stream );
6
 
7
    loop_until_bit_is_set( UCSRA, UDRE );
8
    UDR = c;
9
    return 0;
10
    }
11
    ...
12
    int uart_receive(FILE *stream)
13
    {
14
        ...
15
    }

Ich habe auch folgendes probiert:
1
FILE *fdevopen(int (*uart_sendc)(char c, FILE* stream), int (*uart_receive)(FILE* stream));

Der Compiler macht alles fehlerfrei, aber im Terminal ist nichts zu 
sehen.

Was habe ich nicht beachtet oder was mache ich grundsätzlich falsch?

MfG Martin

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.