www.mikrocontroller.net

Forum: Compiler & IDEs UART-AtmegaAbsturz


Autor: Richi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

ich habe folgendes Problem:

Mein Atmega32 bekommt über UART zu unbestimmten Zeiten je 5 Bytes 
geschickt (Hintereinander). Ich nehme dafür den RXC-Interupt nehmen, in 
dem die 5 Bytes in ein Array geschrieben werden. Sobald das 5. empfangen 
empfangen wird, wird der Interupt ausgeschalten und ein Flag gesetzt.

Wenn ich nun aber mit dem PC einen großen Datenfluss sende, dürften 
eigentlich nur die ersten 5 Byte empfangen und dann über das 
Hauptprogramm auf dem LCD angezeigt werden.

Doch während des Sendens resetet sich der Atmega dauernd (sehe ich an 
einem Counter auf dem Display) bis dieser schließlich ganz den Geist auf 
gibt und nicht mehr reagiert.

Wo könnte der Fehler liegen???


Viele Grüße
Richi

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Zeile 42 liegt die Lösung all Deiner und unserer Probleme...

Anmerkung:
Ohne Quelltext artet das hier in einer wilden Raterei aus.

Autor: Richi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, das ich das vergessen habe.

Kleine Anmerkung:
Wenn die 5 Bytes nicht annähernd hintereinander kommen, werden sie nicht 
akzeptiert. (Siehe Code).

Die LCD-Funktionen habe ich nicht mit aufgeführt, sollten aber klar 
sein.

Hoffe das Hilft (auch wenns ein bisschen viel ist)

Viele Grüße
Richi


Atmega32 mit 16MHz


#include "SLEEP.h"
#include "LCD.h"
#include "USART.h"

int main(void)
{
  Sleep_Init();
  LCD_Init(LCD_ON);
  Usart_Init();

  UART_Enable();

  sei();

  while(1)
  {
    Counter_Print();

    while(UART_neu)
    {
      LCD_Clear();
      LCD_Puts("5 Bytes:");
      LCD_Gotoxy(0,1);
      Sleep(250);
      for(unsigned char i = 0; i<5; i++)
      {
        LCD_Putc(Stelle(UART[i],3)+48);
        LCD_Putc(Stelle(UART[i],2)+48);
        LCD_Putc(Stelle(UART[i],1)+48);
      }

      Sleep(500);

      LCD_Clear();

      UART_neu = 0;
    }

    Sleep(20);
  }

  return 0;
}

Headers:

#ifndef USART_H
#define USART_H

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

volatile unsigned char UART[5], UART_counter, UART_Clock, UART_neu;

#define UART_Disable() UCSRB = 0x00;
#define UART_Enable()  UCSRB = 0x90;

void Usart_Init(void);

void Usart_Write(unsigned char Byte);

unsigned char Usart_Read(void);

#endif


#ifndef SLEEP_H
#define SLEEP_H

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

#include "USART.h"

volatile unsigned long count250Hz;

#define nop()  __asm__ __volatile__ ("nop" ::)

void Sleep_Init(void);

void Sleep(unsigned long time250Hz);

void Delay(void);

#endif

C-Sources:

#include "USART.h"

void Usart_Init(void)
{
  DDRD &= ~(1<<0);
  PORTD |= (1<<0);

  UCSRA = 0x00;
  UCSRB = 0x00;  
  UCSRC = 0x86;
  UBRRL = 103;
  UBRRH = 0;

  UART_neu = 0;
}

ISR(USART_RXC_vect)
{
  if(UART_Clock == 10)
  {
    UART_counter = 0;
  }

  UART_Clock = 0;

  UART[UART_counter] = UDR;

  UART_counter ++;

  if(UART_counter == 5)
  {
    UART_Disable();

    UART_counter = 0;
    UART_neu = 1;
  }
}




#include "SLEEP.h"

ISR(TIMER0_COMP_vect)
{
  count250Hz ++;
  
  if( UART_Clock < 10 )
  {
    UART_Clock ++;
  }
}


void Sleep_Init(void)
{
  TCCR0 = (1 << WGM01) | (1 << CS02);
  OCR0  = 249;
  TIMSK |= (1 << OCIE0);
}

void Sleep(unsigned long time250Hz)
{
  count250Hz = 0;
  while(count250Hz < time250Hz);
}

void Delay(void)
{
  for(unsigned char i=0;i<2;i++)
  {
    nop();
  }
}

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein "andauerndes resetten" kommt in 99% aller Fälle durch einen 
Interrupt, für den keine ISR vorhanden ist.

