Forum: Mikrocontroller und Digitale Elektronik LEDuhr Funktionen im Array speichern/abrufen AVR atmega16


von Julian S. (julli_s)


Lesenswert?

Hi,

ich steh vor folgendem Problem: Ich hab mir eine LED Uhr gebaut/gelötet 
und bin gerade bei der Programmierung.
(Die rückseite ist zu dem Zeitpunkt gerade zu ca. 50% fertig)
http://www.abload.de/img/img_0151tjk80.jpg
http://www.abload.de/img/img_01549fkuz.jpg
Kurze erklärung:
4 x 7-Segment sollte klar sein
Innerer Ring, blaue LEDs -> Sekunden Ring
Mittlerer Ring, rote LEDs -> Minuten Ring
Äußerer Ring, 12 grüne LEDs -> Stunden Ring
Auf Wunsch, bzw. falls es jemanden interessiert, kann ich gern mal ein 
video mit einem Testprogramm hochladen.

So, wieder zum Problem:
Da das ganze mit schiebe-registern funktioniert, habe ich Funktionen 
geschrieben, um auf den 7-Segment "anzeigen" die verschiedenen Zahlen 
auszugeben bzw. um auf den ringen eine LED mehr angehen zu lassen usw.

Jetzt wollte ich die Funktionen für die Zahlen in Arrays Speichern, um 
das eigentliche Programm klein und übersichtlich zu halten. Habe also 
ein bischen gegooglt und bin auf Funktionszeiger gestoßen.
Nach diesem Beispiel habe ich das jetz aufgebaut
(http://www.tutorials.de/c-c/311334-funktionszeiger-array-aber-anders.html)

Mein code:
1
...
2
...
3
typedef void (*pFunc)();
4
5
void seg1_0()//zeigt auf Segment 1 eine 0 an
6
{
7
......
8
.....
9
......
10
}//seg1_0()
11
12
void seg1_1()//zeigt auf Segment 1 eine 1 an
13
{
14
...........
15
..............
16
.....
17
}//seg1_1()
18
19
20
int main(void)
21
{
22
  pFunc seg1[2];
23
  seg1[0] = &seg1_0;
24
  seg1[1] = &seg1_1;
25
26
  j = 0;
27
  
28
    while(1)
29
    {
30
        if (PINA & (1<<PINA7))//if takt
31
        {
32
          _delay_ms(600);
33
          seg1[j];
34
          j++;
35
          if(j == 1)
36
            j = 0;
37
        }//if takt
38
    }//while 1
39
}//main

Es funktioniert allerdings nicht, das ic gibt absolut keine Signale aus, 
die funktionen an sich funktionieren aber, wenn ich sie so ausführe:
1
if (PINA & (1<<PINA7))//if takt
2
{
3
    _delay_ms(600);
4
    seg1_0();
5
}//if takt

Ich hoffe, ich konnte gut beschrieben wo mein Problem liegt und hoffe 
ebenfalls, dass mir jemand helfen kann.
Wäre sehr dankbar =)

Mit freundlichen Grüßen
Julian

von Karl H. (kbuchegg)


Lesenswert?

Julli S. schrieb:


>           seg1[j];

Das ist kein Funktionsaufruf.

Genauso wie

   seg1_0;

noch kein Funktionsaufruf ist. Das holt einfach nur den Pointr auf eine 
Funktion und ......  macht nichts damit.

Das hier

   seg1_0();

wäre ein Funktionsaufruf, der die Funktion seg1_0 aufruft. Und genau 
gleich ist

    seg1[j]();

ein Funktionsaufruf, nur dass diesmal die Adresse der Funktio aus dem 
Array mit den Funktionspointern kommt.



PS: Ich bin nicht wirklich überzeugt, dass Funktionspointer hier eine 
besonders gute Idee sind. IMHO treibst du da viel zu viel Aufwand. Der 
Dreh besteht NICHT darin, dass man für jede darzustellende Ziffer eine 
eigene Funktion schreibt. Der Dreh besteht darin, dass man lediglich 
eine einzige Funktion schreibt, die die Ausgabe erledigt und dass man 
dieser Funktion dann unterschiedliche Daten gibt, die sie ausgeben soll. 
Die Information über die Ziffern, welches Segment leuchten soll und 
welches nicht, steckt in diesen Daten. Funktionspointer sind hier 
absoluter Overkill und verkomplizieren den Code nur unnötig. Ganz 
abgesehen davon, dass der Code viel länger und schlechter zu warten ist, 
als notwendig.

