Forum: Compiler & IDEs Übertragung des Zustandes an PC UART


von Jürgen D. (dell)


Lesenswert?

Habe folgendes Problem:
Benutze STK500 mit Atmega16
Das Senden vom yC und Empfangen am PC funktioniert. Doch leider nicht 
richtig. Wenn ich die Taste am Stk500 drücke wird der Test für den 
Zustand gesendet und beim loslassen der zweite Text. Gewollt war, dass 
wenn Lampe an bzw. aus ist, der Zustand zum Pc gesendet wird.




#include <stdlib.h>
#include <avr/io.h>
#define WARTEPIN PIND
#define WARTEBIT PD0

void uart_init()
{
    UCSRB |= (1<<TXEN);      // UART TX einschalten
    UCSRC |= (1<<URSEL)|(3<<UCSZ0);  // Asynchron 8N1

  #define F_CPU 8000000           /* Oszillator-Frequenz in Hz */

  // Hilfsmakro zur UBRR-Berechnung ("Formel" laut Datenblatt)
  #define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)
  #define UART_BAUD_RATE 9600
  UBRRH = (uint8_t)( UART_UBRR_CALC( UART_BAUD_RATE, F_CPU ) >> 8 );
    UBRRL = (uint8_t)UART_UBRR_CALC( UART_BAUD_RATE, F_CPU );
}
int main(void)
{
  unsigned char taste0_vorher = 0;
   DDRB  = 0xff; // PORTB alle AUSGANG
   PORTB = 0xFF; // Alle LEDS aus (STK500 HIGH)
   DDRD  = 0x00; // EINGANG

   while (1) {

  if ( (WARTEPIN & (1<<PD7)) )
      {
         // Schalter PD0 jetzt offen
         if (taste0_vorher == 1)
         {
            // Schalter PD0 vorher geschlossen => LED umschalten 
(toggeln)
            PORTB ^= (1<<PB7);
     sprintf(text,"Licht an");
      uart_puts(text);

            // neuen jetzt Zustand merken
            taste0_vorher = 0;
         }
      }
      else
      {
         // Schalter PD0 geschlossen
         if (taste0_vorher == 0)
         {
            // Schalter PD0 vorher offen => LED umschalten (toggeln)
            PORTB ^= (0<<PB7);
     sprintf(text,"Licht aus");
      uart_puts(text);

            // neuen jetzt Zustand merken
            taste0_vorher = 1;
         }
      }//Taste 0 PD 0 Ende

   }
   uart_init()
   return 0; // never reached
}

von Michael Wilhelm (Gast)


Lesenswert?

Schlecht formatierter Text. Und uart_init wird gar nicht ausgeführt. 
Warum du trotzdem was siehst, ist mir nicht klar.

MW

von Karl H. (kbuchegg)


Lesenswert?

Jürgen Dell wrote:
> Habe folgendes Problem:
> Benutze STK500 mit Atmega16
> Das Senden vom yC und Empfangen am PC funktioniert. Doch leider nicht
> richtig.

Soweit ich das sehen kann, funktioniert das tadellos.

> Wenn ich die Taste am Stk500 drücke wird der Test für den
> Zustand gesendet und beim loslassen der zweite Text.

Jep. Genauso ist das auch programmiert. Also funktioniert das
Senden über den UART komplett richtig.

> Gewollt war, dass
> wenn Lampe an bzw. aus ist, der Zustand zum Pc gesendet wird.

dazu solltest du erst mal definieren, wann denn die Lampe
ein bzw. ausgeschaltet werden soll. So wie es jetzt programmiert
ist, passiert bei Drücken der Taste etwas und beim Loslassen der
Taste auch und ich glaube das ist nicht das Verhalten, das du
haben wolltest. Ich denke du wolltest haben, dass jedesmal beim
Drücken der Taste der Zustand der Lampe umgeschaltet werden soll.

Falls dem so ist, dann stell erst mal deine Programmformatierung,
im Speziellen die Einrückungen, richtig. Dann siehst du relativ
schnell, wo du dich vertan hast.

Das ist allerdings nur die halbe Miete, denn du hast das Problem
der prellenden Taster komplett ignoriert. Wenn du frische, neue
Taster hast, mag es auch so gehen. Wenn du ältere Taster hast,
die bereits prellen, dann werden die dich mit so einer Progrmmierung
in den Wahnsinn treiben.

PS: Beim nächsten mal poste bitte Code, der auch tatsächlich
compiliert.

von Jürgen D. (dell)


Lesenswert?

