Using a 16 bit counter.
PB0 goes low via a push button and the 16 bit counter starts counting up from 00 00 at 1ms intervals. (I don't know how to do the 16 bit count up but have the 1ms software timer coded).
The button is pressed again and the 16 bit value accumulated is stored in SRAM (I know how to store values in SRAM). If the two values reach FFh FFh then a red error LED comes on (PB1 low), indicating it took to long before the button was pressed a second time.
The two values saved are now loaded back into a counter and this 16 bit value is now counted down (don't know how to do this) at 1ms intervals until it reaches zero. When it reaches zero (time out) PB2 sends out a brief 1ms. pulse (I know how to make the 1ms. pulse).
How do I code a 16 bit counter that counts up and down at 1ms. intervals?
ATTiny85 assembly - timing a event at 1ms.
Setup one of the timers to fire it's interrupt every 1ms. In your code declare a timer variable that will hold your count. When the interrupt fires, increment the counter variable until the button is pressed. Use a similar process for counting down.
You want a state machine that acts every 1ms (either in the timer tick ISR or activated by a flag set in the ISR). You will have states such as
WAITING_FOR_START
GOT_START
WAITING_FOR_STOP
GOT_STOP
SENT_PULSE
and perhaps others. Note that GOT_START and WAITING_FOR_STOP may be the same state in your case.
When the 1ms code runs, depending on the current state it might count a software variable up or count it down. It might also change the state depending on the activity on PB0 & PB1, and on whether the count has reached 0xFFFF. And at some combination of state and software variable value, it will send the output pulse.
To count a 16-bit value up or down by 1 in asm, use the ADIW or SBIW instruction with an argument of 1.
The register pair for the 16 bit count is defined as R24, R26, R28, R30 in the instruction set summary when using ADIW and SBIW. How do I predefine the (selected) register pair in assembly?
You don't need to predefine it, you could just use
ADIW r25:r24,1
Thanks, I'm thinking a 65 second timeout is a long wait for this application but if I do use 0Xffff as my high value is there a over flow flag set when the counter rolls over to 0x0000 or do I have to do a compare on each register? Is there an easy way to do a 16 bit compare if I decide on a smaller value?
In a possibly syntax-challenged pseudocode:
cpi rlo, #LO_CONST bne no_match cpi rhi, #HI_CONST bne no_match have_a_match:
BTW, it's often useful to use a compiler to generate idiomatic asm code for a simple operation. Write the operation in the HLL, like
if (var == CONSTANT) { ..do something.. }
Compile that in a minimal program and look at the generated assembly language to get at least one guaranteed correct way to perform the operation.
Thanks, good suggestion.
Compile that in a minimal program and look at the generated assembly language to get at least one guaranteed correct way to perform the operation.
We used to do that to get Z80 maths routines. Some times you have to strip some compiler gumf (this was before optimizing was common or even available at all) but the technique works well.
______
Rob
Thanks, I'm thinking a 65 second timeout is a long wait for this application but if I do use 0Xffff as my high value is there a over flow flag set when the counter rolls over to 0x0000 or do I have to do a compare on each register? Is there an easy way to do a 16 bit compare if I decide on a smaller value?
This is where the AVR instruction set document if useful. Simply lookup the ADIW instruction and see how if affects the various flags. If you don't have this document, hopefully you can still case it down on the Atmel site. You definitely need it for ASM coding. Here's the section on the status bits changed with the ADIW instruction. AS you can see the carry flag will set on an overflow.
Attachment(s):
Got it. Set it for a 5 second timeout and it worked.