Forum: Mikrocontroller und Digitale Elektronik Multiplexing und Taster Routine


von Hans (Gast)


Lesenswert?

Hallo Ihr,
Ich hab an meinem Testboard fünf 7-Segment Anzeigen per Multiplexing und 
ner selbergeschrieben Funktion dazu gebracht, dass ich ihr ein 
5-Stelliges Wort übergebe, und die Funktion das dann in ner while(1) 
schleife brav anzeigt.
Dann hab ich da noch fünf Taster, die ich auch super entprellen kann 
wenn ich die öfters Abfrag und dazwischen immer 50-120 ms warte und den 
drei mal auslesen lass. Der Tater soll nacher bei einmaligem drücken 
eine Variable einfach 1 machen oder wenn diese schon 1 ist wieder 0 
machen.

Jetzt komm ich in Konflikt, wnn ih die Variable auf der Anzeige anzeigen 
lassen will, hab ich ja immer die Pausen, die meine Entprellung braucht 
auch auf der Anzeige, das heißt ich hab ein ziemlich doofes Flackern.

Meine Frage, wie kann ich meine Entprellung so gestalten, dass diese in 
weniger als drei bis zehn Millisekunden geschieht, denn das sieht man 
der Anzeige noch nicht an, weil das ist ja dann eigentlich ziemlich 
blöd.

Ich programmiere in C also für jegliche Hilfe bin ich euch sehr Dankbar.

Hans

von Peter D. (peda)


Lesenswert?

Du bist in einer Sackgasse.
Es hilft nichts, Du mußt Dich mit Timerinterrupts befassen.

Hier ein Beispiel fürs Entprellen:

Beitrag "Universelle Tastenabfrage"

Und hier fürs Muxen:

Beitrag "ADC mit Multiplexanzeige"

Die Verkopplung mit dem ADC-Interrupt kann man weglassen, wenn man ihn 
nicht braucht.

Mit etwas Überlegung kriegt man beides in einen Timer.


Peter

von Hans (Gast)


Lesenswert?

