Ich habe einen Motor mit einem Hall Sensor. Der hall Sensor aktualisiert eine variable mit einem Interrupt.
Nun soll der Motor auf eine bestimmte pos. fahren soll. Da das Programm nichts anderes machen soll, bis die pos. erreicht ist, ist hier eine while schleife eigentlich optimal.
Beispiel Code:
const int In_Motor_Pos = 3; // Eingang Hall Sensor vom Motor
const int Output = A1; // Ausgang Motor hochfahren
uint64_t Motor_Pos = 0; // Position vom motro (Hall Sensor)
void setup() {
// Pc ausgabe
Serial.begin(9600);
Serial.println("Neustart");
// IO´s Definieren
pinMode(In_Motor_Pos, INPUT );
pinMode(Output , OUTPUT);
// Interrupt für Hall Sensor
attachInterrupt(digitalPinToInterrupt(In_Motor_Pos), Hall_Sensor, RISING ); // Interupt erstellen
// Motor An
digitalWrite(Output, HIGH);
// Auf Pos. Fahren
while (Motor_Pos <= 100){};
// Motor Aus
digitalWrite(Output, LOW);
}
void loop() {}
void Hall_Sensor(){
Motor_Pos+=1;
Serial.println((int)Motor_Pos);
}
Leider funktioniert dies nicht. Das Problemm kann behoben werden, indem man ein Delay in die schleife einbaut.
z.B.:
// Auf Pos. Fahren
while (Motor_Pos <= 100){
delay(30);
};
Dies finde ich aber nicht ideal gelöst, zumal ich auch nicht genau bestimmen kann, wie groß die delay zeit sein muss.
OT:
Eigentlich hätte ich erwartet, dass gleich ein Mensch aus den Büschen gehüpft kommt und behauptet, dass da ein volatile fehlt.
Aber da habe ich mich wohl zum Glück geirrt.
Ich vermute mal das das fehlende volatile irgendwie daran liegt (das ist ja eigentlich auch eine). Ich sehe sie aber nicht. Erleuchte mich bitte.
ATOMIC_BLOCK sorgt ja nur für das atomare auslesen.
Hmmm....
Wenn man sich util/atomic.h anschaut, findet man ein paar __asm__ volatile ("" ::: "memory");
Es setzt also zusätzlich die Memory Barrieren.
Eigentlich sogar zu oft, denn das verwendete cli()/sei() tut das ja auch nochmal.
Ok, danke.
Wenn das volatile implizit in den Macros (mehrfach) mit gesetzt wird, dann wäre es ja wohl auch nicht schädlich, wenn man es bei der Variablendeklaration explizit mit angibt.
Es würde in meinen Augen aber klar im Code Anzeigen, dass diese Variable gesondert behandelt wird. Sozusagen als "Denkhilfe".
volatile und memory barriers sind zwei verschiedene paar Schuhe.
volatile unterbindet ALLE Optimierungen auf der Variablen (auch in der ISR)
Eine memory barrier sorgt nur dafür dass die Variablen neu eingelesen werden.
Ich glaube, jetzt habe ich es?
Das inline ASM volatile wirkt hier nur innerhalb des ATOMIC_BLOCK (bzw. wenn man mit cli/sei arbeitet auch dort) aber nicht in der ISR.
Das volatile im Code bei der Anlage der Variablen wirkt überall.
Eigentlich darf der Compiler alle Statements wild durcheinander würfeln, zwecks Optimierung, solange das richtige dabei raus kommt.
Das macht er auch!
Aber!
z.B. bei cli() und sei() ist die Position, an denen das stattfindet Überlebens wichtig.
Darum wird unterbunden, dass er sie verschieben darf.
Alle anderen Optimierungen finden unbehindert statt.
Ja!
Ein kapitaler Stock in den Speichen des Optimizers.
Da die Variable Motor_Pos mit 0 initialisiert wurde, kann der Compiler hier ein Programm-Stop erzeugen.
Falls in {} eine Funktion aufgerufen wird, (z.B. delay), könnte es sein, dass diese Motor_Pos verändert.
volatile wäre natürlich auch halb richtig gewesen.
Dass eine 64bit Variable generell atomic gelesen werden muss (was hier while <100 praktisch egal ist), stimmt natürlich auch.