Forum: Mikrocontroller und Digitale Elektronik Zeit für die Programmbearbeitung berechnen.


von Christian R. (holle)


Lesenswert?

Hallo,
ich habe folgendes Problem:
Von der Main-While-Schleife wird immer eine Funktion aufgerufen welche 
Ports steuert und dabei immer wieder einen Taster-Zustand abfragt.
Wenn der Taster gedrückt ist zählt eine Vatiable hoch (statisch). Beim 
ersten "Impuls" (Variable von 0 auf 1) wird ein Delay von 100ms 
ausgeführt um eine Fehlinterpretation vom Prellen zu unterbinden. Beim 
loslassen des Tasters wird ebenfalls ein Delay von 100ms ausgeführt.
...schon klar, 100ms sind viel, aber diese Funktion ist nicht 
zeitkritisch.
Bei einem lange Druck der Taste (z.B. 2 Sekunden) soll eine andere 
Aktion ausgeführt werden (deswegen die hochzählende Variable).

Wie kann ich nun ausrechnen, nach wievielen Funktionsaufrufen die Zeit 
erreicht ist?
Ich kenne die Frequenz, aber wieviele Takte nötig sind um die Funktion 
abzuarbeiten weiß ich nicht. Wie kann man sowas errechnen?

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

sowas lässt sich mit delays nicht vernünftig lösen.

Nutze Timer, dann hst du keine Probleme mit deinen Funktionen.

von Peter D. (peda)


Lesenswert?


von Stefan F. (Gast)


Lesenswert?

Zustandsautomaten sind sicher auch hilfreich.

von Christian R. (holle)


Lesenswert?

Vielen Dank, ich habe gerade mal das mit den Timern überflogen. Das 
scheint perfekt für meine Anwendung zu sein.
Auch vielen Dank für die Tastenentprellung, aber ich schau erst mal ob 
das mit den 100ms ausreichend ist, dann spare ich eine Menge Code (so 
üppig ist der Speicher des ATtiny2313 ja nicht).
Sollte das nicht klappen komme ich darauf zurück.
Da ich das für eine Projektarbeit brauche würde ich gerne so viel wie 
möglich selber schreiben, ansonsten habe ich ein 
Mords-Quellenangabe-Verzeichnis, was nicht unbedingt gut ankommt.
Ob ich einen Code selber geschrieben habe, oder ob der von jemand 
anderes stammt wird ein erfahrener Prüfer sofort sehen 
(Programmier-Stil). Ich werde meinen Code sicher nicht so perfekt hin 
bekommen, wie er hier verfügbar ist, aber wenn er funktioniert (und ich 
am Ende alles auf den ATtiny bekomme) sollte das ganz gut ankommen.

Die Timer scheinen auch von der Performance her gut zu sein, weil das ja 
parallel Hardware-Seitig mitläuft. Code spart man damit allemal.

Vielen Dank :-)

von Tony S. (tooony)


Lesenswert?

- Zustandsautomat
- Handling mit Flag-Variablen
- je nach dem wie ausgelastet dein AVR ist kann man sonst auch auf eine 
millis() Funktion wie beim Arduino zurückgreifen (basierend auf einem 
Timer):  https://github.com/zkemble/millis

von HyperMario (Gast)


Lesenswert?

Christian R. schrieb:

> Wie kann ich nun ausrechnen, nach wievielen Funktionsaufrufen die Zeit
> erreicht ist?

Einen Zahler hochzählen wenn die Taste gedrückt wird
Selbigen auf 0 stellen wenn Sie losgelassen wurde
Den delay an das Ende der Schleife legen

Dann kannst du die unterschiedlichsten Aktionen je nach Zählerstand 
ausführen
Der Delay kann auch beleibig klein werden (dann werden halt der 
Zählerwerte größer)

von Peter D. (peda)


Lesenswert?

Christian R. schrieb:
> Auch vielen Dank für die Tastenentprellung, aber ich schau erst mal ob
> das mit den 100ms ausreichend ist, dann spare ich eine Menge Code

Da habe ich so meine Zweifel. Ich optimiere meinen Code recht gut.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Ich optimiere meinen Code recht gut.

Das würde ich für den konkreten Fall der Tastenentprellung bedenkenlos 
unterschreiben. Da ist alles optimiert, was man unter C optimieren kann.

Aber ganz sicher würde das nicht für den allgemeinen Fall deiner Codes 
unterschreiben...

von Christian R. (holle)


Lesenswert?

Irgendwie komme ich nicht weiter.