Kannst du mir da bischen Hilfestellung geben. Beschäftige mich erst seit 
paar Tagen mit dieser Materie.

von Rahul D. (rahul)


Lesenswert?


von Jürgen D. (dell)


Lesenswert?

Habe es mit hilfe von Tutorial vesucht, bekomme es aber nicht hin wie 
ich es möchte. Passiert immer das was ich nicht wollte.
Mir fällt das Programmmieren nicht einfach.

von Jürgen D. (dell)


Lesenswert?

Kann ein Erfahrener meinen Code überfliegen und mir Ratschläge geben was 
man besser machen sollte.Das mit Formatierung muss ich mich noch 
angewöhnen. Der Code ist compiliert und zeigt keine Fehler. Auf Dem 
Stk500 verrichtet es die Arbeit, die ich mir vorgestellt hatte.


#include <stdlib.h>
#include <avr/io.h>
#define WARTEBIT PD0
unsigned char text[10];
unsigned char taste0_vorher;

// hier uart_init, uart_putc, uart_puts (s.o.)
int uart_putc(unsigned char c)
{
  while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
    {
    }
    UDR = c;                      /* sende Zeichen */
    return 0;
}

void uart_puts (char *s)
{
    while (*s)
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
        uart_putc(*s);
        s++;
    }
}

void uart_init()
{
    UCSRB |= (1<<TXEN);      // UART TX einschalten
    UCSRC |= (1<<URSEL)|(3<<UCSZ0);  // Asynchron 8N1

  #define F_CPU 8000000           /* Oszillator-Frequenz in Hz */

  // Hilfsmakro zur UBRR-Berechnung ("Formel" laut Datenblatt)
  #define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)
  #define UART_BAUD_RATE 9600

  UBRRH = (uint8_t)( UART_UBRR_CALC( UART_BAUD_RATE, F_CPU ) >> 8 );
    UBRRL = (uint8_t)UART_UBRR_CALC( UART_BAUD_RATE, F_CPU );
}

int main(void)
{

   DDRB  = 0xff; // PORTB alle AUSGANG
   PORTB = 0xFF; // Alle LEDS aus (STK500 HIGH)
   DDRD  = 0x00; /* alle Pins von Port D als Eingang */
   PORTD = 0xff; /* interne Pull-Ups an allen Port-Pins aktivieren */

   while (1)
   {
  if ( PIND & (1<<PD7))
      {
         // Schalter PD0 jetzt offen
         if (taste0_vorher == 1)
         {
            // Schalter PD0 vorher geschlossen => LED umschalten 
(toggeln)
            PORTB ^= (1<<PB7);
            // neuen jetzt Zustand merken
            taste0_vorher = 0;

      //Wenn Lampe an ist->Zustand senden
      if( !(PINB & (1<<PINB7)) )
          {
           uart_init();
            uart_puts("Licht an");
          }
          }
    }

    if ( !(PIND & (1<<PD7)))
      {
         // Schalter PD0 geschlossen
         if (taste0_vorher == 0)
         {
            // Schalter PD0 vorher offen => LED umschalten (toggeln)
            PORTB ^= (0<<PB7);
            // neuen jetzt Zustand merken
            taste0_vorher = 1;

         if( !(PINB & (1<<PINB7)))
          {
           uart_init();
            uart_puts("Licht aus");
          }
       }
      }//Taste 0 PD 0 Ende
   }
   return 0; // never reached
}

von Rahul D. (rahul)


Lesenswert?

Dir fehlt immer noch das Entprellen.

von Michael Wilhelm (Gast)


Lesenswert?

Des weiteren muss die Initialisierung der UART nur ein mal durchgeführt 
werden, nämlich vor while(1).

MW

von Karl H. (kbuchegg)


Lesenswert?

> int main(void)
> {
>
>    DDRB  = 0xff; // PORTB alle AUSGANG
>    PORTB = 0xFF; // Alle LEDS aus (STK500 HIGH)
>    DDRD  = 0x00; /* alle Pins von Port D als Eingang */
>    PORTD = 0xff; /* interne Pull-Ups an allen Port-Pins aktivieren */
>
>    while (1)
>    {
>   if ( PIND & (1<<PD7))
>       {
>          // Schalter PD0 jetzt offen
>          if (taste0_vorher == 1)
>          {
>             // Schalter PD0 vorher geschlossen => LED umschalten
> (toggeln)
>             PORTB ^= (1<<PB7);
>             // neuen jetzt Zustand merken
>             taste0_vorher = 0;
>
>       //Wenn Lampe an ist->Zustand senden
>       if( !(PINB & (1<<PINB7)) )
>           {
>            uart_init();
>             uart_puts("Licht an");
>           }
>           }
>     }
>
>     if ( !(PIND & (1<<PD7)))
>       {
>          // Schalter PD0 geschlossen
>          if (taste0_vorher == 0)
>          {
>             // Schalter PD0 vorher offen => LED umschalten (toggeln)
>             PORTB ^= (0<<PB7);
>             // neuen jetzt Zustand merken
>             taste0_vorher = 1;
>
>          if( !(PINB & (1<<PINB7)))
>           {
>            uart_init();
>             uart_puts("Licht aus");
>           }
>        }
>       }//Taste 0 PD 0 Ende
>    }
>    return 0; // never reached
> }