?? Ich versteh da irgendwie nur Bahnof, kannste mir das vielleicht mal 
ewas weniger kompliziert erklären, wie so der Grundablauf vom Prorgramm 
ist, weil das Programm ist ja immer nur an einer Stelle im Code, und 
irgendwo muss ich ja die Pause für die Taster machen oder? weil wenn 
ichs jetzt so lass wie ichs hab, dann dafr ich maximal 3ms drücken, um 
die Variable einmal u erhöhen bzw zu ändern, alles andere gibt ein 
schnelles blinken :(.

Bin für jede Hilfe offen, und versuchs dann in meinem Code zu ändern.

Danke Hans

von Hans (Gast)


Lesenswert?

Kan mir mein Problem niemand lösen? oder mir vllt mal den Grundcode 
erklären Programmieren ist dann das kleinere Problem, bin voll in nem 
Gedankenloch :(

von Karl H. (kbuchegg)


Lesenswert?

Deine ganze Gedankenwelt kreist momentan nur um Wartezeiten und 
Schleifen. Wie PeDa schon sagte: Das ist eine Sackgasse! Sieht auf den 
ersten Blick gut und einfach aus, aber wenn du am Ende der Strasse bist, 
merkst du das du so nicht weiter kommst.

Du musst dich mit Timern und Interrupts beschäftigen!
Kurz gefasst: Ein Timer liefert deinem Programm ein regelmässiges Signal 
etwas zu tun. Regelmässig kann alle Millisekunden sein und das was zu 
tun ist könnte zb sein die momentan erleuchtete Anzeige abzuschalten und 
die nächste einzuschalten oder schnell einen kurzen Durchlauf durch die 
Tasten zu machen um zu sehen ob eine gedrückt ist.

Dein eigentliches Programm kriegt davon nichts mit. Interrupts laufen 
ascynchron zum Hauptfaden deines Programms. Dein eigentliches Programm 
wird nur kurz unterbrochen um zwischendurch mal schnell was anderes zu 
machen.

von Christian P. (christian_paier)


Lesenswert?

50-120ms is schon mal sehr viel. Ich hab noch keine taste länger als 
10ms entprellen müssen. Manchmal reicht auch schon 1ms. Ich würde mal 
versuchen die Entprellzeit sukzessive runter zu setzen bis Blödsinn 
entsteht.

Wenn das nicht reicht würd ich die Multiplexing-Funktion in einen 
Timer-Interrupt packen (Falls deine Tasten an einem Interrupt hängen 
muss der Timer Interrupt höhere Priorität haben) der zyklisch dein 
Programm (auch die Entprellung, was ggf. nur zu einer höheren 
Entprellzeit führt) unterbricht und das Display immer zuerst bedient.

#EDIT# Karl heinz war schneller

von Hans (Gast)


Lesenswert?

Aha okay, danke schonmal, dann les ich mir aus dem AVR GCC Tut die Timer 
mal durch, und guck b ich das so versteh, nur noch kurz ne Frage, wenn 
ich einen Timer in meinem Programm haben will, dann läuft das alles auf 
der Software oder? also ich brauch dafür keine Pins an dem Prozessor 
dafür, da im Timer Tut sowas davon steht, und das hab ich nicht ganz 
verstanden.
Wenn bei mir Fragen auftauchen dann guck ich mal in der SuFu ob ich was 
find ansonsten nehm ich diesen Thread.

Grüße Hans

von Karl H. (kbuchegg)


Lesenswert?

Ein Timer ist eine unabhängige Hardwareeinheit in deinem Prozessor.

Stell dir als Analogie zb deine Armbanduhr vor.
Die habe eine Weckfunktion, so dass sie zu jeder vollen Minute ein 
Signal von sich gibt. Und als braver Benutzer kannst du nicht anders als 
bei jedem Signal ins Badezimmer zu gehen und nachzusehen ob die Wanne 
voll ist.

Jetzt kannst du in Ruhe ein Buch lesen während deine Wanne sich füllt. 
Deine Uhr erinnert dich brav jede Minute daran, kurz nachzusehen ob die 
Wanne voll ist. Und da du dich dem Signal nicht entziehen kannst, läufst 
du auch nicht Gefahr, dass die Wanne überläuft. Obwohl du eigentlich ein 
Buch liest.

von Hans (Gast)


Lesenswert?

Jo das Grundprinzip hab ich auch verstanden, und den Code eigentlich 
auch, jetzt gibts da ja den tollen Code für eine Uhr, und da ich ja eine 
super 7-Segment Anzeige hab will ich auch ausprobieren, aber leider ist 
der Code fehlerhaft und da ich mich nochnicht damit beschäftigt hab weiß 
ich au net an was es liegen kann, kann mal vllt einer kurz danach 
schauen?
1
/*Hinweis: Der Timer ist für die 1Mhz vom interne Takt des ATMEGAs*/
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
 
5
//Variablen für die Zeit
6
volatile unsigned int  millisekunden=0;
7
volatile unsigned int  sekunde=0;
8
volatile unsigned int  minute=0;
9
volatile unsigned int  stunde=0;
10
main()
11
{
12
 
13
   //Timer 0 konfigurieren
14
 
15
   TCCR0 =(1<<WGM01) |(1<<CS01);
16
   OCR0=125;
17
 
18
   //Compare Interrupt aktivieren
19
   TIMSK|=(1<<OCIE0);
20
   //Globale Interrupts aktivieren
21
   sei();
22
   while(1)
23
   {
24
    /*Hier kann man die aktuelle Zeit ausgeben werden*/
25
   }
26
 
27
}
28
 
29
 
30
//Der Compare Interrupt Handler
31
//Wird aufgerufen wenn TCNT0 = 125
32
{ISR(TIMER0_COMP_vect)            //### HIER KOMMT DER FEHLER IM COMPILER 
33
{
34
   millisekunden++;
35
   if(millisekunden==1000)
36
   {
37
      sekunde++;
38
      millisekunden=0;
39
      if(sekunde==60)
40
      {
41
         minute++;
42
         sekunde=0;
43
      }
44
      if(minute ==60)
45
      {
46
        stunde++;
47
        minute=0;
48
      }
49
   }
50
}


../Atmega_Testboard.c:946: error: expected identifier or '(' before '{' 
token


Danke schonmal, nur das ich weiter lernen kann ;)

Hans

von STK500-Besitzer (Gast)


Lesenswert?

>{ISR(TIMER0_COMP_vect)            //### HIER KOMMT DER FEHLER IM COMPILER

Was soll auch die geschweifte Klammer vor "ISR"?
Und genau den Fehler markert dir der Compiler an.

von Karl H. (kbuchegg)


Lesenswert?

1
//Der Compare Interrupt Handler
2
//Wird aufgerufen wenn TCNT0 = 125
3
{ISR(TIMER0_COMP_vect)            //### HIER KOMMT DER FEHLER IM COMPILER 
4
{

Was soll die { vor ISR?

Eine ISR ist für dich als C-Programmierer eine Funktion wie jede andere 
auch. Ledglich der Funktionskopf sieht ein klein wenig anders aus.

von Hans (Gast)


Lesenswert?

So jetz tklappt die Uhr und das Programm an sich hab ich jetzt auch 
verstanden, nur sind da noch Sachen, die jetzt nicht beschrieben worden 
sind und die mich aus der Bahn werfen:
1
    TCCR0 |= (1<<CS00)|(1<<CS02);

Das ist mir ja klar, hier wird der Timer mit seinen Bits so gesetzt, 
dass er jeden 1024sten Takt nur inkrementiert wird, soweit alles klar!
Später im fertign Programm heißt die Timer-Zuweißung dann:
1
 TCCR0 =(1<<WGM01) |(1<<CS01);

Hier irritiert mich das WGM01, es ist nicht gesat worden was das ist, 
und oben steht ja immer nur CS00 CS01 oder CS02, für die 
initialisierung.

Zu guter letzt, steht da noch das:
1
 OCR0=125;

Für was genau steht das? Es wird hier ein Wert gesetzt, der dann später 
in der Funktion gebraucht wird, um den Zeipunkt der Ausführung zu 
setzen, oder wie darf ich das verstehen?

Ich bin sehr wissenshungrig, und will das alles lernen drum frag ich 
jetzt euch mal ihr kennt euch da ja richtig aus ;)

Hans

von Christian P. (christian_paier)


Lesenswert?

WGM steht für Waveform-Generation-Mode
OCR0 steht für Output-Compare-Register-Timer0

Das sind ein paar Funktionen die ein AVR-Timer noch mit sich bringt.

Antworten darauf findest du mit STRG+F im Datenblatt deines µC

in deinem geposteten Code kann ich TCCR0 |= (1<<CS00)|(1<<CS02); 
nirgends entdecken.

von Dennis G. (hans_angemeldet)


Lesenswert?

Jo die letzte Zeile steht in dem Tutorial, bei der Timerinitialisierung, 
und ich hab gedacht das geht dann nacher im Program auch nur mit der 
Zeile und nicht mit dem WGM, da ich ja nicht weiß für was das genau 
steht, und was das WGM steht.
Danke für den Rest,ist immer besser wenn man weiß für was die Sachen 
stehn, dann kann man(n) sich das besser merken ;)

Hab mich jetzt nach einiger Zeit auch bei euch angemeldet, da ich 
vermute das ich bei euch bleiben werde ;) macht echt Spaß bei euch und 
das große Tut find ich spitze!

Euer Hans_angemeldet

von Dennis G. (hans_angemeldet)


Lesenswert?

Hab jetzt mal etwas herrumprobiert und hab festgestellt, dass sich die 
Taster über nen Interrupt viel besser auswerten lassen, aber ich muss 
dazusagen, dass der Timer ja parallel zum Programm läuft, aber der 
Zeitpunkt nach dem Overflow wird dann ja im Programm ausgeführt.
Also darf meine Interrupt-Funktion nicht allzu lang sein oder seh ich da 
was flasch?

Schöne Pfingsten Noch
Hans

von Karl H. (kbuchegg)


Lesenswert?

Dennis G. schrieb:
> Hab jetzt mal etwas herrumprobiert und hab festgestellt, dass sich die
> Taster über nen Interrupt viel besser auswerten lassen, aber ich muss
> dazusagen, dass der Timer ja parallel zum Programm läuft, aber der
> Zeitpunkt nach dem Overflow wird dann ja im Programm ausgeführt.
> Also darf meine Interrupt-Funktion nicht allzu lang sein oder seh ich da
> was flasch?

Das siehst du schon richtig.
Wenn du dir allerdings mal ausrechnest (oder überschlägig abschätzt), 
wieviel Rechenzeit prozentual in der ISR draufgeht, dann merkst du: Das 
sind wenige Prozente, wenn überhaupt.

Trotzdem sollten ISR kurz gehalten werden. Während eine ISR läuft wird 
keine andere ISR abgearbeitet. Immer nur nacheinander. Wenn du also 
jeder ISR die Chance geben willst möglichst schnell nach Auftreten des 
zugehörigen Ereignisses gestartet zu werden, dann ist die Devise: Fasse 
dich kurz.

Kleinere Berechnungen sind in einer ISR ok. Sobald es aber länger wird, 
oder gar Ausgaben gemacht werden, dann sieht ein bewährter 
Programmaufbau so aus
1
volatile uint8_t updateDisplay;
2
3
ISR( ... )
4
{
5
  millisek++;
6
  if( millisek == 1000 ) {
7
    millisek = 0;
8
9
    sek++;
10
    if( sek .....
11
    ...
12
13
    updateDisplay = 1;
14
  }
15
}
16
17
int main()
18
{
19
  ....
20
21
  updateDisplay = 0;
22
23
  while( 1 ) {
24
25
    ....
26
27
    if( updateDisplay )
28
    {
29
      updateDisplay = 0;
30
31
      // mache die Ausgabe
32
    }
33
  }
34
}

die ISR 'benachrichtigt' die Hauptschleife in main, dass es am Display 
etwas zu tun gibt. Sowas nennt man Jobflags: Ist das Flag gesetzt, gibt 
es einen Job abzuarbeiten.

von Dennis G. (hans_angemeldet)


Lesenswert?

Hallo wieder einmal,

Ich hab jetzt wieder etwas herumprobiert, und hab jetzt meine Taster nur 
noch über die auslesen lassen wollen, und dann die Flags setzen, sodass 
die while(1)-Schlaufe das dann auswerten kann.

so jetzt zum Code:
1
ISR(TIMER0_COMP_vect)
2
{
3
   
4
       if(!(PINB & (1<<PB0)))
5
    {
6
            Taster_one=1;        //Global angelegt
7
            interrupt_wait=500;  //Global angelegt
8
          } 
9
}
10
11
//Main
12
//
13
int main(void)
14
{
15
16
   Init(); 
17
18
   //Timer 0 konfigurieren
19
   //
20
   TCCR0 =(1<<WGM01) |(1<<CS01);
21
   OCR0=125;
22
 
23
   //Compare Interrupt aktivieren
24
   TIMSK|=(1<<OCIE0);
25
   //Globale Interrupts aktivieren
26
   sei();
27
28
29
   while(1)       //Mainloop
30
   {
31
32
      DisplayText(H,E,L,L,O);  //Funktion, die ich geschrieben
33
                               //hab, wird  ordungsgemäs angezeigt ;)
34
35
36
      if(Taster_one>0)
37
    {
38
       GreenLED(ON);
39
             RedLED(OFF);
40
          }
41
    else
42
    {
43
       RedLED(ON);
44
             GreenLED(OFF);
45
          }
46
   }
47
48
   return (0);     //wird nie erreicht
49
}

Das Problem liegt einach darin, der Code geht zwar, aber der Taster wird 
nicht ausgewertet, also Taster_one wird nicht 1 wenn der Code von ISR in 
der Main-Loop stht, dann gehts :(

Quizfrage was ist falsch ;) :D ich kanns net herrausfinde
grüßle Hans

von Peter D. (peda)


Lesenswert?

Dennis G. schrieb:

> Das Problem liegt einach darin, der Code geht zwar, aber der Taster wird
> nicht ausgewertet
1
volatile uint8_t Taster_one;


Peter

von Dennis G. (hans_angemeldet)


Lesenswert?

Und was macht das dann jetzt genau anderst? ich werd mir mein C-Buch 
erst in ner Woche kaufen, also hoff ich ihr habt noch einsicht ;)

Grüßle

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.