Forum: Mikrocontroller und Digitale Elektronik ATMega8A LED blinkt statt konstantes Lechten


von Bert S. (kautschuck)


Lesenswert?

Hi,
Ich arbeite mich ein bisschen in AVR gcc ein und verwende das AVR 
Studio. Ich habe eine LED über einen Transistor angeschlossen, dass 
ganze wird über den Port PB0 angesteuert. Als Eingang zum wechseln des 
Modus (LED leuchtet  = 1 bzw. leuchtet nicht = 0) verwende ich einen 
Taster mit Pull Up Pfad am Eingang PD0. Wenn ich den Taster drücke, 
wechselt die LED den Modus, doch wenn die LED in den Modus 1 geht,blinkt 
sie, im Modus 0 ist sie konstant aus. Ich habe keine Ahnung woher das 
blinken kommt. Die Frequenz ist unabhängig vom sleep() und etwa 3Hz.

Hier noch mein Code:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdio.h>
4
void sleep( uint8_t ms );
5
uint8_t key_pressed (volatile uint8_t *inputreg, uint8_t inputbit);
6
7
int main(void)
8
{
9
  int x = 1000;
10
    DDRB  = 0xFF;             // (3)
11
  DDRD  = 0x00;
12
    PORTB = 0x01;             // (4)
13
    
14
    while(1) {  
15
    sleep(20); 
16
    uint8_t i = key_pressed (&PIND, PD0);
17
    if(i == 1) {
18
      PORTB ^= ( 1 << PB0 ); 
19
    }  
20
   }                         // (7)
21
   return 0;  
22
}
23
24
void sleep ( uint8_t ms )
25
{
26
    for(ms ; ms > 0; ms--) _delay_ms(1);
27
}
28
29
uint8_t key_pressed (volatile uint8_t *inputreg, uint8_t inputbit)
30
{
31
  static uint8_t last_state = 0;
32
  if (last_state == (*inputreg & (1<<inputbit)))
33
    return 0; /* keine Änderung */
34
  
35
  /* Wenn doch, warten bis etwaiges Prellen vorbei ist: */
36
  _delay_ms(20);
37
  
38
  /* Zustand für nächsten Aufruf merken: */
39
  last_state = *inputreg & (1<<inputbit);
40
  
41
  /* und den entprellten Tastendruck zurückgeben: */
42
  return *inputreg & (1<<inputbit);
43
}

Gruss Bert

: Verschoben durch Admin
von aha! (Gast)


Lesenswert?

Bert Siegfried schrieb:
>  Lechten

wird wohl nur ein Schreibfehler sein!

von Rolf (Gast)


Lesenswert?

Bert Siegfried schrieb:

>
1
uint8_t key_pressed (volatile uint8_t *inputreg, uint8_t inputbit)
2
{
3
  static uint8_t last_state = 0;
4
  if (last_state == (*inputreg & (1<<inputbit)))
5
    return 0; /* keine Änderung */
6
  
7
  /* Wenn doch, warten bis etwaiges Prellen vorbei ist: */
8
  _delay_ms(20);
9
  
10
  /* Zustand für nächsten Aufruf merken: */
11
  last_state = *inputreg & (1<<inputbit);
12
  
13
  /* und den entprellten Tastendruck zurückgeben: */
14
  return *inputreg & (1<<inputbit);
15
}
Die Funktion wird immer nur genau 1 mal ausgeführt, dabei ist last_state 
am Anfang immer 0.
Deine Variable last_state ist lokal zur Funktion, sie wird bei jedem 
Aufruf der Funktion neu deklariert und mit 0 initialisiert. Daher kann 
sich diese Variable nichts für den nächsten Aufruf der Funktion merken.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Rolf schrieb:
> Deine Variable last_state ist lokal zur Funktion, sie wird bei jedem
> Aufruf der Funktion neu deklariert und mit 0 initialisiert. Daher kann
> sich diese Variable nichts für den nächsten Aufruf der Funktion merken.

 Das stimmt nicht, aber static variables in Funktionen sind (für mich)
 eine schlechte Praxis. Es wird Speicherplatz gebraucht, praktisch wird
 damit eine globale Variable deklariert, Compiler kann auf diese
 Variable nicht so einfach zugreifen, es wird einfach komplizierter. ;-)
 Der einzige Vorteil(?) ist, dass man mehrere Variablen mit denselben
 Namen deklarieren kann.

 Einfacher wäre es, last_state beim Aufruf als Parameter übergeben und
 beim Return zurückgeben.

