circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

December 2004, Issue 173

H8/38024F-Based Programmable Timer


by Richard Wotiz


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.