Forum: Mikrocontroller und Digitale Elektronik ATMega 8 LED mit Button schalten


von Christian G. (christian1973)


Angehängte Dateien:

Lesenswert?

Moin Zusammen,

ich habe ein ganz kleines Programm. Dieses soll eine LED am ATMega8 Port 
PB1 einschalten, wenn ein Taster am Eingang PC3 gedrückt wird und nach 
10 Sekunden geht die LED wieder aus:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
void sleep(int milliseconds) {
5
  while (milliseconds > 0) {
6
    _delay_ms(1);
7
    milliseconds--;
8
  }
9
}
10
11
int main() {
12
  // initialize the cabin led 
13
  DDRB  = 0b11111111;           // PORTB output for the LED
14
  // and the button 
15
  PORTC |=  0b0001000;          // enable pull up for PC3
16
17
  // blink the led 4 times
18
  DDRB |= (1<<PB1);
19
  sleep(1000);
20
  DDRB &= ~(1<<PB1);
21
  sleep(1000);
22
  DDRB |= (1<<PB1);
23
  sleep(1000);
24
  DDRB &= ~(1<<PB1);
25
  sleep(1000);
26
  DDRB |= (1<<PB1);
27
  sleep(1000);
28
  DDRB &= ~(1<<PB1);
29
  
30
  
31
  // and go...
32
  while(1) {
33
    // PC3 is low?
34
    if((PINC & 0b0001000)==0) {
35
      DDRB |= (1<<PB1);
36
      sleep(10000);
37
    }
38
    
39
    // finally make sure to turn off the led
40
    DDRB &= ~(1<<PB1);
41
  } // Main loop
42
}

Der HW Aufbau ist dem Bild zu entnehmen und nicht besonders spektakulär. 
Der ATMega hängt an 3 AA Batterien - die liefern ca. 4,09V laut 
Voltmeter.
Ach ja, im Bild hing die LED noch an PD5 - ich hab sie aber testhalber 
auf PB1 umgehängt.

Mein Problem ist nun: weder das Blinken zu Beginn, noch wenn ich den 
Button drücke, funktioniert.

Kann mir einer sagen, was hier falsch läuft???

Danke schon einmal,

Christian

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Du schreibst nie auf PORTB, sondern immer auf DDRB. Das geht nur, wenn 
du PORTB einmal mit einer 1 auf dem LED Bit vorbesetzt. Es ist aber 
einfacher, PORTB zu beschreiben statt dem Richtungsregister.
Sind übrigens nur 3 Blinks am Anfang.

: Bearbeitet durch User
von Christian G. (christian1973)


Lesenswert?

Au Backe. Heisst das, ich muss nur

PORTB |= (1<<PB1);
bzw.
PORTB &= ~(1<<PB1);

schreiben?

von Christian G. (christian1973)


Lesenswert?

Offensichtlich.

von Christian G. (christian1973)


Lesenswert?

Matthias S. schrieb:
> Du schreibst nie auf PORTB, sondern immer auf DDRB. Das geht nur, wenn
> du PORTB einmal mit einer 1 auf dem LED Bit vorbesetzt. Es ist aber
> einfacher, PORTB zu beschreiben statt dem Richtungsregister.
> Sind übrigens nur 3 Blinks am Anfang.