: Bearbeitet durch User
von Michael L. (michaelx)


Lesenswert?

Das die LED blinkt, liegt doch auf der Hand.
Das hast du selbst programmiert:
1
f(i == 1) {
2
      PORTB ^= ( 1 << PB0 ); 
3
    }

Wenn i == 1 ist, wird PB0 bei jedem Durchlauf negiert.

von Erni (Gast)


Lesenswert?

Hallo Bert,

ich habe auch noch nicht gesehen, warum deine LED blinkt. Jedoch habe 
ich einige Vorschläge bezüglich "Software Engineering":

1.)
Das
>uint8_t i = key_pressed (&PIND, PD0);
>if(i == 1) {
wird dir irgendwann das Genick brechen. Die "1" in der IF Abfrage stimmt 
nur so lange, wie du den Pin 0 eines Ports benutzt. Wenn du jetzt Pin 1 
nehmen würdest, müsstest du PD0 auf PD1 ändern !UND! if(i==1) auf 
if(i==2). Du musst also an zwei Stellen was ändern. Noch ist dein 
Programm überschaubar, aber wenn es größer wird, holst du dir den Teufel 
ins Haus
Mach dir ein Macro á la
#define INPUTBIT_PD0 (1<<PD0)
und verwende das im Code.

2.)
Wenn ich das richtig sehe, macht deine Funktion "key_pressed" etwas 
anderes, als ihr Name impliziert. Ich meine, die Funktion gibt nur 
einmalig eine "1" zurück, wenn der Taster nach einem Drücken den Kontakt 
wieder öffnet. Es ist also keine Abfrage eines Zustandes sondern eher 
ein Signalimpuls in Form eines Rückgabewertes im Falle eines Events.

3.)
Ich finde, du solltest die Variable "last_state" anders nennen. So 
erinnert sie zu stark an ein Argument einer statemachine. Nenn sie z.B. 
"lastKeyState".

4.) Wo ich gerade beim Thema bin, es gibt ein paar Regeln, wie Variablen 
#defines und Co im Quelltext geschrieben werden. Goggle mal nach "The 
Clean Coder"
Variablen fangen z.B. immr mit einem kleinem Buchstaben an, haben 
üblicherweise keine Unterstriche und jedes neue Wort innerhalb der 
Variablen bekommt einen großen Buchstaben. Manche sagen auch, dass z.B. 
lokal definierte Variablen eine Kennzeichung brauchen.
#defines werden durchgehen groß geschrieben.

Gruß,
Erni

von stefanus (Gast)


Lesenswert?

Die LED blinkt weil der Pin bei jedem Schleifendurchlauf invertiert 
wird.
1
while(1) {  
2
    sleep(20); 
3
    uint8_t i = key_pressed (&PIND, PD0);
4
    if(i == 1) {
5
      PORTB ^= ( 1 << PB0 ); 
6
    }  
7
}

Das heist in Pseudosprache frage im 20ms Intervall die Taste ab, und 
wenn sie geerade gedrückt ist, dann schalte die LED um.

Daraus folgt: Solange die Taste gedrückt ist, geht die LED alle 20ms 
abwechselnd an und aus.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

stefanus schrieb:
> Daraus folgt: Solange die Taste gedrückt ist, geht die LED alle 20ms
> abwechselnd an und aus.

 Und wie passen da 3Hz rein ?

von stefanus (Gast)


Lesenswert?

Ich glaube, er hat die key_pressed() funktion nicht so dargestellt, wie 
er sie tatsächloch verwendet. Ansonsten wäre das beschriebene Verhalten 
nicht erklärbar.

Wenn die funktion tut, was ihr Name andeutet, dann ist das Verhalten 
logisch, wegen "PORTB ^= ( 1 << PB0 )".

Wenn die Funktion jedoch tatsächlich so aussieht wie oben, dann hat Erni 
sicher Recht, dann dürfte die LED nicht blinken.