Vergleich mal diese beiden Ausschnitte, die in den beiden grossen
ifs vorkommen:

>       if( !(PINB & (1<<PINB7)) )
>           {
>            uart_init();
>             uart_puts("Licht an");
>           }

und

>          if( !(PINB & (1<<PINB7)))
>           {
>            uart_init();
>             uart_puts("Licht aus");
>           }

in beiden Fällen ist die Abfrage dieselbe. Etas soll passieren,
wenn PINB7 am PortB 0 ist.
Nur: In dem einen Fall behauptest du, dass die Lampe an ist und im
anderen Fall behauptest du, dass sie aus ist.
Das kann doch so nicht stimmen!

Des Rätsels Lösung liegt darin, dass du zur Feststellung des Zustands
das PIN Register benutzt. Das ist Unsinn. Das PIN Register wird nur
dann benutzt, wenn du einen externen Zustand an einem µC Pin einlesen
willst. Den Fall hast du aber nicht. Das Port Register ist auf Ausgang
geschaltet und du willst einfach nur feststellen, welchen Zustand denn
der Ausgangspin hat. In dem Fall benutzt du genauso das PORT Register
um festzustellen was Sache ist. Der PIN Register kommt nur dann zum
Einsatz, wenn der entsprechende Port-Pin auch tatsächlich auf Eingang
geschaltet ist. (*)

Das uart_init macht man nur ein einziges mal. Merken: Dinge werden
nur einmal initialisiert. Da stellt man ein was eine Komonpente machen
soll und lässt diese Konfiguration in Ruhe (es sei denn man möchte
umkonfigurieren, aber das willst du ja nicht). Daher wird das uart_init
rausgezogen und ganz am Programmanfang gemacht. Dies ist im übrigen
kein Kavaliersdelikt sondern hat einen handfesten Grund. Wenn die
UART noch mit Senden beschäftigt ist und du initialisierst sie neu,
was denkst du wird dann passieren?

Also: Beide Abfragen und die nachfolgende Ausgabe eines Textes
können zusammengezogen werden:


       if( !(PORTB & (1<<PB7)) )
         uart_puts("Licht an");
       else
         uart_puts("Licht aus");

und da diese Abfrage und Ausgabe in beiden grossen if-Zweigen immer
dieselbe ist, kann man die auch dort herausziehen.

Das nächste ist, dass du im zweiten Fall versuchst, die LED
zu toggeln mit

>             PORTB ^= (0<<PB7);

das wird nichts. Egal wie oft man eine 0 nach links schiebt, sie
bleibt trotzdem eine 0. D.h. da oben steht

              PORTB ^= 0;

das ändert aber am Portzustand nichts.
Code der nichts bewirkt kann und sollte auch wegfallen. Er verwirrt
nur.
1
int main(void)
2
{
3
  DDRB  = 0xff; // PORTB alle AUSGANG
4
  PORTB = 0xFF; // Alle LEDS aus (STK500 HIGH)
5
  DDRD  = 0x00; /* alle Pins von Port D als Eingang */
6
  PORTD = 0xff; /* interne Pull-Ups an allen Port-Pins aktivieren */
7
 
8
  uart_init();
9
10
  while (1)
11
  {
12
    if( PIND & (1<<PD7) )
13
    {
14
      // Schalter PD0 jetzt offen
15
      if( taste0_vorher == 1 )
16
      {
17
        // Schalter PD0 vorher geschlossen => LED umschalten (toggeln)
18
        PORTB ^= (1<<PB7);
19
        // neuen jetzt Zustand merken
20
        taste0_vorher = 0;
21
      }
22
    }
23
24
    else
25
    {    
26
      taste0_vorher = 1;
27
    }
28
29
    if( !(PORTB & (1<<PB7)) )
30
      uart_puts("Licht an");
31
    else
32
      uart_puts("Licht aus");
33
  }
34
35
  return 0; // never reached
36
}

