Forum: Mikrocontroller und Digitale Elektronik STK 500 LED'S über UART


von Bastler (Gast)


Lesenswert?

Hallo zusammen,

ich habe ein STK500 Board und kann inzwischen auf Tastendruck per UART 
einen String an mein Terminalprogramm senden.
Jetzt möchte ich die LED's des STK500 ansteuern und zwar in der Weise, 
das wenn ich eine 2 am Terminalprogramm eingebe, die zweite LED 
angeschaltet wird, bei einer 4 die vierte usw.
Außerdem wäre es schön, wenn das Controller das empfangene Zeichen 
wieder an das Programm zurücksenden würde.
Wie müsste eine solche Funktion aussehen?
Ich verwende einen AT90CAN128 Controller. Der UART ist sende und 
empfangsbereit geschaltet.
Wäre euch sehr dankbar für einen Code oder oder etwas Hilfe.

Gruß

von Patrick (Gast)


Lesenswert?

Hast Du hier schon mal nachgesehen? Mir hats geholfen.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Zeichen_Empfangen

von Bastler (Gast)


Lesenswert?

Ja hab ich schon gemacht, komm aber leider nicht wirklich weiter mit der 
einen kleinen Funktion....
Hast Du schon mal sowas ähnliches gemacht, wie ich machen will?

von Bastler (Gast)


Lesenswert?

Jetzt hab ich es hinbekommen, das ich Strings einlesen kann. Wie muss 
die if nun aussehen, das ich bsp. wenn eine 4 Dez vom Terminalprogramm 
eingelesen wird die vierte LED angeht?
Wäre sehr dankbar für eine Hilfe!

von Karl H. (kbuchegg)


Lesenswert?

Ist das jetzt eine Fangfrage?

   if( empfangenes_Zeichen == '4' )
     tu was immer du tun musst um LED Nr 4 einzuschalten


etwas trickreicher ist allerdings diese Variante
Allerdings sollte sichergestellt sein, dass
in empfangenes Zeichen wirklich nur eine Ziffer
von '0' bis '7' steht

  uint8_t NrLed;
  NrLed = empfangenes_Zeichen - '0';
  PORTx = 0x00;      // alle anderen LED aus
  PORTx |= ( 1 << NrLed );

Das geht dann für alle LED Nummern von 0 bis 7.

von Patrick (Gast)


Lesenswert?

Was Du auch noch beachten solltest, ist dass die Zahl wirklich Dezimal 
daher kommt und nicht etwa im ASCII-Code.

von Andreas K. (oldcoolman)


Lesenswert?

Wie sendest du denn die 2?

tippst du 2 und RETURN ?

dann sendest du den ascii wert des "Buchstabens" 2 !!

somit müßtest du nach den ascii wert abfragen (50)
0=48
1=49
2=50
3=51....

Gruß
andi

von Jörg B. (manos)


Lesenswert?

Patrick wrote:
> Was Du auch noch beachten solltest, ist dass die Zahl wirklich Dezimal
> daher kommt und nicht etwa im ASCII-Code.
Warum?
Ob ich jetzt auf ==0 oder =='0' abfrage ist doch eigentlich egal...

von Karl H. (kbuchegg)


Lesenswert?

Andreas Krieger wrote:
> Wie sendest du denn die 2?
>
> tippst du 2 und RETURN ?

Das macht er mit Sicherheit.

>
> dann sendest du den ascii wert des "Buchstabens" 2 !!
>
> somit müßtest du nach den ascii wert abfragen (50)

Nicht so.
Es ist nicht falsch

  if( Zeichen == '2' )

zu schreiben. Das ist wesentlich selbstdokumentierender als

  if( Zeichen == 50 )  // war das eine ASCII '2'

zu schreiben

von Karl H. (kbuchegg)


Lesenswert?

Jörg B. wrote:
> Patrick wrote:
>> Was Du auch noch beachten solltest, ist dass die Zahl wirklich Dezimal
>> daher kommt und nicht etwa im ASCII-Code.
> Warum?
> Ob ich jetzt auf ==0 oder =='0' abfrage ist doch eigentlich egal...

Äh. Nein. Das ist nicht egal.
Das eine mal wird gegen den Zahlenwert 0 geprüft,
das andere mal wird gegen den ASCII Code von '0'
geprüft.


von Bastler (Gast)


Lesenswert?

Hallo,
danke schon mal für die viele Hilfe,
ich habe euch mal den Code gepostet, den ich geschrieben habe.
Leider funktioniert das ganze noch nicht mit der LED.
Ich nutze die funktion atoi() ist das falsch oder frage ich an der 
falschen Stelle ab?

Hier der Code:

#include <stdint.h>
#include <avr/io.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>

#ifndef F_CPU
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */
#endif
#define length 100  //Textlänge ab welcher Empfangen beendet wird


void uart_putc(unsigned char c)
{
    while (!(UCSR1A & (1<<UDRE1))) {}  // warten bis Senden möglich
    UDR1 = c;                         // Zeichen senden
}

void uart_puts (char *s)
{

  while (*s)          //Sende solange *s ungleich dem Sting Endezeichen 
ist
  {
    uart_putc(*s);
    s++;
  }
}

unsigned char uart_getc(void)
{
    while (!(UCSR1A & (1<<RXC1))) {} // warten bis Zeichen verfügbar
    return UDR1;                    // Zeichen aus UDR zurueckgeben
}



int main (void)
{

DDRB= 0xff;    //Ganzen Port B als Ausgang setzten
PORTB= 0xff;  //LED'S ausschalten

UBRR1L  = 11;                           // Lowbyte ist 11 ( dezimal ) 
ergibt 19,2k bei 3,7Mhz Clocktakt
UCSR1B |=  (1 << TXEN1)|(1 <<RXEN1);  // UART TX und RX einschalten 
(Sendebereit und Empfangsbereit machen)
UCSR1C |= (( 1<<UCSZ11 )|(1<<UCSZ10));  // Asynchron modus Character 
Size 8-bit,2 Stopbit, kein Parity
UBRR1H  = 0;               //Highbite sicher auf 0 setzten damit 
Übertragungsrate stimmt

  uint8_t i;
  int zahl;
 // int test=5;
  char c;
  char* s;
  char string[length+1];


while(1)
{
 zahl=atoi (string);

  if (zahl==4)
{
  PORTB &= ~(1<<PB4);
}
  s=string;
  i=0;

  do
  {
    c=uart_getc();
    if (c!='\r')
     {
      *s=c;
      uart_putc( c );
    s++;
    i++;
     }
  }
  while( i!=length && c!='\r');
  *s=0;

  uart_puts( "\r\n" );
  uart_puts( "eingegebender Text: " );
  uart_puts( string );
  while (!(UCSR1A & (1<<UDRE1))) {}
    uart_puts( "\r\n" );





}

return 0;
}

von Bastler (Gast)


Lesenswert?

Ich hab jetzt mal folgendes versucht:

zahl = uart_getc();

if (zahl=='4')
{
  PORTB &= ~(1<<PB4);

}


Somit kann ich die 4. LED zwar einschlalten, leider aber nur, wenn das 
erste übertragene Zeichen eine 4 gewesen ist. Wenn ich vorher bsp. eine 
6 oder Hallo übertragen habe, dann geht es nicht mehr?!?! Wie bekomm ich 
das in den Griff? Sicher nur ein paar Zeilen oder?

von Johannes M. (johnny-m)


Lesenswert?

Du musst erst mal überprüfen, ob das empfangene Zeichen eine Ziffer 
zwischen 0 und 7 ist.
1
if((zahl >= '0') && (zahl <= '7'))
2
{
3
    //Code
4
}
Nur wenn die Bedingung erfüllt ist, darf die entsprechende LED 
eingeschaltet werden. Und dann kommt das erste Codebeispiel von Karl 
Heinz zum tragen (wobei ich mich frage, ob Du das überhaupt zur Kenntnis 
genommen hast...).

von Bastler (Gast)


Lesenswert?

Das ist mir klar, allerdings ändert das nichts daran, das immer nur das 
erste Zeichen eine Zahl sein muss, jedes weitere Zeichen wird nicht mehr 
beachtet, da der Sting nicht durchgezählt wird, wie ich eben schon oben 
beschrieben habe.
Geb ich ne 5 ein, so reagiert zwar jetzt die fünfte LED, jedoch geb ich 
als nächstes eine 3 ein, so passiert nix mehr, geschweigedenn wenn ich 
vor der 5 noch ein Hallo eingegeben habe, dann bekommt man keine LED zum 
leuchten!
Das ist das Problem!

von Karl H. (kbuchegg)


Lesenswert?

Mal ne blöde Zwischenfrage: Wozu sammelst du
die Zeichen in einem String?

Warum nicht einfach so
1
  while( 1 ) {
2
3
    c = uart_getc();
4
5
    if( c >= '0' && c <= '7' ) {
6
      c = c - '0';    // aus dem ASCII Code die Ziffer machen
7
      PORTB = 0xFF;      // alle anderen LED aus
8
      PORTB &= ~( 1 << c );
9
    }
10
  }

Ist doch viel simpler als der ganze Klimbim, den du da
mit String zusammensuchen und atoi treibst.

von Bastler (Gast)


Lesenswert?

Hallo Karl Heinz, genauso mach ich es inzwischen auch schon, 
funktioniert aber leider eben nicht genau so wie ich es gerne hätte.
Ich kann zwar eine LED einschalten, aber das wars auch schon , eine 
Zweite geht nicht mehr und wenn vor einer Zahl ein anderes Zeichen 
gesendet wurde, bekomme ich keine zum einschalten.
Ich muss irgendwie die Variable zahl nach jedem Return löschen und neu 
bschreiben lassen sonst bekomme ich das nicht in den Griff oder? Wie 
mach ich das?
Hier is mein Code:

zahl = uart_getc();

if ((zahl >= '0') && (zahl<= '7'))            //Wir deine Zahl zwischen 
0 und 7 eingegeben?
{
  uint8_t NrLed;                    //Hilfsvariable int
  NrLed = zahl - '0';
  PORTB = 0xff;                        // alle anderen LED aus
  PORTB &= ~(1 << NrLed);                //Entsprechende LED einschalten
}

von Karl H. (kbuchegg)


Lesenswert?

Aber zurück zu deinem Problem.
Ich denke der Fehler liegt hier
1
  do
2
  {
3
    c=uart_getc();
4
    if (c!='\r')
5
     {
6
      *s=c;
7
      uart_putc( c );
8
    s++;
9
    i++;
10
     }
11
  }
12
  while( i!=length && c!='\r');
13
  *s=0;

Abhängig von deinem Terminal schickt das am Zeilenende
nicht nur \r, sondern auch einen \n. Und ich vermute
mal die Reihenfolge ist: Zuerst der \r und dann der \n.

Da du den \n aber nicht ausfilterst, landet der im String
und damit beginnt der String mit einem \n woraufhin
atoi mit diesem String nichts mehr anfangen kann, da
der ja nicht mit einer Ziffer (oder Vorzeichen) beginnt
sondern mit \n

von Karl H. (kbuchegg)


Lesenswert?

Bastler wrote:

> Ich kann zwar eine LED einschalten, aber das wars auch schon , eine
> Zweite geht nicht mehr und wenn vor einer Zahl ein anderes Zeichen
> gesendet wurde, bekomme ich keine zum einschalten.
> Hier is mein Code:
>
> zahl = uart_getc();
>
> if ((zahl >= '0') && (zahl<= '7'))            //Wir deine Zahl zwischen
> 0 und 7 eingegeben?
> {
>   uint8_t NrLed;                    //Hilfsvariable int
>   NrLed = zahl - '0';
>   PORTB = 0xff;                        // alle anderen LED aus
>   PORTB &= ~(1 << NrLed);                //Entsprechende LED einschalten
> }

Das ist nicht der komplette Code.
Zeig mal die vollständige main()


von Bastler (Gast)


Lesenswert?

Aber gerne, hier ist sie:

int main (void)
{

DDRB= 0xff;    //Ganzen Port B als Ausgang setzten
PORTB= 0xff;  //LED'S ausschalten

UBRR1L  = 11;                           // Lowbyte ist 11 ( dezimal ) 
ergibt 19,2k bei 3,7Mhz Clocktakt
UCSR1B |=  (1 << TXEN1)|(1 <<RXEN1);  // UART TX und RX einschalten 
(Sendebereit und Empfangsbereit machen)
UCSR1C |= (( 1<<UCSZ11 )|(1<<UCSZ10));  // Asynchron modus Character 
Size 8-bit,2 Stopbit, kein Parity
UBRR1H  = 0;               //Highbite sicher auf 0 setzten damit 
Übertragungsrate stimmt

  uint8_t i;
  int zahl;
 // int test=5;
  char c;
  char* s;
  char string[length+1];


while(1)
{

  s=string;
  i=0;

zahl = uart_getc();

if ((zahl >= '0') && (zahl<= '7'))            //Wir deine Zahl zwischen 
0 und 7 eingegeben?
{
  uint8_t NrLed;                    //Hilfsvariable int
  NrLed = zahl - '0';
  PORTB = 0xff;                        // alle anderen LED aus
  PORTB &= ~(1 << NrLed);                //Entsprechende LED einschalten
}



  do
  {
    c=uart_getc();
    if (c!='\r')
     {
      *s=c;
      uart_putc( c );
    s++;
    i++;
     }
  }
  while( i!=length && c!='\r');
  *s=0;

  uart_puts( "\r\n" );
  uart_puts( "eingegebender Text: " );
  uart_puts( string );
  while (!(UCSR1A & (1<<UDRE1))) {}
    uart_puts( "\r\n" );





}

return 0;
}


Ihr armen müsst echt eine Engelsgedult mit mit haben sry....

von Karl H. (kbuchegg)


Lesenswert?

Bastler wrote:

Welchen Teil von
1
  while( 1 ) {
2
3
    c = uart_getc();
4
5
    if( c >= '0' && c <= '7' ) {
6
      c = c - '0';    // aus dem ASCII Code die Ziffer machen
7
      PORTB = 0xFF;      // alle anderen LED aus
8
      PORTB &= ~( 1 << c );
9
    }
10
  }

hast du nicht verstanden?
Das ist bereits die komplette main-Hauptschleife, schmeiss
den ganzen Klimbim mit String-Zusammenwarten raus.
Da ist irgendwo ein Wurm drinn.

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger wrote:
> Da ist irgendwo ein Wurm drinn.

Bzw. da läuft schon wieder das \r \n Problem auf.
Du wartest zwar schön, bis der String komplett ist,
dann kommt irgendwann der \r und du stellst den String
fertig, und gibst ihn aus.
Aber dann: Vom Terminal kommt als nächstes der \n
Der wird dann aber erst hier

> while(1)
> {
>
>   s=string;
>   i=0;
>
>   zahl = uart_getc();

von der Schnittstelle abgeholt und da das keine Ziffer ist,
passiert auch nichts mehr.

Wie gesagt: Schmeiss die komplette String Verarbeitung raus.
Du brauchst sie für diese Aufgabenstellung nicht. Oder aber
alternativ sorge dafür, dass dir ein \n nicht in die Quere
kommt.






von Bastler (Gast)


Lesenswert?

Die Sting Verarbeitung würde ich gerne lassen, so gibt mir der 
Controller wenigstens immer die eingegebenen Zeichen an das Terminal 
zurück.
Naja dann werde ich mal schauen wie ich das trotzdem in den Griff 
bekommen.
Vielen Dank trotzem euch allen.

von Karl H. (kbuchegg)


Lesenswert?

Bastler wrote:
> Die Sting Verarbeitung würde ich gerne lassen, so gibt mir der
> Controller wenigstens immer die eingegebenen Zeichen an das Terminal
> zurück.

Das tut er so auch:
1
  while( 1 ) {
2
3
    c = uart_getc();
4
    uart_putc( c );
5
6
    if( c >= '0' && c <= '7' ) {
7
      c = c - '0';    // aus dem ASCII Code die Ziffer machen
8
      PORTB = 0xFF;      // alle anderen LED aus
9
      PORTB &= ~( 1 << c );
10
    }
11
  }

Aber ok, wenn du das zeilenweise verarbeiten willst (weil
du ev. irgendwann zu einer Art Commandline kommen willst),
dann wirst du nicht umhin kommen, dich um das \n zu
kümmern.

Tip: Wenn du mit Sicherheit weist, dass dein Terminal
immer die Sequenz \r\n bei einem Return schickt, dann
ist das relativ einfach zu brücksichtigen: Die Funktion
uart_getc() ignoriert ganz einfach den \n
1
unsigned char uart_getc(void)
2
{
3
  char c;
4
5
  do {
6
    while (!(UCSR1A & (1<<RXC1))) {} // warten bis Zeichen verfügbar
7
    c = UDR1;                    // Zeichen aus UDR zurueckgeben
8
  } while( c == '\n' );
9
10
  return c;
11
}

aber wehe, du gerätst dann mal an ein Terminal, welches gar keinen
\r und nur \n schickt :-)

von Karl H. (kbuchegg)


Lesenswert?

Noch ein Tipp:
lagere wenigstens den ganzen 'Warte auf eine komplette Zeile-Teil'
in eine eigene Funktion aus.

a) braucht man das sowieso häufig
b) wird dadurch die Hauptschleife kürzer und übersichtlicher
c) kannst du dich dann mal fragen, wie es eigentlich sein
   kann, dass du in deiner Hauptschleife schon einen Befehl
   auswertest, noch bevor du ihn empfangen hast :-)

von Bastler (Gast)


Lesenswert?

Ob mein Terminalprogramm das immer so macht, weiß ich leider nicht das 
Programm heißt Terminal v1.9b by bray
Das Programm ist eigentlich ganz gut, allerdings wie es genau sendet, 
keinen Plan.
Danke Für deine Tips, Du bist echt voll der Checker, vielleicht kann ich 
irgendwann in 100 fernen Jahren auch mal so gut programmieren wie Du :-)

von Karl H. (kbuchegg)


Lesenswert?

Bastler wrote:
> Ob mein Terminalprogramm das immer so macht, weiß ich leider nicht das
> Programm heißt Terminal v1.9b by bray

Das Problem besteht darin, dass Terminals (und auch Terminal-
simulationen) normalerweise konfigurierbar sind, wie sie
Return behandeln sollen.

> Das Programm ist eigentlich ganz gut, allerdings wie es genau sendet,
> keinen Plan.

Für solche Zwecke ist es immer gut, wenn man ein kleines
Testprogramm in petto hat, welches exakt jedes Zeichen,
aber auch wirklich jedes Zeichen, in lesbarer Form mit-
protokolliert. Das heist dann auch: anstelle von \n muss
die Ausgabe dann '\\' 'n' lauten, anstelle von \r kommt '\\' 'r'
und anstelle von \t kommt '\\' 't'.
So dass man exakt mitlesen kann welche Zeichen nun wirklich über
die Schnittstelle in welcher Reihenfolge kommen.
1
int main()
2
{
3
  ....
4
5
  while( 1 ) {
6
7
    c = uart_getc();
8
9
    if( c == '\n' )
10
      uart_puts( "\\n" );
11
 
12
    else if( c == '\r' )
13
      uart_puts( "\\r" );
14
15
    else if( c == '\t' )
16
      uart_puts( "\\t" );
17
18
    else
19
      uart_putc( c );
20
  }
21
}

Damit kannst du dann ganz leicht untersuchen, was denn nun
wirklich gesendet wird (die restlichen Sonderzeichen kleiner
als Leerzeichen im ASCII Code muesste man noch behandeln)
und mal überlegen, wie dein Programm darauf reagiert.

Ja: manchmal muss man sich Debug-Hilfsmittel selbst bauen
um dahinter zu kommen, was da eigentlich passiert.

von Bastler (Gast)


Lesenswert?

Hey Karl Heinz,

kann das wirklich sein, das mein Terminal garkein \n und \r schickt?
Hab gerade mal dein Testprogramm ausprobiert. Ich bekomme immer genau 
das zurück geliefert, was ich eingebe, aber nie ein \\r oder \\n obwohl 
ich Strings eingebe und auch Return drücke... Kann das sein?

von Karl H. (kbuchegg)


Lesenswert?

Bastler wrote:
> Hey Karl Heinz,
>
> kann das wirklich sein, das mein Terminal garkein \n und \r schickt?
> Hab gerade mal dein Testprogramm ausprobiert. Ich bekomme immer genau
> das zurück geliefert, was ich eingebe, aber nie ein \\r oder \\n obwohl
> ich Strings eingebe und auch Return drücke... Kann das sein?

Glaub ich nicht.
Eines von beiden (oder alle beide) müssten kommen.


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.