Wobei mich das Tkming nachdenklich stimmt. 20ms and/aus würde ich eher 
als flimmern bezeichnen. Blinken geht langsamer. Also hat wohl auch noch 
ein Problem mit der Taktfrequenz oder vieleicht mit dem Watchdog.

Ich glaube, Bert hat nicht den Quelltext verkürzt und dabei die 
entscheidenden Teile ausgelassen.

von stefanus (Gast)


Lesenswert?

> Und wie passen da 3Hz rein ?

Huch, zwei Dumme ein gedanke. Ist mir auch gerade aufgefallen. Das passt 
gar nicht.

von Thomas E. (thomase)


Lesenswert?

Dein sleep() funktioniert nicht.
Warnings sind nicht zum ignorieren da!

Aber mit _delay_ms(20) geht es.

Auch wenn da ein grosser Bock drin ist:
1
uint8_t i = key_pressed (&PIND, PD0);
2
if(i == 1)

Zufällig macht es hier aber trotzdem das Richtige.

Grundsätzlich aber bitte so:
1
if(key_pressed (&PIND, PD0))
Die Variable kannst du dir auch sparen.

Das Programm ist nicht sonderlich optimal, böse Zungen würden es als 
"Total beschissen" bezeichnen, aber ich bin ja nicht böse.

Immerhin funktioniert es aber. Und das ist ja auch schon mal was.

Deinen Fehler wirst du also woanders suchen müssen. Im Programm findest 
du ihn nicht.

Mögliche Ursachen:

- mit falschem Controller compiliert
- falsches Hexfile
- Hardwarefehler: "Ich habe eine LED über einen Transistor
  angeschlossen," Da schwant mir, ehrlich gesagt, Böses.
  Wenn deine Hardware annähernd aufwändig ist wie dein Programm,
  schaltest du mit dem Transistor eine 2mA-LED.

mfg.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas Eckmann schrieb:
> Das Programm ist nicht sonderlich optimal, böse Zungen würden es als
> "Total beschissen" bezeichnen, aber ich bin ja nicht böse.
 Ich auch nicht, aber...

> Deinen Fehler wirst du also woanders suchen müssen. Im Programm findest
> du ihn nicht.
>
> Mögliche Ursachen:
>
> - mit falschem Controller compiliert
 Oder:
 20ms + 20ms = 40ms
 8MHz compiliert, läuft auf 1MHz
 ergibt:
 40ms * 8 = 320ms = ungefahr 3Hz.

von Michael L. (michaelx)


Lesenswert?

Ups, die 3 Hz hab ich gar nicht gelesen. Nach der Überschrift stach mir 
gleich das ^= ins Auge. Aber Thomas und Marc haben schon den Finger 
drauf ...

: Bearbeitet durch User
von Holger L. (max5v)


Lesenswert?

Marc Vesely schrieb:
> 20ms + 20ms = 40ms
>  8MHz compiliert, läuft auf 1MHz
>  ergibt:
>  40ms * 8 = 320ms = ungefahr 3Hz.

Das hört sich gut an.

Aus delay.h
#ifndef F_CPU
/* prevent compiler error by supplying a default */
# warning "F_CPU not defined for <util/delay.h>"
# define F_CPU 1000000UL
#endif

Entweder die Zeile mit dem define für F_Cpu wurde nicht kopiert, oder 
sie fehlt.

von MWS (Gast)


Lesenswert?

Holger L. schrieb:
> Aus delay.h
> #ifndef F_CPU
> /* prevent compiler error by supplying a default */
> # warning "F_CPU not defined for <util/delay.h>"
> # define F_CPU 1000000UL
> #endif
>
> Entweder die Zeile mit dem define für F_Cpu wurde nicht kopiert, oder
> sie fehlt.

Würde die Delay-Funktion eine niedrigere als die tatsächliche FCPU 
annehmen, so würde das Delay schneller, aber nicht langsamer ausgeführt.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

MWS schrieb:
> Würde die Delay-Funktion eine niedrigere als die tatsächliche FCPU
> annehmen, so würde das Delay schneller, aber nicht langsamer ausgeführt.

 Hmmm.
 Blinkt etwa 8x langsamer, du willst also sagen, dass seine CPU mit
 80MHz läuft ?
 Klingt logisch.

