Dann bildet man neben dem Hard Timer noch ein Soft Timer.
Alternativ benutzt du für Wartezeiten einfach einen eigenen HardTimer
und wartes drauf, dass er abgelaufen ist.
Also ich seh bei dem Thema nun kein großes Problem.
Dr. Emmett Brown schrieb:> ch schrieb:>> Damit verschiebst Du das Problem in die Zukunft.>> Mit einem µs-Timer in ca. 600000 Jahren.
Er kann zwischendurch den Timer oder die Überläufe zurücksetzen. Das
hält dann ca. eine Ewigkeit.
Das würde funktionieren, wenn sichergestellt ist, dass der Timer nicht
"full speed" als mit Prozessortakt, läuft. In meinem Anwendungsfall ist
das aber gegeben.
ch schrieb:> Das würde funktionieren, wenn sichergestellt ist, dass der Timer nicht> "full speed" als mit Prozessortakt, läuft. In meinem Anwendungsfall ist> das aber gegeben.
Meine Güte, ist denn das so schwierig?
In der Overflow-ISR deines mit 3,5GHz getakteten Timers:
1
staticuint8_tms_timer;
2
ms_timer++;
3
if(ms_timer==(3500000000UL/65536/1000))
4
{
5
millis++;
6
ms_timer=0;
millis ist eine globale Variable und mit den Rundungsfehlern mußt du
leben.
danvet schrieb:> UINT ist doch unsigned ???
ja. Sag ich doch, dass es richtig ist.
Es gibt aber auch Zeitgenossen, die mitlesen und nicht erkennen, wo der
springende Punkt liegt. Viele sehen in Datentypen nicht mehr als eine
Art 'schmückendes Beiwerk'.
Hallo,
die meisten in Prozessoren verwendeten Timer können das ohne weiteres
und ohne langes Nachdenken des Programmierers: vom eingestellten
Startwert wird heruntergezählt auf 0, ein IRQ ausgelöst und der
Startwert wieder geladen. Die IRQs folgen also äquidistant aufeinander
ohne jeden Programmeingriff.
Das Problem existiert also eigentlich garnicht.
Georg
Georg schrieb:> Hallo,>> die meisten in Prozessoren verwendeten Timer können das ohne weiteres> und ohne langes Nachdenken des Programmierers: vom eingestellten> Startwert wird heruntergezählt auf 0, ein IRQ ausgelöst und der> Startwert wieder geladen. Die IRQs folgen also äquidistant aufeinander> ohne jeden Programmeingriff.>> Das Problem existiert also eigentlich garnicht.>> Georg
Jepp, was wiederum heißt, dass "while(delay);" schlechter
Programmierstil ist.
Es sei denn, man bezweckt was ganz spezielles damit.
ch schrieb:> In Mikrocontrolleranwendungen gibt es oft das Problem, eine Schleife mit> konstanter Frequenz durchlaufen zu lassen.
Die bessere Variante ist es allerdings, nicht solange Däumchen zu
drehen, bis eine bestimmte Zeit (voraussichtlich) um ist. Wobei es auch
Ausnahmen gibt, wenn die Zeiten sehr kurz sind und nicht mit
UNterbrechungen zu rechnen ist.
Die weit aus bessere Variante ist es, den Timer so aufzusetzen und so zu
verwenden, dass er in den gewünschten regelmässige Zeitabständen das
Startsignal für die nächste Abarbeitung von Funktionalitäten gibt.
Georg schrieb:> die meisten in Prozessoren verwendeten Timer können das ohne weiteres> und ohne langes Nachdenken des Programmierers: vom eingestellten> Startwert wird heruntergezählt auf 0, ein IRQ ausgelöst und der> Startwert wieder geladen. Die IRQs folgen also äquidistant aufeinander> ohne jeden Programmeingriff.>> Das Problem existiert also eigentlich garnicht.
Genau so ist es. Man muss in der Software keine Probleme lösen, die man
schon von der Hardware erschlagen bekommt.
danvet schrieb:> Jepp, was wiederum heißt, dass "while(delay);" schlechter> Programmierstil ist.> Es sei denn, man bezweckt was ganz spezielles damit.
Meistens macht das nur Probleme.
Das hört sich ziemlich gut an.
Hier mal der Vorschlag umgesetzt auf einem Arduino Due. Es läuft ca.
eine Sekunde und bleibt dann hängen.
Sieht jemand den Fehler?
ch schrieb:> uint8_t Start;> uint8_t Delay;
Vergessen.
uint8_t ist keine gute Idee.
Der springende Punkt ist das unsigned. Machst du aber Rechnungen mit
uint8_t so wird das int (und zwar signed int) gerechnet. Genau das
kannst du aber nicht brauchen! Du willst und musst die Berechnung
unsigned halten.
Wozu das ganze? millis liefert dir einen unsigned long. Ob du den jetzt
wie ein wilder runter castest oder gleich alles in unsigned long machst,
schenkt sich nichts.
>Der springende Punkt ist das unsigned. Machst du aber Rechnungen mit>uint8_t so wird das int (und zwar signed int) gerechnet
Danke für die Antwort. Bist Du Dir aber sicher?
int8_t Signed
uint8_t Unsigned
https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h
ch schrieb:> uint8_t systemTime()> {> return millis();> }
laut Arduino.h:
>unsigned long millis(void);
unsigned long vs uint8_t ;) irgendwann ist der uint8_t voll...
ch schrieb:>>Der springende Punkt ist das unsigned. Machst du aber Rechnungen> mit>>uint8_t so wird das int (und zwar signed int) gerechnet>> Danke für die Antwort. Bist Du Dir aber sicher?>> int8_t Signed> uint8_t Unsigned>> https://en.wikibooks.org/wiki/C_Programming/C_Refe...
Das Problem ist nicht der Typ sondern die Berechnung. Siehe hier:
http://en.cppreference.com/w/cpp/language/implicit_cast
Entsprechender Auszug:
unsigned char or unsigned short can be converted to int if it can hold
its entire value range, and unsigned int otherwise.
ch schrieb:> Danke für die Antwort. Bist Du Dir aber sicher?
Ich bin mir sicher, dass sich Karl Heinz sicher ist. Die Datentypen
selbst sind zwar unsigned, die Berechnung wird in diesem Fall jedoch als
signed int durchgeführt. Kompiliere ich folgenden Code,
1
uint8_tValue=3;
2
Value=2*Value;
so erhalte ich eine Warnung:
1
warning: conversion to ‘uint8_t {aka unsigned char}’ from ‘int’ may alter its value [-Wconversion]|
Das ganze nennt sich integral promotion.
Konkret geht es um diese Zeile:
1
while((systemTime()-Start)<Delay);
Alle Operanden sind ein uint8_t und werden somit zu einem signed int
gecastet. Dementsprechend wird die Berechnung als signed durchgeführt.
be s. schrieb:> Alle Operanden sind ein uint8_t und werden somit zu einem signed int> gecastet. Dementsprechend wird die Berechnung als signed durchgeführt.
Und damit natürlich auch der Vergleich.
> Bist Du Dir aber sicher?
Ja, ich bin mir absolut sicher. So sind nun mal die C Regeln.
In einer Operation werden alle beteiligten Operanden immer auf den
höchsten Types eines der beiden Operanden hochgehoben, mindestens aber
int.
> UINT8 startTime;> UINT8 delay = 20;>> startTime = currentTime();>> while( (currentTime() - startTime) < delay);>
Der oben gepostete Code war mit UINT8.
Mein Code ist mit uint8_t.
Seht Ihr da einen Unterschied?
ch schrieb:> Der oben gepostete Code war mit UINT8.> Mein Code ist mit uint8_t.> Seht Ihr da einen Unterschied?
Nein. Sollte an und für sich beides auf unsigned char hinauslaufen.
Aber der Ansatz an sich ist zweifelhaft. Von daher solltest Du lieber
das konkrete Problem beschreiben, welches du eigentlich lösen willst.
be stucki (bestucki) schrieb
>Konkret geht es um diese Zeile:>>while( (systemTime()-Start ) < Delay );>>Alle Operanden sind ein uint8_t und werden somit zu einem signed int>gecastet. Dementsprechend wird die Berechnung als signed durchgeführt.
Hmm, ich hätte gedacht, dass die Berechnung folgendermaßen durchgeführt
wird:
(uint8_t)((uint8_t)systemTime()-(uint8_t)Start ) < (uint8_t)Delay
Dazu folgender Test:
1
voidsetup()
2
{
3
Serial.begin(115200);
4
5
uint8_ta;
6
uint8_tb;
7
8
a=250;
9
b=255;
10
Serial.print("a= ");Serial.println(a);
11
Serial.print("b= ");Serial.println(b);
12
Serial.println("Is (b-a < 6) true or false?");
13
14
if(b-a<6)Serial.println(" it is true");
15
Serial.println("");
16
Serial.println("");
17
18
a=255;
19
b=4;
20
Serial.print("a= ");Serial.println(a);
21
Serial.print("b= ");Serial.println(b);
22
Serial.println("Is (b-a < 6) true or false?");
23
24
if(b-a<6)Serial.println(" it is true");
25
Serial.println("");
26
}
27
28
voidloop()
29
{
30
31
}
Das Ergebnis ist
a= 250
b= 255
Is (b-a < 6) true or false?
it is true
a= 255
b= 4
Is (b-a < 6) true or false?
it is true
Arduino?
Dann sind die Zeiten alle unsigned long zu definieren. Und auch so damit
zu rechnen. uint8_t macht da wenig Sinn.
Hier mal ein Vorschlag in "Arduino", etwas Ressourcen verplempernd, aber
das spielt ja hier erstmal keine Rolex.
ch schrieb:> a= 255> b= 4> Is (b-a < 6) true or false?> it is true
Genu hier liegt dein Denkfehler:
x - 255 mit x[0...255] ergibt immer eine negative Zahl oder null. Somit
ist deine Bedingung immer wahr. Daher musst du dafür sorgen, dass die
Subtraktion als unsigned Operation durchgeführt wird.
ch schrieb:> Hmm, ich hätte gedacht, dass die Berechnung folgendermaßen durchgeführt> wird:
Nein.
Genau deswegen gibt es Literatur, in der die Regeln genau und
ausführlich vermittelt werden.
Kurz gesagt: Nein, C funktioniert nicht so.
> a= 255> b= 4> Is (b-a < 6) true or false?> it is true
4 - 255 ergibt -251. Und das ist selbstverständlich kleiner 6.
Und genau das willst du nicht haben. Du willst nicht haben, dass das
Ergebnis ein Vorzeichen besitzt. Dazu muss aber die ganze Berechnung und
der ganze Vergleich unsigned durchgeführt werden.
Das ist prinzipiell kein Problem, solange man berücksichtigt, dass in C
niemals in einem kleineren Datentyp als int gerechnet wird. In diesem
Zusammenhang spielt es daher keine Rolle, dass a und b als unsigned char
definiert sind. Denn beide werden zuerst auf den Datentyp int
hochgehoben, ehe die Berechnung überhaupt startet. Wichtig: int(!) -
nicht unsigned int! Denn die Regeln sagen auch, dass in so einem Fall
der erste Datentyp genomen wird, der alle Werte aufnehmen kann. Und das
ist nun mal ein int. Ein unsigned char hat einen Wertebereich von 0 bis
255 - passt perfekt in einen int hinein, womit sich über die Hintertür
wieder ein Vorzeichen einschmuggelt, welches selbstverständlich dann in
weiterer Folge berücksichtigt und ausgewertet wird.
ch schrieb:> scheint dann zu funktionieren, wenn man in die Zeile mit dem while einen> typecast einfügt:>> while( (UINT8)(currentTime() - startTime) < delay);
Und jetzt lehnst du dich zurück, denkst noch mal über alles nach, was
dir heute erzählt wurde und lässt dir durch den Kopf gehen, WARUM in
diesem Fall das richtige passiert.
Es ist wichtig das du verstehst, was da warum passiert.
>Und jetzt lehnst du dich zurück, denkst noch mal über alles nach, was>dir heute erzählt wurde und lässt dir durch den Kopf gehen, WARUM in>diesem Fall das richtige passiert
Ich weis, warum das richtige passiert. Nur leider habe ich eine Weile
gebraucht, den Fehler zu finden. Hättest Du weiter oben nicht Folgendes
geschrieben
Karl Heinz (kbuchegg) (Moderator) schrieb
>>danvet schrieb:>> UINT ist doch unsigned ???>ja. Sag ich doch, dass es richtig ist.>Es gibt aber auch Zeitgenossen, die mitlesen und nicht erkennen, wo der>springende Punkt liegt. Viele sehen in Datentypen nicht mehr als eine>Art 'schmückendes Beiwerk'.
und erwähnt dass in Beispiel von davnet der typecast fehlt, wäre auch
alles etwas schneller gegangen.
Karl H. schrieb:> while( (currentTime() - startTime) < delay);
Ähemm.. sind ja alles vorzeichenlose Bytes, also beispielsweise:
currentTime = 254;
starttime = 250;
delay = 150;
Hab ich heut schon zuviel Rotwein intus, oder..?
Also wenn es bei mir auf kleinere, aber präzise Delays ankommt, dann
reserviere ich dafür einen Timer, den ich geeignet programmiere und
starte.
Wenn es lediglich größere Wartezeiten sind, dann setze ich einen
"delayed_Event", der vom Timertick des Systems verwaltet wird. Dieser
zählt die Millisekunden per long, also 32 Bit - UND!! er zieht am
Tagesende einen ganzen Tag ab (sowohl bei der Uhrzeit als auch bei den
verwalteten delayed Events). Da klappt immer, ist sauber und einfach zu
benutzen.
W.S.
ch schrieb:> und erwähnt dass in Beispiel von davnet der typecast fehlt, wäre auch> alles etwas schneller gegangen.
Da hast du recht. Allerdings muss ich gestehen, dass ich da auch zu spät
geschaltet habe.
W.S. schrieb:> Karl H. schrieb:>> while( (currentTime() - startTime) < delay);>> Ähemm.. sind ja alles vorzeichenlose Bytes, also beispielsweise:>> currentTime = 254;> starttime = 250;> delay = 150;>> Hab ich heut schon zuviel Rotwein intus, oder..?
Mag sein. Aber bei einem unsigned char soll es auch schon mal
vorgekommen sein, dass ein Überlauf zwischendurch passiert und
currentTime dann effektiv kleiner als startTime ist.
Was an und für sich keine Rolle spielt, solange die Arithmetik unsigned
durchgeführt wird. Was sie hier allerdings nicht wird, da da noch die
"es wird nicht kleiner als int gerechnet" Regel mit ins Spiel kommt.
Sobald die uint8_t auf mindestens uint16_t geändert werden, ist dieses
Problem keines mehr und das ganze läuft auch ohne unsigned cast des
Subtraktionsergebnisses völlig richtig ab.
ch schrieb:>> [64 bit]> Damit verschiebst Du das Problem in die Zukunft.
500 Millionen Jahre bis die ersten Reklamationen eintrudeln, bis dahin
sollte Version 2 und ein kostenloses Update auf nen 128 bit Zähler
ausgerollt sein.
Karl Heinz (kbuchegg) (Moderator) schrieb:
>Sobald die uint8_t auf mindestens uint16_t geändert werden, ist dieses>Problem keines mehr und das ganze läuft auch ohne unsigned cast des>Subtraktionsergebnisses völlig richtig ab.
Naja, der Arduino Due ist ein ARM-Controller mit 32 bit, da führt das
weglassen des typcast zur Fehlfunktion.
Damit die Routine portabel auf verschiedenen Architekturen funktioniert,
sollter der typecast auf jeden Fall drinn bleiben.
Meine Routinen laufen auf mindestens 5 verschiedenen
Controller-Architekturen.
Und dann wollen wir ein Delay, dass mehr als 255 irgendwas beträgt und
schwupp ist sie auch nicht korrekt. Warum du unbedingt einen uint8_t
verwendest auf einem 32bitter ist mir schleierhaft.