December
2004, Issue 173
H8/38024F-Based
Programmable Timer
SOFTWARE
DETAILS
The
software was written in C language using HEW 2.0. Renesas
has since come out with HEW 3.0, which may have slight
differences from the menus I’ll describe. The code was
so straightforward that I built it using Release mode
and wrote debug information to the LCD rather than take
my chances trying to integrate the routines needed for
the debugger. The code is posted on the Circuit Cellar
ftp site.
The
code weighs in at just under 4 KB and uses 512 bytes
of RAM. I adjusted the linker’s segment map to put the
stack at the bottom and the variables at the top of
the RAM to take advantage of 8-bit absolute addressing
that’s available for locations 0xFF00 through FFFF.
This allows for faster access to key variables used
in the code that runs in Sub-Active mode, helping to
minimize execution time and power consumption. I did
this by first selecting “Hitachi H8S,H8/300 Standard
Toolchain” from the Options menu. Next, I went to the
C/C++ tab, selected “Category: Optimize,” and then selected
“@aa:8” in the Data Access box. This puts all char-sized
variables in a separate segment named $ABS8D (for initialized
data), $ABS8C (for constants), or $ABS8B (if not initialized).
Then, I had to let the linker know where to put the
data by going to the Link/Library tab, selecting “Category:
Section,” and then adding a section named $ABS8B at
the top of the map. Lastly, I had to modify the file
DBSCT.C (supplied by the HEW Project Generator) by uncommenting
the line containing $ABS8B, thus allowing the section
to be cleared to zero at start-up. I didn’t need to
worry about $ABS8C or $ABS8D because the program doesn’t
use any initialized char variables.
Figure
3 shows the main routine control flow. After initialization,
the main loop stops in Standby mode with the On button
interrupt enabled. When an interrupt occurs, it first
checks that it was from the On button. Then it initializes
some variables, turns on the LCD, and checks the battery
level. If it’s low, “Lb” is displayed briefly. It then
switches to Sub-Active mode and scans the buttons until
one is pressed or a 30-min. idle timer expires.
|

(Click
here to enlarge)
|
Figure
3—The main routine waits for you to press a button
when the timer is in Sub-Active mode. It switches
to Active mode before handling it. After you press
the Start/Stop button, the timer starts counting
down if a nonzero time was set; otherwise, it will
count up from zero. |
The
push button debounce routine takes approximately 10
ms to run. It needs to run once every 10 ms to debounce
the buttons reliably without any perceived delay, so
there isn’t any extra time to switch to Sub-Sleep mode.
After a button has been debounced, a routine is called
to execute the corresponding function. The buttons can
be used to select a particular stored time, set a desired
time, or start/stop the timer.
If
the Start/Stop button is pressed, the timer beeps once,
sets up TimerA to interrupt every 0.5 s, enables the
Start/Stop button interrupt, and switches to Sub-Sleep
mode. The colon blinks on the LCD each time an interrupt
comes along. Every other TimerA interrupt, the displayed
time is updated by 1 s. Because this routine executes
in Sub-Active mode, it needs to be as short and efficient
as possible. Listing 1 shows the time countdown code.
If
the Start/Stop button is pressed again, the timing loop
exits and returns to the main routine to wait for another
button press. When the time reaches zero (if counting
down) or 99:59 (if counting up), an “End” message appears
and the timer beeps twice before returning to the main
routine.
All
of the tasks are done one at a time in the main loop.
As a result, the interrupt routines only have to set
flags.