Ich habe eine Funktion welche immer wieder aufgerufen wird und einen 
übermittelten Wert auf 2 7-Segment-Anzeigen anzeigt.

Nun habe ich zum Testen, ob das mit dem Timer klappt einfach mal 
folgendes versucht:
1
    // Interrups
2
    TCCR1A = ((1<<CS00) | (1<<CS02));    // Counter aktivieren mit einem Prescaler von 1024
3
  
4
    while (1) 
5
    {
6
        if (TCNT1 > 21600) zeigeZeichen(22);
7
        else zeigeZeichen(11);
8
    }
9
    return;

Da der Timer 16 Bit hat und ich mit einer Frequenz von 11.059200 MHz 
takte sollten doch eigentlich 2 Sekunden lang eine "11" angezeuigt 
werden, danach für ca. 4 Sekunden eine "22" und dann wieder von vorne 
beginnend mit der "11" (sofern der Counter wieder bei 0 anfägt).

Es wird aber lediglich die 11 angezeigt und die 22 erscheint niemals.
Was mache ich da falsch?

Ich möchte eigentlich nur den Timer lesen (und ggf. auf 0 setzen) 
können, ohne dass ein Interrupt ausgelöst wird. Alle Pins sind 
anderweitig belegt und ein Interrupt wäre da störend.

Was mache ich falsch?

von Stefan F. (Gast)


Lesenswert?

> TCCR1A = ((1<<CS00) | (1<<CS02));

Fehler: Die Bits CS00 und CS02 befinden sich im Register TCCR1B!

von Christian R. (holle)


Lesenswert?

JAAAAAA :-)
Genau das war es, nun kappt´s wie es soll.
Vielen Dank :-)

von Christian R. (holle)


Lesenswert?

Peter D. schrieb:
> Christian R. schrieb:
>> Auch vielen Dank für die Tastenentprellung, aber ich schau erst mal ob
>> das mit den 100ms ausreichend ist, dann spare ich eine Menge Code
>
> Da habe ich so meine Zweifel. Ich optimiere meinen Code recht gut.


Du hast zu Recht gezweifelt.
Die 100ms merkte man doch stark, indem die 7-Segment-Anzeige verzögert 
ein-/ausgeschaltet wurde. Das wäre eigentlich nicht so tragisch, aber da 
die beiden Anzeigen abwechselnd angesteuert werden sah es schon 
merkwürdig aus, wenn erst eine ausgeht und 0,1s später die andere.
Wenn ich mit der Zeit runter gegangen bin wurde der optische Aspekt 
besser, aber dafür kam es zu Fehler (prellen).

Nun habe ich eine ganz simple Lösung gefunden. Das geht zum einen so 
schnell, dass man optisch keine Verzögerung in den Anzeigen mehr sehen 
kann und zum anderen ist es auch noch zuverlässiger.
Ich habe einfach sowohl beim Betätigen, wie auch beim Loslassen des 
Tasters eine Schleife laufen lassen, welche so lange läuft bis 250 
Zyklen der gleiche Wert stehen bleibt.
Wenn ein Taster nun also lange prellt läuft die Schleife etwas länger, 
wenn ein Taster gar nicht prellt läuft die Schleife 250 durchläufe, was 
bei 11,059200 MHz ungefähr 23ms sind.

Hier ist meine "Not-Lösung", welche jedoch erstaunlich gut funktioniert.
1
for (uint8_t i=250; i; i--) {
2
    if (PIND & 0x08) i = 250;
3
}
Beim Loslassen habe ich halt
1
if (!(PIND & 0x08))
 benutzt (das ! davor).
Ich habe den Taster (Billist-Ware aus China) nun bestimmt 50x betätigt, 
dabei hatte ich kein einzigen Tastenpreller :-)

von Thomas E. (picalic)


Lesenswert?

Christian R. schrieb:
> wenn ein Taster gar nicht prellt läuft die Schleife 250 durchläufe, was
> bei 11,059200 MHz ungefähr 23ms sind.

Sicher? Das wären ja ca. 1000 Takte pro Schleifendurchlauf - kann ich 
mir bei so einer simplen Schleife irgendwie nicht vorstellen.

von Christian R. (holle)


Lesenswert?

Habe ich falsch gerechnet?
11.059200 MHz / 1024 (Teiler) = 10800 Takte pro Sekunde
250 Durchläufe / 10800 = 0,02315 --> 23 ms

von Christian R. (holle)


Lesenswert?

Oh, da ist ja der Fehler...
Ich hatte kurz vorher noch mit dem Timer gerechnet, deshalb war ich 
immer noch bei dem Prescaler von 1024.
Das ist hier aber eine "normale" Schleife, und somit:

