I am making a program to accept three values (a_value, b_value and c_value), .
These values are in microseconds
when the timer reach a_value do something.
when the timer reach b_value do something.
when the timer reach c_value do something.
Then stop until the program receive other 3 values.
It seems like delayMicroseconds() is much easier for my application, but it is not very accurate.
I tried this sample code but the 50us pulse shifted left and right in the oscilloscope.
int outPin = 8; // digital pin 8
void setup(){
pinMode(outPin, OUTPUT); // sets the digital pin as output
}
void loop()
{
digitalWrite(outPin, HIGH); // sets the pin on
delayMicroseconds(50); // pauses for 50 microseconds
digitalWrite(outPin, LOW); // sets the pin off
delayMicroseconds(50); // pauses for 50 microseconds
}
I'm thinking to use timer, but will it be suitable for my application?
loop() is a function that is called from main and the call overhead affects your code.
using a while reduces this overhead to minimum
int outPin = 8; // digital pin 8
void setup()
{
pinMode(outPin, OUTPUT); // sets the digital pin as output
}
void loop()
{
while ( true )
{
digitalWrite(outPin, HIGH); // sets the pin on
delayMicroseconds(50); // pauses for 50 microseconds
digitalWrite(outPin, LOW); // sets the pin off
delayMicroseconds(50); // pauses for 50 microseconds
}
}
digitalWrite() takes a few microseconds to write the bit
Check out direct port manipulation to minimize this time.
The Arduino timer has limitation. I did try the timer in instructable and the pulse still shift left and right. No matter what is the frequency, the rising edge has error within 750ns. (Note: the code in instruable has already disable all interrupt)
As my application needs to accumulate number of counts, the error accumulates... Guess I have to shift to FPGA instead.
Why?
Revise your code so that all the counting is done without invoking the loop function.
Watch for a pin to go high, enable one of the timer/counter inputs to count pulses, which free-runs in hardware, until you disable counting. Your FPGA implementation would do a similar thing.
The wave looks much better when I put cli() at the setup. But for 180ms, there is still a 0.1ms error, I would if my delay subroutine issue.
int outPin = 5; // digital pin 8
void setup()
{
pinMode(outPin, OUTPUT); // sets the digital pin as output
cli();
}
void loop()
{
digitalWrite(outPin, HIGH); // sets the pin on
delayMicroseconds(50); // pauses for 50 microseconds
digitalWrite(outPin, LOW); // sets the pin off
delayMicroseconds(50); // pauses for 50 microseconds
}
This creates 180ms pulse, I got 180-180.2ms in my oscilloscope. How to calculate the timing of the clock cycle of my subrountine? Thanks
int outPin = 5;
long delay_tmp = 180000;
void setup()
{
pinMode(outPin, OUTPUT); // sets the digital pin as output
cli();
}
void loop()
{
digitalWrite(outPin, HIGH); // sets the pin on
delay_subroutine(delay_tmp);
digitalWrite(outPin, LOW); // sets the pin off
delay_subroutine(delay_tmp);
}
Please use code tags, it is the # button above the smileys
times are expressed in unsigned long
try this
const int outPin = 5; // const because it may not change
unsigned long delay_tmp = 180000; // might need to adjust this
unsigned long lastFlip = 0;
uint8_t state = HIGH;
void setup()
{
pinMode(outPin, OUTPUT); // sets the digital pin as output
cli();
lastFlip = micros();
}
void loop()
{
if (micros() - lastFlip >= delay_tmp) // subtraction handles the roll over of micros()
{
digitalWrite(outPin, state);
lastFlip = micros();
state = !state; // inverts the state
}
}
void loop()
{
if (micros() - lastFlip >= delay_tmp) // subtraction handles the roll over of micros()
{
PIND = PIND | 0b00100000; // invert Port D, bit 5 by writing to the bit - adjust for actual pin used
lastFlip = micros(); // capture the 'time'
}
}
Takes advantage of this:
"Three I/O memory address locations are allocated for each port, one each for the Data Register – PORTx, Data Direction Register – DDRx, and the Port Input Pins – PINx. The Port Input Pins I/O location is read only, while the Data Register and the Data Direction Register are read/write. However, writing a logic one to a bit in the PINx Register,
will result in a toggle in the corresponding bit in the Data Register."
AK51:
If the delay is big. I'm thinking to use delay() and delayMicroseconds() in sequence. Is there any additional delay if I do that? Thanks.
delay is not accurate to 1ms, let alone us.
delayMicroseconds() cannot be called with very large arguments (because the
type is 16 bit and it is buggy (well, coded for speed) and doesn't work for large
values anyway).
hardware timers are cycle-accurate, but this can only be shown when using them to directly
flip output pins - any interrupt handler is going to have a little jitter dependent on the
instruction being interrupted.
The best you can achieve is to write assembler loops that observe a timer value
I think. Using C will be a little less accurate perhaps:
TCNT1 = -delay ; // assume no interrupts and timer1 not clocked too fast:
while (TCNT1 != 0) // busy-wait
{}
This will be more accurate for 8-bit timers as reading TCNT0 or TCNT2 is
one instruction, reading TCNT1 is two instructions, since its a 16-bit pseudo-
register. With 8-bit timers you'll have to count overflows as well...
Thanks for the help.
micros() is a good choice.
The error is 180ms to 180.1ms (May be the oscilloscope reading issue)
I guess it is acceptable for Arduino.
Thanks and cheers.