Das was ich da vor langer Zeit mal gecoded hatte funktioniert übrigens auch recht gut aufm AVR (ATMega-2560 @16MHz)
Test mit AVR-Simulator:
Aufruf: delayMilliSeconds(137);
Dauer: 138.950us = 138,95ms
macht knapp 2% Fehler
Ich vermute sehr stark, dass das einfach ein konstanter Faktor ist, den man mit einrechnen. Der Großteil wird wohl konstant innerhalb folgender Schleife verbraten:
Code:
for (currentCycle=0; currentCycle < totalCycles; currentCycle++){
_delay_ms(MAXIMUM_DELAY_MS);
}
Lässt sich vermutlich recht einfach rausrechnen (3-4 Werte ins EXCEL-Sheet...)
Wers selber probieren will...
"myUtil.h"
Code:
#include "myUtil.c"
void delayMilliSeconds(long totalMs);
"myUtil.c"
Code:
/**
* Converts an double value to an integer
*/
int doubleToInteger(double d);
/**
* AVRs cannot sleep more than the following per _delay_ms()-Call
* MAXIMUM_DELAY_MS = 262,2ms / F_CPU_in_MHz
*/
#ifdef F_CPU
#define MAXIMUM_DELAY_MS (262 / (F_CPU / 1000000))
#endif
void delayMilliSeconds(long totalMs){
long totalCycles; // Max-number of cycles
long rest; // Rest of the flolowing integer-division
// Calculate the total amount of cycles neccessary to reach the wanted delay
totalCycles = doubleToInteger(totalMs / MAXIMUM_DELAY_MS);
// Calculate the rest that has been lost due to integer-division
rest = totalMs - (totalCycles * MAXIMUM_DELAY_MS);
// Will hold the current Cycle
int currentCycle;
// Work out all full cycles
for (currentCycle=0; currentCycle < totalCycles; currentCycle++){
_delay_ms(MAXIMUM_DELAY_MS);
}
// Work out the rest if there is one
if(rest != 0){
_delay_ms(rest);
}
}
int doubleToInteger(double d){
return d;
}
Lesezeichen