Ich danke Dir. Geht jetzt. Ich schnall das mit diesen ganzen Registern 
und Ports einfach nicht :-(

von Sigma (Gast)


Lesenswert?

Christian G. schrieb:
> Ich schnall das mit diesen ganzen Registern
> und Ports einfach nicht :-(

Da gibt es eigentlich nix zu schnallen, weil es einfach so festgelegt 
wurde. Man muss es nur wissen oder wissen wo man es nachschauen kann. 
Bei anderen Mikrocontrollern ist anders geregelt.

von HildeK (Gast)


Lesenswert?

Christian G. schrieb:
> Ich schnall das mit diesen ganzen Registern
> und Ports einfach nicht :-(

Schau dir mal sbit.h (von Peter D.; peda) und deren Verwendung an:
Beitrag "Re: Frage zu Struktur für IO-Port bei AVRs"

Das sieht dann wesentlich übersichtlicher aus, weniger fehleranfällig zu 
schreiben und ist auch nach langer Zeit problemlos lesbar.

Dann wird aus
1
  PORTB |= (1<<PB1);
2
  sleep(1000);
3
  PORTB &= ~(1<<PB1);
4
5
 // übersichtlicher:
6
7
  LED0 = 1;    
8
  sleep(1000);
9
  LED0 = 0;

Du musst nur sbit.h einbinden und ein paar defines machen; für das 
Beispiel dann
1
#include "sbit.h"
2
#define LED0     PORT_B0
3
// und ggf. noch 
4
#define AUS      0
5
#define EIN      1
6
// so dass final auch stehen könnte:
7
  LED0 = EIN;
8
  sleep(1000);
9
  LED0 = AUS;

Ähnlich einfach ist die Abfrage eines Pins.
Ich kann das nur empfehlen und peda sagt, es erzeugt sogar sehr 
effizienten Code.

von c-hater (Gast)


Lesenswert?

Christian G. schrieb:

> Ich danke Dir. Geht jetzt. Ich schnall das mit diesen ganzen Registern
> und Ports einfach nicht :-(

Dann hast du ein strukturelles Kompetenzproblem. Sowas kann man durch 
Lernen bekämpfen...

von Falk B. (falk)


Lesenswert?

Christian G. schrieb:
> Ich danke Dir. Geht jetzt. Ich schnall das mit diesen ganzen Registern
> und Ports einfach nicht :-(

Wo liegt das Problem?

DDRx  data direction register, legt die Richtung des IOs fest,
      0=Eingang, 1=Ausgang
PORTx legt den Ausgabewert fest, wenn das Pin als Ausgang konfiguriert 
ist,
      oder
      schaltet den internen Pull-Up Widerstand ein, wenn es als Eingang
      konfiguriert ist
PINx  liest den Pegel des IO-Pins, egal welche Richtung konfiguriert ist

von Achim H. (pluto25)


Lesenswert?

Natürlich muß man das schnallen. Auch die anderen mußten es irgenwann 
lernen wollen es aber jetzt nicht verraten :-(
Es gibt drei Register für jeden Port.
Wie schon richtig verwand das Pin-Register: es zeigt den wirklich 
vorhandenen Zustand der Anschlüsse.
Dann das DDR. Das bestimmt ob die Pins Ausgang(1) oder Eingang (0) sein 
sollen. Meißt wird es nur einmal vor der Main loop gesetzt.
Und dann noch das Port Register. Das bestimmt ob der Pin geschaltet wird 
(wenn DDR=1) oder nur ein Pullup (wenn DDR=0)

von c-hater (Gast)


Lesenswert?

A. H. schrieb:

> Wie schon richtig verwand das Pin-Register: es zeigt den wirklich
> vorhandenen Zustand der Anschlüsse.

Ja schon, aber leider nicht instantan, sondern es zeigt den Zustand, der 
dort vor 1..(unendliche Näherung an)2 Takten geherrscht hat.

> Dann das DDR. Das bestimmt ob die Pins Ausgang(1) oder Eingang (0) sein
> sollen. Meißt wird es nur einmal vor der Main loop gesetzt.
> Und dann noch das Port Register. Das bestimmt ob der Pin geschaltet wird
> (wenn DDR=1) oder nur ein Pullup (wenn DDR=0)

Tja, das, wie auch alles andere steht, man glaubt es kaum, im 
Datenblatt. Und Lernen bedeutet bei µC halt insbesondere: Lektüre des 
Datenblatts.

Das ist die absolut notwendige Grundlage. Man kann i.d.R. noch sehr viel 
mehr lernen, aber das kommt später...

von Stefan F. (Gast)


Lesenswert?

Christian G. schrieb:
> void sleep(int milliseconds) {
>   while (milliseconds > 0) {
>     _delay_ms(1);
>     milliseconds--;
>   }
> }

Das ist ein uraltes längst überflüssiges Relikt. Die Funktion 
_delay_ms() kann beliebig lange warten, da braucht man keine Schleife 
drumherum.

> DDRB |= (1<<PB1);

Soll das die LED einschalten? Du konfigurierst damit den I/O Pin als 
Ausgang mit LOW Pegel (weil das der Standart-Wert im PORTB Register 
ist). Kann man machen, wenn die LED entsprechend zwischen Ausgang und 
VCC liegt.

> Au Backe. Heisst das, ich muss nur
> PORTB |= (1<<PB1);
> schreiben?

Nein, denn "nur" damit wäre der Pin ein Eingang. Du musst ihn schon als 
Ausgang konfigurieren, sonst kann er die LED nicht antreiben.

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.