Da deine Interrupt-Freigaben aber etwas kryptisch sind, musst du dein 
Programm schon selber auf dieses Problem hin untersuchen.

Oliver

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schmeiss mal den ganzen Sleep-Krempel raus.
Ein Programm, welches die halbe Zeit nur einen Sleep macht, will man 
sowieso nicht haben und erhöht erst mal die Übersicht durch weniger 
Code.

Für den Reset ist so erst mal keine Ursache direkt erkennbar. Bist du 
sicher, dass ein Reset erfolgt?
Am Anfang Led ein, _delay_ms(500) und Led aus. Wenn die Led die ganze 
Zeit ruhig bleibt, dann sind es keine Resets, sondern irgendwas bügelt 
über deinen Counter drüber.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm hier

volatile unsigned char UART[5], UART_counter, UART_Clock, UART_neu;

die Variable UART_counter aus dem Header File raus. Dieser Counter geht 
ausser der ISR niemanden etwas an.

Stattdessen wandert die ins C-File
#include "USART.h"

static unsigned char UART_counter;

void Usart_Init(void)
{
  DDRD &= ~(1<<0);
  PORTD |= (1<<0);

  UCSRA = 0x00;
  UCSRB = 0x00;  
  UCSRC = 0x86;
  UBRRL = 103;
  UBRRH = 0;

  UART_neu = 0;
  UART_counter = 0;   // sicherheitshalber
}

ISR(USART_RXC_vect)
{
  if(UART_Clock == 10)
  {
    UART_counter = 0;
  }

  UART_Clock = 0;

  UART[UART_counter] = UDR;

  UART_counter ++;

  if(UART_counter >= 5)
  {
    UART_Disable();

    UART_counter = 0;
    UART_neu = 1;
  }
}

Sicherheitshalber in der Init auf 0 setzen (auch wenn sie das als 
globale Variable sowieso sein sollte. Die Abfrage auf Buffer voll 
defensiv mit einem >= anstelle des == programmieren.

Darüber
#define UART_Disable() UCSRB = 0x00;
#define UART_Enable()  UCSRB = 0x90;
sag ich jetzt nichts. 0x90 ist so herrlich aussagekräftig, so dass man 
mit einem Blick sofort sieht, was du da einschaltest :-)

Einen Grund für Resets hab ich allerdings immer noch nicht gefunden. Was 
ist, wenn du dir die Bestätigung anstelle mit dem LCD mit ein paar LED 
geben lässt? Ev. ein Fehler in den LCD Funktionen?

Autor: Richi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also: 0x90 --> (1<<RXCIE) | (1<<RXEN)

Einen Fehler in den LCD_Funktionen schließe ich aus, da sich ja der 
Counterwert, welcher angezeigt wird, ständig ändert.

Während dem Datenfluss stellt sich dieser dann plötzlich wieder auf 0.
--> Reset

Autor: Richi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Normalerweise müsste doch der Empfänger völlig abgeschalten sein und der 
Interrupt darf nicht mehr ausgeführt werden.

Mir ist auch aufgefallen, dass in diesem Fall die Sleep-Routinen nicht 
mehr ordentlich eingehalten werden.

Autor: Richi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachdem sich der Counter wieder auf 0 gestellt hat erscheint gleich die 
Meldung der Empfangenen Bytes.

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ohne drüber zu schauen: Du löschst aber nach dem Ausschalten des RX-IRQ 
ein evtl. schon wieder gesetztes RXC-Flag?

Sind so meine fallen, nach dem Abschalten des Krams macht man noch was, 
dann wird die ISR beendet, die globalen IRQ wieder freigegen und es 
lauert ein RXC-Flag, weil inzwischen ein Byte eingetroffen ist, das man 
eigentlich garnicht mehr haben will...

Gruß aus Berlin
Michael

Autor: Richi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Alles vorgeschlagene Nützt nichts, ich habe nun eine Extra-LED für den 
Reset eingebaut und das LCD weggelassen.

Kann es sein, dass es evtl. Probleme mit dem Data-Overrun gibt und dass 
die ISR beim Starten einmal durchlaufen wird?

Gruß
Richi

Autor: Richi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke mitlerweile weiß ich wo der Fehler liegt:
Wieder  einmal auf meinem Steckbrett!!!

Wenn ich die LEDs/UART über das STK500 laufen lasse, gehts einwandfrei, 
auf dem Steckbrett nicht.

Ich weiß nur noch nicht, wo genau.

Gruß
Richi

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.