von Julian S. (julli_s)


Lesenswert?

Hi,

vielen Dank für die schnelle Hilfe, hätte ich eigentlich selbst drauf 
kommen müssen. So funktionierts =)

Ich lass mir dein Vorschlag mal durch den Kopf gehen, allerdings werde 
ich das wahrscheinlich noch nicht hinbekommen.
Studiere zwar Informatik, bin aber erst im 2. Sem und daher noch relativ 
am Anfang des Programmierens.
v1.0 wird wohl auf eine umständliche aber einfach zu programmierende 
Variante hinauslaufen, evtl. setz ich mich später mal an v2.0 =)

LG
Julian

von Karl H. (kbuchegg)


Lesenswert?

Julli S. schrieb:
> Hi,
>
> vielen Dank für die schnelle Hilfe, hätte ich eigentlich selbst drauf
> kommen müssen. So funktionierts =)
>
> Ich lass mir dein Vorschlag mal durch den Kopf gehen, allerdings werde
> ich das wahrscheinlich noch nicht hinbekommen.

Dann musst du daran arbeiten.
Eine derartige Funktion mit Argumentübernahme zu schreiben verlangt von 
dir lediglich Grundfertigkeiten. Wenn du die (noch) nicht hast, dann ist 
es sowieso zu früh, ein reales Projekt in Angriff zu nehmen.

> v1.0 wird wohl auf eine umständliche aber einfach zu programmierende
> Variante hinauslaufen,

Das ist Quatsch.

Funktionspointer sind überspitzt gesagt 6. Semester. Mit ganz normalen 
Programmierwissen aus dem 2. Semster (Funktionen und Argumentübergabe 
sowie Bitzerlegung) lässt sich das wunderbar programmieren. Das ist 
Grundlagenwissen für jeden µC-Programmierer. Etwas was ich von 
Funktionspointern nicht sagen würde.
Du versuchst gerade ein Haus zu bauen und dein einziges Werkzeug ist ein 
Hammer. Und weil du mit dem Borstenpinsel nicht umgehen kannst versuchst 
du gerade die Oberfräse (weil du das irgendwo gelesen hast) dazu 
einzusetzen, Tapeten an die Wand zu bringen.

von Peter D. (peda)


Lesenswert?

Julli S. schrieb:
> void seg1_0()//zeigt auf Segment 1 eine 0 an

Oh Gott, das wird ja ein Riesenmonster an völlig unübersichtlichen Code.

Der übliche Ansatz ist folgender:

Du legst ein Array im SRAM an, was den LEDs entspricht.
Array-Größe = (alle LEDs + 7) / 8
Dieses Array ist quasi Dein Bild-RAM und in dem kannst Du ganz einfach 
arbeiten.
Dann hast Du eine Funktion, welche dieses Array komplett ausgibt. Es 
werden also immer alle LEDs refresht (Ziffern + Ringe).

Um eine Ziffer anzuzeigen, brauchst Du nun eine weitere Funktion. Dieser 
übergibst Du die Stelle und die Ziffer. Diese Funktion holt sich den 
7-Segment Code der Ziffer aus einem konstanten Array und schreibt es in 
den Bild-RAM an die Adresse, die der Stelle entspricht.

Du hast also nur 2 Funktionen, nix mit Funktionspointern.

Sinnvoller Weise sind die Segmente für alle Stellen in der gleichen 
Reihenfolge und in einer 8-er Gruppe (Byte), sonst muß die 
Ausgabefunktion noch umsortieren vor dem Schieben.
Und die Schiebergister sind natürlich kaskadiert, damit man alles in 
einem Rutsch machen kann und auch weniger Verdrahtung hat.

Die Ring-LEDs sind also auch mit im Bild-RAM.
Da schreibt man sich wieder eine Funktion mit 2 Argumenten: Ringnummer 
und Anzahl der leuchtenden LEDs.

