;-------------------------------------------------------------------------;
; EGGTIMER.ASM A 3 minute countdown timer for boiling eggs ;
;-------------------------------------------------------------------------;
LIST P=16F84 ; tells which processor is used
INCLUDE "p16f84.inc" ; defines various registers etc. Look it over.
ERRORLEVEL -224 ; supress annoying message because of tris
__CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF ; configuration switches
;-------------------------------------------------------------------------;
; Here we set up the user defined registers ;
;-------------------------------------------------------------------------;
CBLOCK H'0C' ; first free register address is 12
sec ; keeps track of seconds
sec10 ; keeps track of tens of seconds
mins ; keeps track of minutes
w_temp ; holds value of W during interrupt
status_temp ; holds value of STATUS during interrupt
finflag ; act as a flag to indicate end of countdown
oldsec10 ; holds last displayed value of sec10
ENDC
ORG 0 ; start a program memory location zero
goto main ; jump over the interrupt routine
ORG 4
;-------------------------------------------------------------------------;
; here is the interrupt routine, happens every second if GIE is enabled ;
;-------------------------------------------------------------------------;
movwf w_temp ; save W
swapf STATUS,W ; save status
movwf status_temp ; without changing flags
decf sec, f ; decrement seconds register
movlw H'FF' ; check if underflow
subwf sec, W ; will give zero if sec = H'FF'
btfss STATUS, Z ; skip next instruction if underflow
goto restore ; no underflow, leave interrupt routine
movlw 9 ; change seconds register to 9
movwf sec
decf sec10, f ; now we follow the same procedure ...
movlw H'FF' ; for the sec10 register
subwf sec10, W
btfss STATUS, Z ; skip if underflow
goto restore ; no underflow, leave
movlw 5 ; change sec10 register to 5
movwf sec10
decf mins, f ; and decrement minutes register
movlw H'FF' ; check if ...
subwf mins, W ; an underflow of minutes ...
btfss STATUS, Z ; yes means the count is finished
goto restore ; no underflow
incf finflag, f ; set the finished flag
restore:
swapf status_temp,W ; get original status back
movwf STATUS ; into status register
swapf w_temp,f ; old no flags trick again
swapf w_temp,W ; to restore W
bcf INTCON,T0IF ; clear the TMR0 interrupt flag
retfie ; finished reset GIE
;=========================================================================;
; This is the main program ;
;=========================================================================;
main:
;-------------------------------------------------------------------------;
; initialize the ports, set up interrupts etc: ;
;-------------------------------------------------------------------------;
movlw B'00000000' ; all bits low in W
tris PORTA ; contents of W copied to PORT A ...
movlw B'00010000' ; RB4 input, all other output
tris PORTB ; and PORT B
movlw B'00000100' ; port B pull-ups active
; prescalar assigned to TMR0 and set 1:32
option ; rolls over each second
movlw B'00100000' ; T0IE set, GIE not set yet...
movwf INTCON ; in the interrupt register
clrf PORTB ; display 0
;-------------------------------------------------------------------------;
; initialize some other registers: ;
;-------------------------------------------------------------------------;
clrf sec ; start with sec = zero
clrf sec10 ; and sec10 = zero
clrf oldsec10 ; make oldsec10 the same
movlw D'3' ; and minutes = 3
movwf mins
clrf finflag ; clear the finished flag
;-------------------------------------------------------------------------;
; wait for pushbutton to start ;
;-------------------------------------------------------------------------;
btfsc PORTB, 4 ; switch closed, (gives 0)?
goto $ -1 ; not yet
; switch has been detected closed
; ( no debounce necessary )
clrf TMR0 ; start with timer at zero
bcf INTCON, T0IF ; and make sure the interrupt flag is clear
bsf INTCON, GIE ; enable interrupts, countdown starts
;-------------------------------------------------------------------------;
; This is the main loop that displays the time and checks if finished ;
;-------------------------------------------------------------------------;
loop: ; now go into a loop displaying registers in..
; sequence each time sec10 changes, (every
; ten seconds), and checking for finished flag
btfsc finflag, 0 ; skip next if finflag not set
goto finished ; time up
movf oldsec10, W ; check if sec10 has changed
subwf sec10, W ; zero flag set if sec10 is same as oldsec
btfsc STATUS, Z ; skip over if not the same
goto loop ; else keep checking
movf sec10, W ; replace oldsec10
movwf oldsec10 ; making it equal to sec10
movf mins, W ; display minutes
movwf PORTB ; on LEDs
call onesecond ; for one second
clrf PORTB ; blank briefly
call msec250
movf sec10, W ; now the same with sec10
movwf PORTB ; show 10's of seconds
call onesecond ; for one second
clrf PORTB ; blank
goto loop
;-------------------------------------------------------------------------;
; We come to this point when the countdown is over ;
;-------------------------------------------------------------------------;
finished:
movlw H'F' ; turn on all leds indicating finish
movwf PORTB
goto $ ; go into an endless loop
;-------------------------------------------------------------------------;
; Four calls to a delay for 250 millisecond = 1 second delay ;
;-------------------------------------------------------------------------;
onesecond: ; a subroutine that delays for 1 seconds
call msec250
call msec250
call msec250
call msec250
return
;-------------------------------------------------------------------------;
; This subroutine delays for 250 milliseconds ;
;-------------------------------------------------------------------------;
msec250: ; a subroutine to delay 250 msec
movlw D'250' ; W is changed but no separate register needed
nmsec: ; could call it here with # msec in W
nop ; each nop is 0.122 milliseconds
nop
nop ; each total loop is 8 X 0.122 = 0.976 msec
nop
addlw H'FF' ; same as subtracting 1 from W
btfss STATUS, Z ; skip if result is zero
goto nmsec ; this is 2 X 0.122 msec
return ; back to calling point
end ; end of program
When you run the program the LEDs will be initially blank. When the pushbutton on RB4 is pressed the count will be given every 10 seconds, first by flashing minutes and then tens of seconds. The numbers are in BCD but you should be able to catch them. Seconds are not flashed because they are always zero. If tens of seconds is zero, it will not be seen either. Rather than counting down in binary and then converting to decimal, three registers mins, sec10 and sec are used to handle the numbers directly in decimal. All LEDs are turned on when the count is over.
Program # 2 used an interrupt flag, (T0IF), but didn't use interrupts. This program uses interrupts. When interrupt conditions are satisfied, everything stops, the program jumps to address 4 and execution continues from there. Instructions are executed until a 'retfie' instruction returns to where the interruption happened and carries on as before.
The interrupt routine shouldn't modify any registers or flags used in the main program. That is the reason for the complex set of instructions at the beginning and end of the isr, (interrupt subroutine). Both 'W' and STATUS are likely to be changed in the isr and must be saved. The original values will be restored before exiting the isr.
The count is initially 3 minutes, 0 seconds. Each second the isr decrements this by one second. Underflow is checked by seeing if the digit has gone to H'FF'. If this happens, the digit is reset to a starting value and the next digit to the left is decremented. When the underflow travels through all three digits, the finished flag is set.
We haven't seen the addlw instruction yet. It obviously adds a literal, (number), to W. But, in this case it is used to subtract 1 from W. You might be tempted to us 'sublw'. I have, and regretted it. 'sublw 3' does not subtract 3 from W, it subtracts W from 3! H'0FF' is the twos compliment value of '-1'. Adding twos compliment is the same as subtracting.The instruction occurs in the nmsec subroutine which introduces a way to provide a delay without using an extra register as we did before. This subroutine can also be entered at two points, msec250 to get a 1/4 second delay or at nmsec with the number of millisecs of delay put in W first.
'subwf (register), W' is a new instruction in the interrupt routine. Notice that W is subtracted from f, not the other way around. In this case we are only looking for a zero so it doesn't make a difference. But, in many cases it might be important. Also, if the destination is W, the register f is not altered.
BCF, ( clear a bit in the register f), provides a way to clear an individual bit in a register without changing other bits. There is also a BSF instruction to set individual bits.
If you run the program you find that the 4 LEDs don't come on when the count reaches 0 but 10 seconds later. Can you figure out what is wrong and fix it?
The obvious addition to the program is a speaker to indicate when time is up. I find the easiest way to do this is to put a piezoelectric speaker directly between a port and +4.5V. The ones having a paper cone attached seem louder. A piezo speaker is actually a capacitor so a 100 ohm resistor in series is a good idea to limit the original surge current.
The code to drive the speaker would simply bring the port high, hold it for a millisecond, bring it low, hold it for a millisecond and repeat over and over. See if you can add a speaker at the point where all the LEDs are turned on.
Can you figure a way to have all of the last digits 9-0 displayed?
A way to change the starting value might be interesting too. Say, if the battery were attached with the button not pressed the starting time would default to 3 minutes. If the button is pressed when power is supplied, the display starts flashing 1,2,3...etc until the button is released. The time at release would be the starting time in minutes. Could you write that program? Remember button debouncing because you would then have to wait for an additional press to start the countdown.
It is also inconvient to power-down and back up to restart the countdown. How about a press of the button at the end to turn off the LEDs. Yet another press would reload the starting count, (maybe display the minutes). Another press would begin the countdown. Can you make the changes?
See:
Questions:
Questions:
| file: /Techref/piclist/cheapic/eggtimer.htm, 16KB, , updated: 2013/8/14 08:29, local time: 2025/10/24 17:10,
216.73.216.188,10-3-157-36:LOG IN
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://www.ecomorder.com/techref/piclist/cheapic/eggtimer.htm"> Eggtimer Program </A> |
| Did you find what you needed? |
Welcome to ecomorder.com! |
|
The Backwoods Guide to Computer Lingo |
.