Forum: Mikrocontroller und Digitale Elektronik LED einzeln an per Funktion


von Dominique (Gast)


Lesenswert?

Hallo zusammen,
ich habe einen ATMega16 und an PORTA 8 LEDs angeklemmt,
die ich jetzt einzeln ein/aus schalten möchte. Dafür haeb ich mir eine 
Funktion geschrieben, welche ich wie folgt aufrufe:

unique(LEDNr, Status);

also z.B. so:
unique(3,1); //Schaltet LED3 (PORTA2) ein

aber irgendwie funktioniert das noch nicht richtig, habe die funktion 
erstmal soweit bis zum EINSCHALTEN programmiert, um das Ausschalten 
kümmere ich mich danach.
hier die Funktion:
1
unique(int LEDNr, int Status)
2
{
3
int  LED = LEDNr-1;
4
char  praefix[3];
5
6
praefix[0] = 'P';
7
8
if((LED >= 0) && (LED <= 7))
9
{
10
praefix[1] = 'A';
11
praefix[2] = LED;
12
}
13
14
if(Status == 1)
15
{
16
PORTA |= (1 << praefix);   // hier wird Fehler angezeigt (siehe unten)
17
}
18
}

Der Fehler: main.c:1265: error: invalid operands to binary <<

ich hoffe mir kann jemand weiterhelfen, ich denke ich weiß auch woran 
das liegt, nämlich an der char variable, oder ??

vielen dank

von Simon K. (simon) Benutzerseite


Lesenswert?

Ähem, das geht so nicht...

wie wärs mit:
1
unique(int LEDNr, int Status)
2
{
3
  if (Status == 1)
4
    PORTA |= (1 << (LEDNr-1));
5
}

von Dominique (Gast)


Lesenswert?

:)
ja genauso hatte ich das vor, das funktioniert super und ist viel 
kompakter als meine Idee....
vielen dank simon !!

Jetzt muss ich bloß noch hingehen nund was programmieren, das ich auch 
PORTC und PORTD damit ansprechen kann...
Habe eine LED-Leiste mit 24 LEDs und Treiberbaustein, die ich gerne 
einzeln ansteuern würde....
Also dirty geht es, halt nur einzenl über Funktionsaufruf war noch ein 
Featue, was ich brauchte :)


VIELEN DANK !! echt super geil !!

von Matthias (Gast)


Lesenswert?

1
// PORTNr: 0=PortA, 1=PortB, 2=PortC, 3=PortD
2
// LEDNr: 0..7
3
unique(uint8_t LEDNr, uint8_t PORTNr)
4
{
5
  switch ( PORTNr )
6
   {
7
     case 0:
8
       PORTA |= (1 << LEDNr);
9
       break;
10
     case 1:
11
       PORTB |= (1 << LEDNr);
12
       break;
13
     case 2:
14
       PORTC |= (1 << LEDNr);
15
       break;
16
     case 3:
17
       PORTD |= (1 << LEDNr);
18
       break;
19
   }
20
}

von Simon K. (simon) Benutzerseite


Lesenswert?

Dominique wrote:
> :)
> ja genauso hatte ich das vor, das funktioniert super und ist viel
> kompakter als meine Idee....
> vielen dank simon !!
>
> Jetzt muss ich bloß noch hingehen nund was programmieren, das ich auch
> PORTC und PORTD damit ansprechen kann...
> Habe eine LED-Leiste mit 24 LEDs und Treiberbaustein, die ich gerne
> einzeln ansteuern würde....
> Also dirty geht es, halt nur einzenl über Funktionsaufruf war noch ein
> Featue, was ich brauchte :)
>
>
> VIELEN DANK !! echt super geil !!

Übrigens: Das Ausschalten funktioniert mit obiger Funktion nicht. Nur 
das einmalige Anschalten. Wenn du die LED auch ausschalten möchtest 
(über den Status Parameter) dann musst du die Funktion etwas erweitern:
1
unique(int LEDNr, int Status)
2
{
3
  if (Status == 1)
4
    PORTA |= (1 << (LEDNr-1));  //LED AN
5
  else
6
    PORTA &= ~(1 << (LEDNr-1)); //LED AUS
7
}