: Bearbeitet durch User
von MWS (Gast)


Lesenswert?

Marc Vesely schrieb:
>  Hmmm.
>  Blinkt etwa 8x schneller, du willst also sagen, dass seine CPU mit
>  80MHz läuft ?
>  Klingt logisch.

Nein, ich sprach davon, dass falls der Delay-Funktion das F_CPU fehlen 
würde und diese 1MHz annimmt, die dann erzeugten Verzögerungsschleifen 
zu kurz ausfallen, wenn die CPU mit tatsächlichen 8MHz läuft.

Ergo, ist dieser Fehlerfall hier unwahrscheinlich. Möglich ist dagegen, 
dass F_CPU auf 8MHz eingestellt ist, die CPU dagegen per Fuse auf 1MHz 
läuft.

Hast Du jetzt verstanden?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

MWS schrieb:
> Ergo, ist dieser Fehlerfall hier unwahrscheinlich. Möglich ist dagegen,
> dass F_CPU auf 8MHz eingestellt ist, die CPU dagegen per Fuse auf 1MHz
> läuft.
>
> Hast Du jetzt verstanden?

 LOL.
 Bist du doof, oder was ?

Marc Vesely schrieb:
> Oder:
>  20ms + 20ms = 40ms
>  8MHz compiliert, läuft auf 1MHz
>  ergibt:
>  40ms * 8 = 320ms = ungefahr 3Hz.

 Hast du Schwierigkeiten beim lesen oder beim Verstehen ?

von Holger L. (max5v)


Lesenswert?

Nein, aber wenn F_CPU nicht eingetragen wurde wird es mit 1 MHz 
berechnet.
Außerdem :
Bert Siegfried schrieb:
> Die Frequenz ist unabhängig vom sleep()

von MWS (Gast)


Lesenswert?

Marc Vesely schrieb:
>  LOL.
>  Bist du doof, oder was ?
>
> Marc Vesely schrieb:
>> Oder:
>>  20ms + 20ms = 40ms
>>  8MHz compiliert, läuft auf 1MHz
>>  ergibt:
>>  40ms * 8 = 320ms = ungefahr 3Hz.
>
>  Hast du Schwierigkeiten beim lesen oder beim Verstehen ?

Mensch, Vaseline, Du hast eine Auffassungsgabe wie 'ne Dose Kekse, 
hältst aber andere für doof?

1) mein erstes Post oben war an Holger L. gerichtet, der annahm, dass 
F_CPU nicht zur Delay-Funktion durchgereicht wurde und deshalb als 
Standard 1MHz setzte. Diese Fehlermöglichkeit hab' ich logisch 
ausgeschlossen.

2) Die von Dir ins Spiel gebrachte mögliche Fehlerquelle hab' ich nicht 
in Frage gestellt, ich hab' sie sogar nochmal bekräftigt, worauf ich von 
Dir dummen Bub blöd angequatscht wurde.

Wenn also jemand Deine These lediglich nochmal wiederholt, so sagt er 
damit nicht, dass diese falsch wäre. Jetzt verstanden?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

MWS schrieb:
> Wenn also jemand Deine These lediglich nochmal wiederholt, so sagt er
> damit nicht, dass diese falsch wäre. Jetzt verstanden?

 LOL.
 Redest du auch so viel wie du schreibst, um nichts zu sagen ?
 Politik studiert ?

von Holger L. (max5v)


Lesenswert?

Ojeh ojeh, so ein schöner Sonntag.

Was haltet ihr von Brown-Out detection und Versorgung mit Batterie ?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Holger L. schrieb:
> Außerdem :
> Bert Siegfried schrieb:
>> Die Frequenz ist unabhängig vom sleep()

Thomas Eckmann schrieb:
> Dein sleep() funktioniert nicht.
> Warnings sind nicht zum ignorieren da!

 Nicht ausprobiert, vertraue Thomas (blind).

von MWS (Gast)


Lesenswert?

Marc Vesely schrieb:
>  LOL.
>  Redest du auch so viel wie du schreibst, um nichts zu sagen ?
>  Politik studiert ?

OK, man kann's Dir leider nicht verständlich machen.
Versuch's nochmal, wenn Dir ein bisserl mehr Hirn gewachsen ist.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Holger L. schrieb:
> Was haltet ihr von Brown-Out detection und Versorgung mit Batterie ?

 In Zusammenhang mit ?

von Holger L. (max5v)


Lesenswert?

In Zusammenhang mit der Led, evtl. genügt diese ja bereits aus um an die 
2,7 V / 4 V Grenze zu kommen.
Eventuell ist es auch der Watch-dog ?

von Thomas E. (thomase)


Lesenswert?

Marc Vesely schrieb:
> 40ms * 8 = 320ms = ungefahr 3Hz.

Das würde die Zeit erklären. Aber nicht, dass es überhaupt blinkt.

Eine Vermutung ist, dass er als Transistor einen dicken Mosfet dran hat, 
der mit seiner Kapazität beim Schalten die Stromversorgung kurz 
zusammenbrechen lässt und nach einem Reset geht es dann wieder von vorne 
los.


mfg.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Holger L. schrieb:
> In Zusammenhang mit der Led, evtl. genügt diese ja bereits aus um an die
> 2,7 V / 4 V Grenze zu kommen.

 Möglich, aber eine LED mit 20mA ?

Thomas Eckmann schrieb:
> Eine Vermutung ist, dass er als Transistor einen dicken Mosfet dran hat,
> der mit seiner Kapazität beim Schalten die Stromversorgung kurz
> zusammenbrechen lässt und nach einem Reset geht es dann wieder von vorne
> los.

 Das erklärt das Blinken auch nicht.
 Wenn die Stromversorgung beim Schalten zusammenbricht:
   a) LED wird mit Log.1 eingeschaltet, dann gelingt das Programm
      gar nicht bis zur Abfrage.
   b) LED wird mit Log.0 eingeschaltet, dann würde es nur ein
      kurzes Blitzen geben (wenn überhaupt).

 Oder ich sehe das alles falsch.

von Michael L. (michaelx)


Lesenswert?

Thomas Eckmann schrieb:
> Marc Vesely schrieb:
>> 40ms * 8 = 320ms = ungefahr 3Hz.
>
> Das würde die Zeit erklären. Aber nicht, dass es überhaupt blinkt.
>
> ...

Die Ursache fürs Blinken liegt doch im Code. Das wurde nicht nur von mir 
schon weiter oben festgestellt.

von Thomas E. (thomase)


Lesenswert?

Marc Vesely schrieb:
> Oder ich sehe das alles falsch.

Das Problem ist, dass wir das gar nicht sehen und uns auf den 
subjektiven Eindruck des TO verlassen. Was der eine als Blitzen 
wahrnimmt, ist für jemand anderes Blinken und für den nachsten leuchtet 
es ständig mit kurzen Unterbrechungen.

mfg.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Michael L. schrieb:
> Die Ursache fürs Blinken liegt doch im Code. Das wurde nicht nur von mir
> schon weiter oben festgestellt.

 Nicht ganz.
 Es sei denn, für Compiler ist:
1
   static uint8_t last_state = 0;
 gar nicht static.
 Dann könnte das mit Blinken und 1MHz statt 8MHz die einzig logische
 Erklärung sein.
 Da ich das aber für wenig wahrscheinlich halte, wird wohl sein
 gepostetes und sein geflashtes Code unterschiedlich sein.

von Michael L. (michaelx)


Lesenswert?

Marc Vesely schrieb:

>  Nicht ganz.

Klappt wohl heute nicht ganz mit dem Lesen?

Ohne das hier würde nichts blinken:
1
PORTB ^= ( 1 << PB0 );

;-)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Michael L. schrieb:
> Klappt wohl heute nicht ganz mit dem Lesen?

 Und bei dir ?
1
    uint8_t i = key_pressed (&PIND, PD0);
2
    if(i == 1) {
3
      PORTB ^= ( 1 << PB0 ); 
4
    }

von Michael L. (michaelx)


Lesenswert?

Marc Vesely schrieb:
>  Und bei dir ?

Du hast Recht. Irgendwas wird da noch sein. Vorhin, kurz nach dem 
letzten Posting hats mich erst mal weg gedreht. Ich glaube, ich sollte 
mit meiner fetten Erkältung etwas kürzer treten.

:-(

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.