11059200 Takte / Sekunde (und nicht 10800)
Somit:
250 / 11059200 = 22,6 µs

Nun bin ich doch sehr verwundert, dass die Tastenentprellung so 
überhaupt funktioniert.
...egal es funktioniert und das sogar "Sau schnell" ;-)

Wenn ich mal einen Taster habe der vielleicht länger prellt, dann müsste 
ich auf einen 16 Bit Integer ausweichen und ein paar µs dazu geben.

von Peter D. (peda)


Lesenswert?

Christian R. schrieb:
> Die 100ms merkte man doch stark, indem die 7-Segment-Anzeige verzögert
> ein-/ausgeschaltet wurde.

Nun, das Multiplexen von Anzeigen macht man ja auch nicht in der 
Mainloop, sondern im Timerinterrupt. Da kann man dann auch gleich das 
Entprellen mit aufrufen.

von Stefan F. (Gast)


Lesenswert?

Peter D. schrieb:
> Nun, das Multiplexen von Anzeigen macht man ja auch nicht in der
> Mainloop, sondern im Timerinterrupt.

Normalerweise mache ich so viel wie möglich in der Main-Loop. Interrupts 
sollen im Idealfall nur Ereignisse zählen, Flags setzen oder Buffer 
übertragen.

Bei gemultiplexten Anzeigen stimme ich Dir jedoch zu, die flackern sonst 
nämlich sichtbar und das sieht einfach sch*** aus.

von Thomas E. (picalic)


Lesenswert?

Christian R. schrieb:
> 11059200 Takte / Sekunde (und nicht 10800)
> Somit:
> 250 / 11059200 = 22,6 µs

Diese Rechnung stimmt aber auch nicht, denn der Controller braucht 
sicher mehr, als nur einen Takt pro Schleifendurchlauf!

Wie hast Du denn festgestellt, daß die Entprellung funktioniert? Wenn 
Deine Anzeige bei gedrückter Taste etwas anderes anzeigt, als bei 
losgelassener Taste, heißt das ja noch lange nicht, daß sie ggf. beim 
Umschalten nicht ein paar mal hin- und her gesprungen ist. Das Auge ist 
ja recht träge...

: Bearbeitet durch User
von Christian R. (holle)


Lesenswert?

Stefanus F. schrieb:
> Bei gemultiplexten Anzeigen stimme ich Dir jedoch zu, die flackern sonst
> nämlich sichtbar und das sieht einfach sch*** aus.

Ich habe das Multiplexen in einer Funktion, welche ich aus der Main 
heraus aufrufe.
Da ist keiene Spur von Flackern zu sehen, alles sehr homogen.


Thomas E. schrieb:
> Christian R. schrieb:
>> 11059200 Takte / Sekunde (und nicht 10800)
>> Somit:
>> 250 / 11059200 = 22,6 µs
>
> Diese Rechnung stimmt aber auch nicht, denn der Controller braucht
> sicher mehr, als nur einen Takt pro Schleifendurchlauf!
>
> Wie hast Du denn festgestellt, daß die Entprellung funktioniert? Wenn
> Deine Anzeige bei gedrückter Taste etwas anderes anzeigt, als bei
> losgelassener Taste, heißt das ja noch lange nicht, daß sie ggf. beim
> Umschalten nicht ein paar mal hin- und her gesprungen ist. Das Auge ist
> ja recht träge...

Stimmt, die Schleife braucht auch etwas.

Mit dem Tastendruck habe ich die Anzeige aus-/eingeschaltet. Vorher (mit 
prellen) flackerte diese beim drücken öfters uns blieb dann an oder aus. 
Die hat halt nich einmal aus- oder eingeschaltet, sondern x mal und ist 
dann irgendwo stehen geblieben (an oder aus).
Nun habe ich den Taster ca. 50 mal betätigt und ich hatte weder 
Flackern, noch einen Fehlerhaften wechsel (an <--> aus).

Ich bin noch ein blutiger Anfänger, was die Programmierung von µC 
betrifft, somit bin ich für jeden Tipp (und auch konstruktive Kritik) 
dankbar.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Christian R. schrieb:
> Ich habe das Multiplexen in einer Funktion, welche ich aus der Main
> heraus aufrufe.
> Da ist keiene Spur von Flackern zu sehen, alles sehr homogen.

Dann hast du wahrscheinlich das Glück, dass jeder Durchlauf der 
Hauptschleife ungefähr gleich lange dauert.

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.