Countdown Timer

I wanted to add a countdown timer to a project I’m working on but I’m not sure how to accomplish this in my program. I’ve created simple countdown timers before but this was the only operation being performed by the microcontroller. This made it easy to specify a PAUSE command between variable indexing. The timer was by no means ultra-accurate but performed well enough. Here’s an example of the code I would normally use:

[code]DO

’ Calculate hours, minutes, seconds
IF seconds = 60 THEN seconds = 0: minutes = minutes + 1
IF minutes = 60 THEN minutes = 0: hours = hours + 1

’ Display digits on LCD display
SEROUT …

’ Pause for approx. 1 second and index second variable +1
PAUSE 991
seconds = seconds + 1

LOOP[/code]

Again this method works fine when the microcontroller is only performing this function but for my application I also need to perform several other subroutines within each main loop and the same subroutines are not performed each time depending on the state of other inputs.

How can I include a timer within my code that is still semi-accurate? I’ve been considering using a separate microcontroller especially because I hope to use 7-segment LEDs which require numerous I/O pins. Any suggestions?

Hi Dan,

I think from other posts you have made, that you have an Basic Atom Pro 28. So you might try using one of the three hardware timers (TimerA, TimerW, TimerV). TimerW is nice as it is a 16 bit timer, where as the other two are 8 bit timers, but if you use HSERVO then this subsystem uses it.

You will probably need to setup an interrupt handler to take care of when the timer overflows. There are several threads on this, including:
lynxmotion.net/viewtopic.php?t=3496

To understand the timer fully you will need to open it’s data sheet (H8/3694), which is downloaded as part of the IDE. You can easily get to it from the help menu.

Good Luck
Kurt

I assumed timers would be the answer to my dilemma and I’m glad to see they’re built in to the Basic Atom Pro 28 which I’m using. I’ve only recently graduated past the Parallax Basic Stamp and do not have much knowledge of timers, their function, and the proper syntax for their utilization. Does a useful tutorial exist somewhere that can help me become acquainted? Thanks.

Hi again dan,

Sorry, I don’t think there are any complete tutorials on using timers.

Did you look at all at the thread I passed a link to or the sections on the different timers on the H8 processor? There are other threads such as:
lynxmotion.net/viewtopic.php?t=2653&highlight=timer, which talk about it some.

But put in the simplist terms, the timers can be used as machine clock counters. That is, the processor will automatically increment a system register on every N clock cycle regardless of what else is going on. You can select the clock scalling by setting a system register. For the remainder of this post I will only talk about TimerA. Note: some of these timers have some other interesting capabilities that I will not discuss here.

To use TimerA, you will need to setup your scaling. This is done by setting certain bits in the TMA register. For our example, the valid values for TMA are:

0: φ/8192
1: φ/4096
2: φ/2048
3: φ/512
4: φ/256
5: φ/128
6: φ/32
7: φ/8

As the clock on the BAP28 runs at 16,000,000 cycles per second (more or less), if you choose lets say TMA=6, then the clock will increment every 32 cycles or about 2uS. The running system counter for TimerA is kept in the system register TCA. As TimerA is an 8 bit counter, TCA is only 8 bits in length and will overflow when it wants to hit the value of 256. For now I will assume you wish to time things that take more than 256 units (actually 512 as you could use the overflow indicator…, but…). To do this you will probably want to enable the interrupt on the TimerA overflow and provide an interrupt handler, which increments a counter of how many interrupts that have happened. An example of this is in the forum post that I put a link to in the previous message.

Here is some more sample code from one of my programs. Currently I only use this when debugging so I only made the counter to be 16 bits, but I could just as easily made it 32 bits.

wTimerCnt		var	word		; 
wTimerCnt = 0
...

; Initialize the timer stuff
TMA = 6	                                           ; clock / 16
ONASMINTERRUPT TIMERAINT, HANDLE_TIMERA_ASM ; set interrupt handler
ENABLE TIMERAINT                                ; enable the timer interrupt
ENABLE                                                 ; globabl enable interrupts
...

;--------------------------------------------------------------------
;[Handle_Timer_asm] - Handle timer A overlfow in assembly language.  Currently only
;used for timings for debuging the speed of the code, may be pulled later or may be
;used for timing delays.

   BEGINASMSUB 
HANDLE_TIMERA_ASM 
	push.w 	r1                  ; first save away ER1 as we will mess with it. 
	bclr 	#6,@IRR1:8               ; clear the cooresponding bit in the interrupt pending mask 
	mov.w 	@WTIMERCNT:16,r1      ; Add 256 to our counter 
	inc.b 	r1h 
	mov.w 	r1, @WTIMERCNT:16 
	pop.w 	r1 
	rte 
	ENDASMSUB 

;--------------------------------------------------------------------
;[getTimerVal] - Gets the Timer value from our overflow counter as well as the TCA counter.  It
;                makes sure of consistancy. That is it is very posible that 
;                after we grabed the timers value it overflows, before we grab the other part
;                so we check to make sure it is correct and if necesary regrab things.

bTimerTmp	var	byte
GetTimerVal:	
	bTimerTmp = WtimerCnt.highbyte
	wTimerCnt.lowbyte = TCA
	if wTimerCnt.highbyte <> bTimerTmp then GetTimerVal	; make sure consistent value
	return

In this example I did use an assembly language interrupt handler for speed, but could have made it a basic hander, which would have been something like:

ONINTERRUPT TIMERAINT, HANDLE_TIMERA
...
HANDLE_TIMERA:
    wTimerCnt = wTimerCnt + 256
    resume

Again Could have easily extended to 32 bits.
I also had a helper function to try to get a consitent value. That is there are chances that when you are grabing the current timer value, that at that instant the timer wrapped around and an interrupt happened and your value will not be correct…

I hope this helps.
Kurt