Forum: Mikrocontroller und Digitale Elektronik merkwürdeges Phänomen


von Max F. (Gast)


Lesenswert?

Hi,

und zwar ist mir gestern Abend an meinem ATMEGA8535 mit T6963 Display
folgendes aufgefallen
In meinem Hauptprogramm verwende ich diesen Code:
while()
  {
   if(tasten() == 3)
           tagesprofil();
  }
Wenn ich meinen Hex Code in meinen ATMEGA8535 lade dann wird auch alles
auf meinem Display angezeigt. Nur meine Uhr bleibt komischerweise stehe.
Ich vermute dass es an dem "getchar()" liegt.
Denn wenn ich diese if Anweisung entferne, dann funzt auch alles
super.
Ich Verwende den sende und empfangs Interrupt der UART den AD Wandler
und den "TIM1_COMPA" Interrupt.
Was könnte da falsch sein?

interrupt [USART_RXC] void uart_rx_isr(void)
{
 uart_recieve = UDR;
}

interrupt [USART_TXC] void uart_tx_isr(void)
{
}

void tagesprofil (void)
{
 unsigned char n, m;
 for (n=0; n<24; ++n)
    {
     if (n == 0)
      {
       putchar('T');
      }
     sprintf (printbuf,"%4d %2d.%2d.%2d
",2006,(int)12,(int)16,(int)n);
     sprintf (printbuf+15,"%4d%3d",1014,(int)23);
     *(printbuf+24) = 0x0d;
     *(printbuf+25) = 0x0a;
     for (m=0; m<26; ++m)
        {
          putchar(*(printbuf + m));
        }
     {unsigned int i; for (i=1000; i>0; --i);}
    }
 putchar('E');
}

unsigned int readADC_10BIT(unsigned char channel)
{
  unsigned char m;
  unsigned int result;

  ADCSRA = 0x86;    // Frequenzvorteiler
                               // setzen auf 64 (1) und ADC aktivieren
(1)

  ADMUX = channel;    // Kanal waehlen
  ADMUX |=  0x40; // AVCC als Referenzspannung nutzen

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu
lassen" */
  ADCSRA |= 0x40;              // eine ADC-Wandlung
  while(!(ADCSRA & 0x10));     // auf Abschluss der Konvertierung
warten (ADIF-bit)

  result = 0;

  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden
Wandlungen */
  for(m=0;m<4;m++)
  {
    ADCSRA |= 0x40;            // eine Wandlung "single conversion"
    while(!(ADCSRA & 0x10));   // auf Abschluss der Konvertierung
warten (ADIF-bit)

  result += (ADCL + (ADCH<<8));       // mit uint16_t x


  //result += ADC;        // Wandlungsergebnisse aufaddieren
  }

  ADCSRA &= ~0x80;             // ADC deaktivieren (2)

  result >>= 2;                     // Summe durch vier teilen =
arithm. Mittelwert

  return result;
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
 #if XTAL % DEBOUNCE                   // bei rest
  OCR1A = XTAL / DEBOUNCE - 1;   // compare DEBOUNCE - 1 times
 #endif
 if( --prescaler == 0 )
   {
    prescaler = DEBOUNCE;
    sekunde++; // exact one second over
    Uhrzeit(sekunde);
    tasten();
    #if XTAL % DEBOUNCE        // handle remainder
      OCR1A = XTAL / DEBOUNCE + XTAL % DEBOUNCE - 1; // compare once
per second
    #endif
   }
}

von Max F. (Gast)


Lesenswert?

Shit ich habe mich da oben vertan ich habe den Code benutzt.
while()
  {
   if(getchar() == 'h')
       tagesprofil();
  }

Wenn ich in dem Hauptprogramm dies hier vewende:

while()
  {
   if(tasten() == 3)
           tagesprofil();
  }

Dann tut es auch korrekt. Also die Uhr bleibt dann in der
Anzeige(Display) nicht sethen

von dieter (Gast)


Lesenswert?

Ich kenn mich nicht so damit aus, aber von C++ kenne ich ein getch() -
welches auf die Tasteneingabe wartet. Mit if prüfst du einen Wert  -
hier ist es egal, ob der Wert übergeben wurde.

von Max F. (Gast)


Lesenswert?

Ja ich ich weiss da nicht weiter. Wie gesagt meine Uhr auf dem Display
läuft da nicht mehr. Nur wenn ich eine Anforderung sende, dass das
Tagesprofil gesendet werden soll, dann läuft die Uhr kurz weiter.
Ich glaube schon dass der Timer da ganz normal arbeitet. Es hängt
möglicherweise mit dem Display zusammen. Hmmmm...

von Steffen (Gast)


Lesenswert?

kommt getchar() nicht erst zurück, wenn ein Zeichen empfangen wurde ?
Damit würde Dein System stehen.

von Max F. (Gast)


Lesenswert?

Hmmm...ich habe halt deswegen die Funktion getchar() verwendet, weil ich
von der UART auf ein bestimmtes Zeichen warte und dann soll die
entsprechende Aktion ausgeführt werden. In diesem Falle wird das
Tagesprofil gesendet.

Welche Funktion müsste ich dann verwenden um ein Zeichen von der UART
zu empfangen(Controller)?

von Steffen (Gast)


Lesenswert?

einfach einen neue Function schreiben.

char rec_char(void)
{
   if((UCSRA & (1<<RXC)));
       return UDR;
   else
       return 0x00;
}

von Max F. (Gast)


Lesenswert?

Die Funktion hab ich mal getestet. Funzt nicht!
Wenn ich die Funktion uart_recieve() ausführe und ich sende vom PC aus
ein Zeichen dann hört die UART nicht mehr auf zu empfangen.
Kann ich überhaupt die UART Interrupt so verwenden?

interrupt [USART_RXC] void uart_rx_isr(void)
{
 uart_recieve = UDR;
}

interrupt [USART_TXC] void uart_tx_isr(void)
{
}


unsigned char uart_recieve(void)
{
 while(!(UCSRA & 0x80))
 return UDR;
}

von Max F. (Gast)


Lesenswert?

Wenn ich es so mache wie Steffen beschrieben hat, dann tut sich gar
nix.

char rec_char(void)
{
   if((UCSRA & (1<<RXC)));
       return UDR;
   else
       return 0x00;
}

Stimmt der Code wirklich?

von Max. F (Gast)


Lesenswert?

Also das mit der UART klappt nach nicht so richtig.
Ich habe mich entschlossen das ganze ohne UART Interrupt zu machen.

unsigned char uart_recieve(void)
{
 while(!(UCSRA & 0x80))
 return UDR;
}

unsigned char uart_transmit(void)
{
 while(!(UCSRA & 0x20))
 UDR = data;
}

Die uart_transmit Funktion tut soweit. Die andere Funktion funktioniert
noch nicht.
Die UART tue ich im Hauptprogramm so initialisieren:
UCSRB = 0x18; //ohne Interrupt //für Interrupt 0xD8 verwenden:
UBRRH = 0;
UBRRL = 0x33;
Was ist in meiner Empfangfunktion falsch?

von Profi (Gast)


Lesenswert?

solltest Du nicht auch noch mitteilen, dass das Zeichen abgeholt wurde?
interrupt [USART_RXC] void uart_rx_isr(void)
{
 uart_recieve = UDR;
 lösche_IRQ_Flag();
}
kenn mich mit Atmel wenig aus.

Steffen löst es mit Polling, es gilt:
entweder pollen oder mit Interrupt

von Max. F (Gast)


Lesenswert?

Ich verwende keinen Interrupt. Ich habe zwei Funktionen.

unsigned char uart_recieve(void)
{
 while(!(UCSRA & 0x80))
 return UDR;
}

unsigned char uart_transmit(void)
{
 while(!(UCSRA & 0x20))
 UDR = data;
}

Nur die uart_recieve Funktion tut gar nicht.

von hans dieter (Gast)


Lesenswert?

warum lässt du die uhr nicht per interrupt aktualisieren?
dann kann das hauptprogramm auf ungestört auf deine anfragen reagieren
und deine uhr läuft ordentlich.

wenn das display ein busy flag hat, dann ist das mit dem schreiben auf
das display auch nicht schlimm. das hauptprogramm muss halt vor jedem
schreiben auf das fertigstellen des kommandos im display warten.
in der isr brauchst du nur auf das display schreiben und eigentlich
nicht warten, bis es fertig ist.

von Max. F (Gast)


Lesenswert?

Hmmm..wei meinst du das genau?

Wie müsste die uart_recieve() FUnktion korrekt aussehen?

von Max. F (Gast)


Lesenswert?

Ich lasse doch bei mir die Uhr per Interrupt aktualisieren.
Ich verwende den Timer Compare. Und da wird meine Uhrzeit aktualisiert.

Deshalb verstehe ich das nicht was hans dieter da geschrieben hat.

Ich hab ein Problem mit dem Empfangen von der UART.
Die uart_recieve Funktion tut nicht. Senden funktioniert ja.
Muss ich bei der uart_recieve Funktion irgend ein Bit löschen?
Als Controller verwende ich den ATMEGA8535

unsigned char uart_recieve(void)
{
 while(!(UCSRA & 0x80))
 return UDR;
}

unsigned char uart_transmit(void)
{
 while(!(UCSRA & 0x20))
 UDR = data;
}

von Thomas K. (thkais)


Lesenswert?

Bei Deiner uart_receive-Funktion kommt ein unbekannter Wert zurück,
falls nichts im UDR drinnen ist.
Ich verwende in solchen Fällen zwei Funktionen für den Empfang:

uint8_t get_serial_status(void)
{
  if (bit_is_set(UCSRA,RXC))
    return 1;
  else
    return 0;

}

uint8_t get_serial(void)
{
  return UDR;
}

Im Hauptprogramm frage ich dann erstmal den Status ab. Falls der Status
= 0, muss das Hauptprogramm einfach weitermachen, ohne etwas von der
seriellen Schnittstelle abzuholen. <-- Das ist wichig. Wenn Du auf die
serielle Schnittstelle wartest, wird währenddessen das LCD nicht mehr
aktualisiert.
Ist der Status = 1, lese ich die serielle Schnittstelle aus und
verarbeite die Daten.
Noch ein kleiner Tipp am Rande: Man verwendet sinnvollerweise keine
Konstanten bei dem Setzen von Bits, sondern die Bezeichnungen aus dem
Datenblatt. Das macht den Code lesbarer.

von Profi (Gast)


Lesenswert?

schau mal im Datenblatt, ob das Lesen des UDR das Bit7 (RXC) im UCSRA
wieder zurücksetzt, oder ob Du das selbst machen musst.

von Max F. (Gast)


Angehängte Dateien:

Lesenswert?

Super! Ich kann jetzt von der UART senden und empfangen.
Leider funzt es noch als nicht zu 100% korrekt.
Ich habe in meiner Main in der while Schleife drei if Bedingungen
eingebaut.

        if(uart_recieve() == 'A')
         {
          test();
         }
        if(uart_recieve() == 'B')
         {
          uart_transmit('E');
         }
        if(uart_recieve() == 'C')
         {
          tagesprofil();
         }
Wenn ich das Zeichen 'A' an den Controller sende dann sendet der
Controller auch --> test();

Wenn ich das Zeichen 'B' oder 'C' sende dann sendet der Controller
da nix.Überhaupt kein Zeichen.
nur wenn ich wieder das Zeichen 'A' sende dann tut es.
Wenn ich das Zeichen'B' sende warum tut sich da nichts?

Ich habe mal das Register UCSRA in der while Schleife ausgelesen.
Am Anfang steht dort 0x20 wenn ich das Zeichen 'A' drücke dann
erscheint der HEX Wert 0x60. Warscheinlich muss man das TxC Register
wieder löschen oder? Wie kann ich denn von dem UCSRA Register das 7Bit
löschen?

//Funktionen zur UART
void uart_transmit(unsigned char data)
{
 while(!(UCSRA & 0x20));
 UDR = data;
}

unsigned char uart_recieve(void)
{
 while((UCSRA & 0x80))
 return UDR;
}

von Max F. (Gast)


Angehängte Dateien:

Lesenswert?

In den beiden Bilder befindet sich die genauere Beschreibung der UARt
Register vom ATMEGA8535.

von Karl H. (kbuchegg)


Lesenswert?

>         if(uart_recieve() == 'A')
>         {
>          test();
>         }
>         if(uart_recieve() == 'B')
>         {
>          uart_transmit('E');
>         }
>         if(uart_recieve() == 'C')
>         {
>          tagesprofil();
>         }

Der Code versucht insgesammt 3 mal zu lesen.
D.h. Wenn Du B tippst und die Code Sequenz ganz am
Anfang steht, so wird das nicht ausgewertet (da ja kein
'A'). In den Zweig fuer 'B' kommt er aber auch nicht
rein, da Du ja wieder uart_receive() aufrufst und da
kommt dann nichts mehr (das 'B' das du ueber die Serielle
geschickt hast wurde ja bereits vom vorhergehenden if
weggefressen).

Machs mal so:

   char Zeichen;


   ...

   zeichen = uart_receive();
   if( zeichen == 'A' )
   {
   }

   else if( zeichen == 'B' )
   {
   }

   else if( zeichen == 'C' )
   {
   }

von Thomas K. (thkais)


Lesenswert?

Oder:

switch (uart_receive())
{
  case 'A':
    mach irgendwas
    break;
  case 'B':
    ....
    break;
  case 'C':
    ....
    break;

usw.

usw.

}

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.