Damit ist der Code aber schon um einiges kürzer und damit auch
leichter zu durchschauen.

Deine nächste Aufgabe: Mach dich über Entprellen schlau und hol dir
aus dem angegebenen Artikel den entsprechenden Code. Den dann
einbauen.


(*) es gibt da bei neueren Prozessoren eine Ausnahme bei der man das
PIN Register tatsächlich auch dann benutzt, wenn der Port auf
Ausgang geschaltet ist. Aber das würde jetzt zu weit führen.

von Jürgen D. (dell)


Lesenswert?

Danke für die Hilfe. Habe es versucht mit dem entprellen, funktioniert 
auch wohl, bloss es gibt bis jetzt noch ein anderes problem.
1
while (1)
2
  {
3
    if( PIND & (1<<PD7) )
4
    {
5
      // Schalter PD0 jetzt offen
6
      if( taste0_vorher == 1 )
7
      {
8
        // Schalter PD0 vorher geschlossen => LED umschalten (toggeln)
9
        PORTB ^= (1<<PB7);
10
        // neuen jetzt Zustand merken
11
        taste0_vorher = 0;
12
      }
13
    }
14
15
    else
16
    {    
17
      taste0_vorher = 1;
18
    }
19
20
    if( !(PORTB & (1<<PB7)) )
21
      uart_puts("Licht an");
22
    else
23
      uart_puts("Licht aus");
24
  }
25
26
  return 0; // never reached
27
}

Das ding ist die ganze Zeit am senden und blicke grad nicht durch woran 
es liegt. Mit meinem überlangen und falsche Programmierweise hat es aber 
funktioniert was ich wollte.

Für später: Wie stelle ich an das der yC erst senden soll wenn 2 
Tasten(ungleichmässig gedrückt) oder mehrer Tasten gedrückt werden, nen 
Text zum PC sendet?

von Karl H. (kbuchegg)


Lesenswert?

Jürgen Dell wrote:
> Danke für die Hilfe. Habe es versucht mit dem entprellen, funktioniert
> auch wohl, bloss es gibt bis jetzt noch ein anderes problem.
>
>
1
> while (1)
2
>   {
3
>     if( PIND & (1<<PD7) )
4
>     {
5
>       // Schalter PD0 jetzt offen
6
>       if( taste0_vorher == 1 )
7
>       {
8
>         // Schalter PD0 vorher geschlossen => LED umschalten (toggeln)
9
>         PORTB ^= (1<<PB7);
10
>         // neuen jetzt Zustand merken
11
>         taste0_vorher = 0;
12
>       }
13
>     }
14
> 
15
>     else
16
>     {
17
>       taste0_vorher = 1;
18
>     }
19
> 
20
>     if( !(PORTB & (1<<PB7)) )
21
>       uart_puts("Licht an");
22
>     else
23
>       uart_puts("Licht aus");
24
>   }
25
> 
26
>   return 0; // never reached
27
> }
28
>
>
> Das ding ist die ganze Zeit am senden und blicke grad nicht durch woran
> es liegt.

Ach du wolltest, dass der Text nur gesendet wird, wenn
ein Tastendruck festgestellt wird? Sorry. Das hab ich nicht
mitgekriegt.

Na ja, dann musst du das auch so programieren. Nur dann, wenn
eine Taste gedrückt wurde, wird der Text gesendet.
Wo wird festgestellt, dass eine Taste gedrückt wurde?

Na hier, denn genau dan dieser Stelle schaltest du ja auch
die LED um:

>     if( PIND & (1<<PD7) )
>     {
>       // Schalter PD0 jetzt offen
>       if( taste0_vorher == 1 )
>       {

Also wird wohl die Ausgabe da hineinwandern müssen.

> Für später: Wie stelle ich an das der yC erst senden soll wenn 2
> Tasten(ungleichmässig gedrückt) oder mehrer Tasten gedrückt werden, nen
> Text zum PC sendet?

Du hältst in einer Variablen fest welche Tasten gedrückt sind.
Und wenn dann diese Variable einen bestimmten Wert (der den
gewünschten gedrückten Tasten entspricht) dann löst du deine
Aktion aus.

Aber: Das alles geht sehr viel einfacher mit den Entprellroutinen
aus den weiter oben angegebenen Verlinkungen. Die führen auch darüber
Buch, ob und wenn ja welche Taste gedrückt ist. Ob sie lang oder
kurz gedrückt wurde.
Und die Auswertung ist sehr viel simpler.

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.