von Dominique (Gast)


Lesenswert?

Jo das habe ich schon :) aber etwas anders, aber läuft auch sehr gut 
meine Lösung...

hier ist sie:
1
unique(int LEDNr, int Status)
2
{
3
int  LED = LEDNr-1;
4
5
if((LED >= 0) && (LED <= 7))
6
{
7
if(Status == 1)
8
{
9
  PORTA |= (1 << (LEDNr-1));
10
}
11
else if(Status == 0)
12
{
13
  PORTA &= (0 << (LEDNr-1));
14
}
15
}
16
}

ist doch auch gut, oder ??
das mit dem switch-case finde ich auch eine sehr gute Lösung

von Dominique (Gast)


Lesenswert?

Alo gut, für PORTA und PORTC habe ich es am laufen, leider jedoch 
funktioniert die funktion nicht bei PORTD :(
hier mal die beiden Auszüge für A und D aus der Funktion unique();

=============================
if((LED >= 0) && (LED <= 7))
{
if(Status == 1)
{
  PORTA |= (1 << (LEDNr-1));
}
else if(Status == 0)
{
  PORTA &= (0 << (LEDNr-1));
}
}
=============================
if((LED >= 16) && (LED <= 23))
{
if(Status == 1)
{
  PORTD |= (1 << (LEDNr-1));
}
else if(Status == 0)
{
  PORTD &= (0 << (LEDNr-1));
}
}
=============================


Ich verstehe nicht ganz, wiedo das mit PORTD nicht geht :(
kann das an irgendwelchen Fuses liegen ??

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das Ausschalten funktioniert in keiner der Varianten korrekt:

  PORTA &= (0 << (LEDNr-1));


Woran liegt das Problem?

0 << 1 ist 0, genauso wie 0 << 7 immernoch 0 ist.

PORTA &= 0 setzt den GESAMTEN PortA auf 0, schaltet also alle LEDs aus.


Simon hat bereits den richtigen Weg vorgeschlagen:

  PORTA &= ~(1 << (LEDNr-1));

von Dominique (Gast)


Lesenswert?

Doch doch, Ausschalten geht auch mit meiner Variante, zumindest bei 
PortA und PORTC
bei PORTD geht garnichts mit dieser Variante, nichtmal einschalten :(

von Johannes M. (johnny-m)


Lesenswert?

Dominique wrote:
> Doch doch, Ausschalten geht auch mit meiner Variante, zumindest bei
> PortA und PORTC
Klar, wenn man das ganze Portregister Null schreibt, dann geht alles 
aus. Nur ist das, was Rufus schreibt, spätestens dann relevant, wenn an 
dem Port auch noch Sachen dranhängen, die nicht mit ausgehen sollen.

> bei PORTD geht garnichts mit dieser Variante, nichtmal einschalten :(
Das Problem mit Port D kann eigentlich nur in Deiner Initialisierung 
liegen, die Du geheimhältst... oder ein Hardware-Fehler.

von Matthias (Gast)


Lesenswert?

Ja, aber wie Rufus bereits gesagt hatte: Du schaltet DEN GANZEN Port 
damit ab, und nicht einzelne LEDS.
Wenn natürlich nur eine an war, merkst du das nicht.

Wenn der PortD nicht geht, dann solltest du mal nach dem DDRD Register 
sehen, oder alternative Funktionen verwendet?

An Fuses liegt sowas nicht...

von Karl H. (kbuchegg)


Lesenswert?

Dominique wrote:
> if((LED >= 16) && (LED <= 23))
> {
> if(Status == 1)
> {
>   PORTD |= (1 << (LEDNr-1));
> }
> else if(Status == 0)
> {
>   PORTD &= (0 << (LEDNr-1));
> }
> }
> =============================
>
>
> Ich verstehe nicht ganz, wiedo das mit PORTD nicht geht :(
> kann das an irgendwelchen Fuses liegen ??

Überlag mal wie gross den LEDNr ist, wenn dieser if Zweig
betreten wird.
Und dann denk mal drüber nach, was mit einer 1 passiert, wenn
man sie derartig oft nach links schiebt.

von Dominique (Gast)


Lesenswert?

ja stimmt schon, das ich den ganzen port ausschalte, habe das jetzt 
alles geändert, aber es geht immer noch nicht:

Aber PORTD ist alles richtig initialisier, denn über meine anderen 
Funktionen kann ich den prima ansprechen, auch direkt aus der while 
schleife, alles kein problem, nur halt der aufruf aus dieser funktion 
heraus will nicht


=============================
if((LED >= 0) && (LED <= 7))
{
if(Status == 1)
{
  PORTA |= (1 << (LEDNr-1));
}
else if(Status == 0)
{
  PORTA &= ~(1 << (LEDNr-1));
}
}
=============================
if((LED >= 16) && (LED <= 23))
{
if(Status == 1)
{
  PORTD |= (1 << (LEDNr-1));
}
else if(Status == 0)
{
  PORTD &= ~(1 << (LEDNr-1));
}
}
=============================

von Karl H. (kbuchegg)


Lesenswert?

@Dominique

Du bist im Moment drauf und drann, dich regelmässig mit
übermässig kompliziertem Code selbst auszutricksen.

zb. Entweder du benutzt eine Variable LED, die grundsätzlich
um 1 kleiner ist als das übergebene Argument LedNr. Dann
benutzte aber bitte diese Variable quer durch deine Funktion.
Oder aber du schriebst überall in deiner Funktion LedNr-1.
Aber bitte dann auch konsequent
Oder aber du gehst den besten Weg von allen und akzeptierst
ganz einfach dass in C nun mal bei 0 angefangen wird zu
zählen. Gewöhn dich daran, das spart dir im Laufe der Zeit
viel Kopfzerbrechen: Das erste Element (egal wovon) ist
das mit der Ordnungszahl 0

von Karl H. (kbuchegg)


Lesenswert?

@Dominique

Ach ja, hab ich vergessen:

Ein konsistentes Einrückschema ist kein Luxus, sondern ein
Instrument um Fehler leichter sehen zu können. Also benutz
das auch.

Ich weiss: Neulinge sagen immer "Das mach ich später".
Nur: Ich hab schon erlebt, dass Neulinge stundenlang nach
Fehlern gesucht und nicht gefunden haben. Dann hab ich
als erstes mal den Code korrekt eingerückt und in 30 Sekunden
haben sie dann selbst das Problem gesehen.


PS: Hast du meine Anmerkung weiter oben gesehen?
Wenn nicht, hier ist sie nochmal:

> if((LED >= 16) && (LED <= 23))
> {
> if(Status == 1)
> {
>   PORTD |= (1 << (LEDNr-1));
> }
> else if(Status == 0)
> {
>   PORTD &= (0 << (LEDNr-1));
> }
> }
> =============================
>
>
> Ich verstehe nicht ganz, wiedo das mit PORTD nicht geht :(
> kann das an irgendwelchen Fuses liegen ??

Überlag mal wie gross den LEDNr ist, wenn dieser if Zweig
betreten wird.
Und dann denk mal drüber nach, was mit einer 1 passiert, wenn
man sie derartig oft nach links schiebt und nur 8 Bit zur Verfügung
hat.

von Michael Wilhelm (Gast)


Lesenswert?

Bei Port D schiebst du in einem 8-bit Register die Leds 16 bis 23 mal. 
Also, bei Port D LEDNr - 16, dann sollte deine konstruktion 
funktionieren.

MW

von Joe (Gast)


Lesenswert?

Schau dir mal folgenden Thread an, hier wird eine Möglichkeit der 
direkten Zuweisung von PIN's innerhalb eines Ports erklärt.

Beitrag "sbit macro für avr-gcc"

Bei 8x51 Typen ist das kein Problem und für die AVR's gibts eben den 
genannten Workarround. Damit sollte es übersichtlicher und korrekt 
werden.

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.