merkwürdeges Phänomen

Gast #303732
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
   }
}
Gast #303733
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
Gast #303735
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...
Gast #303737
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)?
Gast #303739
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;
}
Gast #303741
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?
Gast #303742
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
Gast #303743
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.
Gast #303744
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.
Gast #303746
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;
}
#303747
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.
Gast #303749
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;
}
Angehängte Dateien:
#303751
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' )
   {
   }

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren