Forum: Mikrocontroller und Digitale Elektronik UART LED anschalten und halten


von André (Gast)


Lesenswert?

Hallo zusammen

Ich hab nen Problem mit der UART-Schnittstelle bei einem Mega8. Ich will 
vom Rechner ein Zeichen senden (also 8bit) und wenn der Controller 
dieses empfängt, soll er eine LED an PortC anschalten.
Geht auch alles, nur bleibt die LED nicht an. Er empfängt, die LED 
blitzt auf und geht wieder aus und ich weiß nicht warum.
Wenn ich die zweite While-Schleife wegnehme, bleibt die LED an, wenn 
aber was empfängt, gehts kurz an und wieder aus, das macht keinen Sinn 
finde ich. Wenn der Port einmal auf 1 gesetzt wurde, bleibt er doch auf 
1, da er ja nirgendwo auf 0 setzt.

Hier erstmal der Code:
1
#include  <avr\io.h>    
2
//----------------------------------------------------------------------
3
4
int main ( void )
5
       {
6
  DDRC=0x01;
7
8
  UCSRA=0x00;
9
  UCSRB=0x10;  //receiver
10
  UCSRC=0x86;  //8bit 1stop
11
  UBRRH=0x00;
12
  UBRRL=0x19;  //Baud 9600 bei 4MHz Takt
13
14
  while (1)
15
    {
16
17
           while (((UCSRA >> RXC) & 1) ==0)
18
               {}
19
20
     PORTC = 0x01; 
21
    }
22
23
  return 0;
24
       }

Bitte entschuldigt die komische Frage, aber ich komm einfach nicht 
weiter an dem Punkt und hoffe ihr könnt mir helfen. Vielen Dank schonmal

Viele Grüße
André

von Hubert G. (hubertg)


Lesenswert?

Watchdog eingeschalten, macht der µC ein Reset?

von Moritz (Gast)


Lesenswert?

Was steht denn im Datenregister drin?

Gruß

von willi (Gast)


Lesenswert?

ich würde ja fast wetten, dass die LED leuchtet wenn der entsprechende 
ausgangspin auf 0 ist

von André (Gast)


Lesenswert?

An der 0 kann es nicht liegen, wenn ich "while (((UCSRA >> RXC) & 1) 
==0)" wegnehme, dann geht die LED an und bleibt es auch.
Kann es sein, dass es einen Reset gibt, sobald wieder oben in die 
while(1)-schleife gegangen wird?
Der watchdog ist doch standartmäßig aus oder? ich hab ihn jedenfalls 
nicht wissendlich angeschaltet.
Was im Emfangsregister steht, ist mir erstmal egal, ich will nur 
unterscheiden, ob was drin steht, oder nicht. Wenn was drin steht, soll 
er die LED anschalten und sie soll an bleiben.

nochmal eine andere Idee Code, vllt wird dann eher klar, wo mein Problem 
liegt:
1
  while(1)
2
  {
3
         if (UDR !=0x00)
4
         PORTC = 0x01;
5
   }

von Karl H. (kbuchegg)


Lesenswert?

Find erst mal raus, ob dein µC ungewollt resettet.

Häng an einen 2.ten Pin noch eine Led.
In main schaltest du die LED ein, wartest ein Weilchen und schaltest sie 
wieder aus
1
#define F_CPU 4000000
2
#include <avr\io.h> 
3
#include <util\delay.h>
4
5
//----------------------------------------------------------------------
6
7
int main ( void )
8
{
9
  DDRC=0x03;
10
11
  PORTC |= 0x02;
12
  _delay_ms( 1000 );
13
  PORTC &= ~0x02;
14
15
  UCSRA=0x00;
16
  UCSRB=0x10;  //receiver
17
  UCSRC=0x86;  //8bit 1stop
18
  UBRRH=0x00;
19
  UBRRL=0x19;  //Baud 9600 bei 4MHz Takt
20
21
  ...

Wenn diese LED nach dem Programmstart ein zweites mal blinzelt, hat dein 
µC zwischendurch einen Reset gemacht.

von Hubert G. (hubertg)


Lesenswert?

Watchdog ist standardmässig ein. Den musst du mit den Fuses ausschalten.

von Karl H. (kbuchegg)


Lesenswert?

Hubert G. schrieb:
> Watchdog ist standardmässig ein.

Das wär mir neu

von Hubert G. (hubertg)


Lesenswert?

Ist richtig, WDTON ist  nicht ein, da habe ich mich vom Fuse-Calculator 
verleiten lassen.

von André (Gast)


Lesenswert?

Ok, das mit der Pin hab ich gemacht, aber das delay mag er nicht. er 
schaltet die LED an, aber nicht wieder aus.
Der fehler muss bei der zweiten while schleife liegen, die muss 
irgendwie den Port zurücksetzen auf den wert, der vor aufruf da war.
irgendwie macht das alles keinen sinn ... :S

von Andy H. (vinculum) Benutzerseite


Lesenswert?

wo führt dein return hin, wenn nix auf dem stack liegt?

von Karl H. (kbuchegg)


Lesenswert?

André schrieb:
> Ok, das mit der Pin hab ich gemacht, aber das delay mag er nicht. er
> schaltet die LED an, aber nicht wieder aus.

Ich bin mal davon ausgegangen, dass deine LED bei einer 1 am 
Port-Ausgang angehen. Meistens allerdings macht man es genau anders rum.

> Der fehler muss bei der zweiten while schleife liegen, die muss
> irgendwie den Port zurücksetzen auf den wert, der vor aufruf da war.

Das tut sie mit Sicherheit nicht.

> irgendwie macht das alles keinen sinn ... :S

Du sagst es.

Bist du absolut, 100% sicher, dass bei dir die LED angehen, wenn der 
Portpin auf 1 gesetzt wird?

von sam (Gast)


Lesenswert?

ich würde dir empfehlen erstmal die korrekte funktion deiner serriellen 
verbindung zu testen:
auf zeichen auf der usart warten und per usart wieder zurücksenden ... 
mit einem terminalprogramm (z.b. HTerm) kannst du dann sicherstellen , 
dass der mega8 überhaupt was empfängt etc.

dann würde ich im mainloop einfach die empfangenen zeichen auswerten 
(per if oder switch) und z.b. bei 'a' ein ausgang togglen : PORTB=PORTB 
^ 0xFF;
und dazu noch ein echo zurück an den pc senden.

und was mich dann noch stört: bevor PORTC dann auf 0x01 gesetzt wird ist 
er quasi undefiniert (eigentlich sollte er immer 0x00 sein, aber da du 
ihm das nie gesagt hast, kannst du dir nicht sicher sein)

in der C-programmierung gibt es doch auch eine warnung wenn man 
nichtinitialisierte variablen benutzt, weil man den inhalt eben nicht 
kennt.

von André (Gast)


Lesenswert?

Hallo, da bin ich wieder. Hab jetzt ne Weile experimentiert und mir 
einiges durchgelesen und einiges klappt und das eigentlich gewollte 
immernoch nicht.

Ich hab mir einen Beispielquellcode aus dem Internet geladen, was per 
UART ein Byte empfängt und wieder zurücksendet. Das macht er, aber nicht 
immer, manchmal kommt quatsch, ich denke, wenn ich zu schnell 
hintereinander sende. Er empfängt aber auch das richtige, Einstellung 
müssten also stimmen.

Was aber immernoch nicht geht, egal ob LED bei 0 oder bei 1 an sein 
soll, ist das Halten des Status. Er setzt immer wieder zurück, ich weiß 
nicht warum.

Hier mal der Text, bei 0 soll die LED jetzt an sein:
1
#define OSCSPEED  4000000    /* in Hz */
2
3
#include "avr/io.h"
4
5
void Initialize(void)
6
{
7
  PORTB = 0x0;
8
  PORTC = 1<<2;  /* turn the LED off */
9
  PORTD = 0x0;
10
11
  DDRB = 0x0;
12
  DDRC = 1<<2;    /* PC2 as output - the LED is there */
13
  DDRD = 0x0;
14
15
}
16
17
void InitUART(uint32_t baud)  /* here a simple int will not suffice*/  
18
{
19
  int baudrate=(OSCSPEED/(16*baud))-1; /* as per pg. 133 of the user manual */
20
  /* Set baud rate */
21
  UBRRH = (unsigned char)(baudrate>>8);
22
  UBRRL = (unsigned char)baudrate ;
23
  /* Enable Receiver and Transmitter */
24
  UCSRB = (1<<RXEN)|(1<<TXEN);
25
  /* Set frame format: 8data, 1stop bit */
26
  UCSRC = (1<<URSEL)|(3<<UCSZ0);
27
  
28
}
29
30
unsigned char UARTReceive(void)
31
{
32
  if (UCSRA & (1<<RXC))
33
    return UDR;
34
  else  /* no data pending */
35
    return 0;
36
}
37
38
void UARTTransmit(unsigned char data)
39
{
40
  while (!( UCSRA & (1<<UDRE)) );
41
  /* Put data into buffer, sends the data */
42
  UDR = data;
43
}
44
45
int main(void)
46
{
47
  unsigned char ch;
48
  Initialize();
49
  InitUART(9600);
50
51
  while (1)
52
  {
53
    ch=UARTReceive();
54
    if (ch==0x41)
55
       PORTC &= ~(1<<2);
56
57
    if (ch)
58
    {
59
      UARTTransmit(ch);
60
    }
61
62
  }
63
  return 0;
64
}
Wann kann es denn allgemein sein, dass der Controller resetet? Wenn ich 
sonst den PORT setze, bleibt er doch auch.

Viele Dank aber schonmal für die ganzen Vorschläge und natürlich auch 
vorab vielen Dank :)

Grüße
André

von STK500-Besitzer (Gast)


Lesenswert?

1. Frage die sich mir stellt:
Woher kommt der Takt? Sind die Fuses richtig gesetzt (ist zwar eine 
zweite Frage, hängt aber mit demTaktproblem zusammen).

2. Findet der Kommunikationsabbruch in regelmäßigen Abständen statt? 
(Watchdog immer noch an?)

3. Wieso machst du dein Programm so unnötig kompliziert?
1
#define OSCSPEED  4000000    /* in Hz */
2
#define baudrate=(OSCSPEED/(16L*baud))-1; /* as per pg. 133 of the user manual */
3
4
#include "avr/io.h"
5
6
void Initialize(void)
7
{
8
  PORTB = 0x0;
9
  PORTC = 1<<2;  /* turn the LED off */
10
  PORTD = 0x0;
11
12
  DDRB = 0x0;
13
  DDRC = 1<<2;    /* PC2 as output - the LED is there */
14
  DDRD = 0x0;
15
16
}
17
18
void InitUART(uint32_t baud)  /* here a simple int will not suffice*/  
19
{
20
21
  /* Set baud rate */
22
  UBRRH = (unsigned char)(baudrate>>8);
23
  UBRRL = (unsigned char)baudrate ;
24
  /* Enable Receiver and Transmitter */
25
  UCSRB = (1<<RXEN)|(1<<TXEN);
26
  /* Set frame format: 8data, 1stop bit */
27
  UCSRC = (1<<URSEL)|(3<<UCSZ0);
28
  
29
}
30
31
32
int main(void)
33
{
34
  unsigned char ch;
35
  Initialize();
36
  InitUART(9600);
37
38
  while (1)
39
  {
40
    while (!(UCSRA & (1<<RXC))); // Warten bis ein Zeichen eingetroffen ist
41
    ch=UDR;
42
    if (ch==0x41) // Empfangenes Zeichen ist eine '1' (*)
43
       PORTC &= ~(1<<2);
44
  
45
    while (!( UCSRA & (1<<UDRE)) ); // auf leeren Sendepuffer warten
46
    UDR = ch; // Zeichen versenden
47
    }
48
49
  }
50
  return 0;
51
}

Sollte völlig reichen.
Die mit (*) markierte Zeile kann man auch auskommentieren, was zu einem 
Blinken der LED bei jeden empfangenen Zeichen führt.

von André (Gast)


Lesenswert?

zu 1:
Der Takt kommt von einem Quarz, 4MHz zwischen PB6 und PB7 und von jedem 
nen 22pF Kondensator gegen Masse. Die Fuses hab ich mit "myAVR Workpad" 
eingestellt. Ich hab "Ext. Crystal/Resonator High Freq.; Start-up time: 
258 CK + 4 ms" gewählt, hab ich irgendwo so gelesen. Der berechnet die 
Fusebits dann, kam raus: Low Fuse (0xCE)  High Fuse (0x99) Lockbits 
(0xFF)
Könnt ihr damit was anfangen? Mir wäre es auch lieber, wenn ich 
verstehen würde, was ich da machen lasse. Ich wollte aber nichts kaputt 
machen ...

zu 2. Watchdog war nie an bzw nie wissentlich angemacht. Hab schon 
versucht, nen System zu erkennen, aber ich finde keins, wann es nicht 
richtig geht.

Zu 3. Du meintest, wenn ich "if (ch == 0x41)" weglasse, blinkt er beim 
Empfangenen aus ... das ist ja genau mein Problem. Das will ich nicht, 
die Lampe soll an bleiben. Weil ich setze doch den Port und sage 
nirgendwo, dass wenn er nichts empfängt, er den Port zurückschalten 
soll.
Ich will den Controller letztendlich als Steuereinheut einsetzen, ich 
sende ihm z.b. ein "E" und er schaltet eine Lampe ein und wenn ich ihm 
irgendwann ein "A" sende, geht die Lampe wieder aus. Aber das geht ja 
nur, wenn der PORT nach dem Empfangen auch so bleibt wie ich ihn setze.
Versteht ihr was ich meine und vorhabe? :)

Danke für die Geduld

von Karl H. (kbuchegg)


Lesenswert?

André schrieb:

> nur, wenn der PORT nach dem Empfangen auch so bleibt wie ich ihn setze.
> Versteht ihr was ich meine und vorhabe? :)

Ja.
Wenn es auf deinem System mit deinem Programm so ist, dass die LED beim 
empfang eines Zeichens an geht und kurz darauf wieder aus, dann hast du 
ein Hardwareproblem. Das hat nichts mit deinem µC (ausser wenn der 
defekt wäre, was aber unwahrscheinlich ist) oder dem Programm zu tun.

Hier sind wir raus. Dein Hardwareproblem können wir so nicht lösen, da 
musst du ran. Mal die üblichen Verdächtigen abklopfen. 
Versorgungsspannung, Blockkondensatoren etc.

von Marco -. (Gast)


Lesenswert?

Hallo
ich möchte über USART zeichen empfangen und auswerten. USART 
fukntioniert auch soweit aber ich hab ein Problem mit der Funktion 
"test". Komischerweise wird die LED nur dann eingeschaltet wenn ich in 
der if-abfrage eine andere Funktion aufrufe oder eine Verzögerungszeit 
drin habe, die größer als 90 ms ist. Beim Ausschalten gibts keine 
Probleme. Hat jemand eine Idee woran das liegen könnte?
Danke im Voraus.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include "uart.h"
5
6
void init ( void );
7
void test( uint8_t data );
8
uint8_t temp;
9
10
11
12
int main(void){
13
14
  cli();              /* disable interrupt */
15
  init();              /* init ports, baudrate */
16
  sei();              /* enable interrupt */
17
18
  while(1){
19
    test(temp);
20
  }
21
  
22
  return 0;
23
}
24
25
26
27
ISR(USART_RX_vect){
28
  
29
  unsigned char receive;
30
  
31
  if(UDR == 0x73){          /* "s" command */
32
            
33
    receive = USART_Receive();
34
    
35
    if(receive == 0x61)        /* "a" command */  
36
      temp = 1;  
37
    
38
    if(receive == 0x62)        /* "b" command */  
39
      temp = 2;  
40
41
    if(receive == 0x63)        /* "c" command */
42
      temp = 3;
43
  }
44
}
45
46
47
48
void init( void ){
49
  DDRB = 0xff;
50
  PORTB = 0xff;
51
  
52
  /* baudrate 19200 using a 8MHz crystal */
53
  USART_Init(25);        
54
55
  temp = 0;
56
57
}
58
59
60
void test(uint8_t data){
61
62
  if (data == 1){
63
  //  USART_Transmit('a');
64
    PORTB &= ~(1<<PB0);
65
  //  _delay_ms(100);
66
  }
67
68
  if (data == 3){
69
    PORTB |= (1<<PB0);
70
  }
71
}

von Falk B. (falk)


Lesenswert?

Siehe Interrupt, Stichwort volatile.

von aaaaa (Gast)


Lesenswert?

stack in ordnung?

von gadgaet (Gast)


Lesenswert?

Hast du die LED direkt an den µC angeschlossen? Mir ist es schonmal 
passiert, dass an der LED zu viel Strom fließt und der µC deswegen 
"abstürzt". Liegt es vllt. daran?

An wie vielen Stellen im Code wird das Ausgangsregister neu gesetzt? 
Kann es sein, dass das Bit für die LED aus Versehen gelöscht wird?

grüssse
g.

von Marco -. (Gast)


Lesenswert?

volatile hats gebracht
danke

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.