Sind insgesamt 3 Funktionen, ich schätze mal, 100..200 Byte Code.

von Julian S. (julli_s)


Lesenswert?

Hi, die uhr läuft jetz ansich =) Muss jetzt nur noch das dcf77 signal 
auslesen und dekodieren.

Peter Dannegger schrieb:
> Oh Gott, das wird ja ein Riesenmonster an völlig unübersichtlichen Code.

also ich find die 42 Zeilen schon relativ übersichtlich, na klar sind 
davor noch die funktionen aber das sind alles in allem knapp 500 Zeilen.

Trotzdem danke, für die Hilfe und die ganzen anregungen =)
1
if (PINA & (1<<PINA7))//if takt
2
{
3
  _delay_ms(600);
4
  sek++;//sekunden variable
5
  sekp1();//sekundenring eine led mehr
6
      
7
  if(sek == 60)
8
  {
9
    sek = 0;
10
    min++;
11
    sekoff();//sekundenring aus
12
    sekp1();//Nullte led wieder an
13
    minp1();//minuten ring eine mehr an
14
  }    
15
      
16
  if (min == 60)
17
  {
18
    min = 0;
19
    stund++;//stunden variable
20
    minoff();//Minutenring aus
21
    minp1();//Nullte led wieder an
22
    stdp1();//stundenring eine mehr an
23
  }
24
      
25
  if (stund == 12)
26
  {
27
    stdoff();
28
    stdp1();
29
  }
30
      
31
  if (stund == 24)
32
  {
33
    stund = 0;
34
    stdoff();
35
    stdp1();
36
  }      
37
      
38
  seg1[min%10]();
39
  seg2[min/10]();
40
  seg3[stund%10]();
41
  seg4[stund/10]();
42
      
43
}//if takt

LG Julian

von Karl H. (kbuchegg)


Lesenswert?

Julli S. schrieb:

> also ich find die 42 Zeilen schon relativ übersichtlich, na klar sind
> davor noch die funktionen aber das sind alles in allem knapp 500 Zeilen.

500?

Da sind mindestens 300 zu viel. Eher sogar 400.



>   if(sek == 60)
>   {
>     sek = 0;
>     min++;
>     sekoff();//sekundenring aus
>     sekp1();//Nullte led wieder an
>     minp1();//minuten ring eine mehr an
>   }

Tip.
Trenne das Hochzählen der Uhr von der Anzeige.
Brauchst du sowieso, denn irgendwie willst du die Uhr ja auch händisch 
stellen.

Und was hat der delay da drinn verloren?
Mit einem delay kriegst du keine einigermassen genau gehende Uhr. DCF 
hin oder her. Deine Uhr muss auch dann noch laufen, wenn DCF mal 
ausfällt.

Das 'Uhrwerk' einer µC-Uhr besteht aus einem Timer im CTC-Modus. Alles 
andere ist auf lange Sicht gesehen nicht geeignet.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Julli S. schrieb:
> davor noch die funktionen aber das sind alles in allem knapp 500 Zeilen.

Genau das meinte ich.
Anbei mal 2 der oben genannten 3 Funktionen, um das Prinzip zu 
verdeutlichen.

von Julian S. (julli_s)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und was hat der delay da drinn verloren?
> Mit einem delay kriegst du keine einigermassen genau gehende Uhr. DCF
> hin oder her. Deine Uhr muss auch dann noch laufen, wenn DCF mal
> ausfällt.

Ich habe einen externen, quarzgenauen taktgeber (1Hz) und das 600. delay 
dient zum entprellen. (deswegen auch if(takt) )
Brauche das dcf77 modul also garnicht unbedingt wegen der genauigkeit 
sondern, um die uhr nach dem ausziehen nicht am pc stellen zu müssen.

Manuell stelle ich die Uhr im moment indem ich die sek, min und die 
stunden variable einfach vorgebe.

(@Peter Dannegger, hab mir den code grade mal angeschaut, steige da 
jedoch im moment nicht durch. Schau morgen nochmal in ruhe drauf.)

Es funktioniert jedenfalls bestens, wie es gerade läuft.
Wie schonmal angesprochen, im späteren verlauf des Studiums setze ich 
mich vielleicht nochmal v2.0.

LG Julian

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.