Wie implementiert man eine Verzögerungsfunktion in Keil ARM MDK, die eine bestimmte Zeit in Mikrosekunden wartet, die auf jede vernünftige Taktgeschwindigkeit neu kompiliert werden kann, die in den Keil-Projekteinstellungen definiert ist? Und das alles ohne Timer.
Der beste Ansatz ist IMHO, einen Hardware-Timer zu haben, der nie geschrieben wird, sondern einfach frei läuft. Dies ermöglicht es, auf einfache Weise beliebige abrufbare Zeitgeber für Dauern bis zur Hälfte der Länge des Hardware-Zeitgebers zu emulieren. Um einen Timer zu "starten", berechnen Sie einfach den Wert des Hardware-Timers, wenn er ablaufen sollte. Um zu sehen, ob ein Timer bereits abgelaufen ist, subtrahieren Sie die erwartete Ablaufzeit von der aktuellen Zeit (betrachten Sie beide Größen als vorzeichenlos) und prüfen Sie, ob das (vorzeichenlose) Ergebnis die Hälfte des maximalen Timerwerts überschreitet. Wenn ja, ist der Timer noch nicht abgelaufen.
Wenn man alternativ einen Timer zum Messen der Zeit seit dem Eintreten eines bestimmten Ereignisses wünscht, kann man einfach den Timerwert speichern, wenn das Ereignis aufgetreten ist, und später die Differenz zwischen dem gespeicherten Wert und der gegenwärtigen Zeit berechnen.
Sie müssen die Länge eines NOP bestimmen und es dann mit #Defines so machen, dass es basierend auf der Taktgeschwindigkeit die richtige Zahl einfügt.
Insbesondere möchten Sie die genaue Anzahl der Taktzyklen wissen, die erforderlich sind, um eine Schleife des Stils abzuschließen:
for(long i=0;i<NUMBER_OF_LOOPS_REQUIRED;i++)
{
__NOP();
}
Indem Sie #define for number of loops required rekonfigurieren, so dass es automatisch ist, basierend auf der angeforderten Verzögerung und der Taktgeschwindigkeit, mit der Sie gerade laufen. Das ganze lässt sich in ein Makro packen.
#if _Main_Crystal == 25000000
#define LOOP_DELAY 400
#elif _Main_Crystal == 16000000
#define LOOP_DELAY 256
#else
#error microsecond delay must be adjusted!
#endif
void usDelay( void )
{
for (int i = 0; i < LOOP_DELAY; i++)
{
SERVICE_WATCH_DOG();
}
}
wo SERVICE_WATCH_DOG()
ist ein Makro, um den Watchdog-Timer zu warten. Diese kann auch durch eine ersetzt werden NOP
.
Verwenden Sie eine Testfunktion, um herauszufinden, was Ihre LOOP_DELAY-Konstanten für jede Taktfrequenz sein müssen:
void TestDelay( void )
{
SetIOPin(); // Use a scope to start measuring elapsed time here.
usDelay();
ResetIOPin(); // use a scope to end measuring elapsed time here.
}
Eine Hardware-Timer-Referenz wird bevorzugt, da ein guter Optimierer die Schleife ganz entfernen oder sie basierend auf den Einstellungen ändern könnte. Das andere hier nicht erwähnte Problem mit Zeitschleifen ist, dass es viel länger dauern kann, wenn während Ihrer Zeitschleife ein Interrupt auftritt. Unterbrechungen sollten sowieso kurz sein, aber nicht jedes System folgt diesem Mantra.
Leon Heller
semaj
Benutzer1844
x4mer
x4mer
Kortuk
Toby Jaffey
Chris Stratton
Roh
Chris Stratton