Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

12c508a - Power Timer

Status
Not open for further replies.
Well, here goes... I'm stumped. Apologies if I'm missing something really obvious.

Code:
;Based on original 'Tutorial 2.1' by Nigel Goodwin

LIST	p=16F628		;tell assembler what chip we are using
include "P16F628.inc"		;include the defaults for the chip
__config 0x3D18			;sets the configuration settings (oscillator type etc.)


LEDPORT	Equ	PORTA			;set constant LEDPORT = 'PORTA'
SWPORT	Equ	PORTA			;set constant SWPORT = 'PORTA'
LEDTRIS	Equ	TRISA			;set constant for TRIS register
SW1	Equ	7			;set constants for the switches
SW2	Equ	6
SW3	Equ	5
SW4	Equ	4
LED1	Equ	3			;and for the LED's
LED2	Equ	2
LED3	Equ	1
LED4	Equ	0

;// START - DEFs from the delay generator
cblock
d1
d2
d3
endc
;// END - DEFs from the delay generator

;end of defines
	
	org	0x0000			; org sets the origin, 0x0000 for the 16F628,
					; this is where the program starts running	
	movlw	0x07
	movwf	CMCON			; turn comparators off (make it like a 16F84)

   	bsf 	STATUS,		RP0	; select bank 1
   	movlw 	b'11110000'		; set PortA 4 inputs, 4 outputs
   	movwf 	LEDTRIS
	bcf	STATUS,		RP0	; select bank 0
	clrf	LEDPORT			; set all outputs low


MainLoop	
	btfss	SWPORT,	SW1		; Loop until reset / power on is triggered
	goto	PowerOnTimer		;If pushed, jump into the power on timer
	
	goto	MainLoop		; Loop back to the top of the main loop

ResetDelay
	;4999993 cycles
	movlw	0x2C
	movwf	d1
	movlw	0xE7
	movwf	d2
	movlw	0x0B
	movwf	d3
	retlw	0x00
	
PowerOnTimer
	goto	ResetDelay		; Reset the delay values back to 5 seconds
	clrf	LEDPORT			; turn all LED's off
	bsf	SWPORT,	LED1		; turn LED1 on
	goto	Delay_0			; Jump into the delay loop
	clrf	LEDPORT			; turn all LED's back off
	retlw	0x00
	
Delay_0
	btfss	SWPORT,	SW1		; Check for button push, and reset if necessary
	call	ResetDelay		; This line gets skipped over if the switch isn't pushed
	
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3, f
	goto	Delay_0

	;3 cycles
	goto	$+1
	nop

	;4 cycles (including call)
	return

	end
 
The first thing I spotted was the cblock instruction. It should have an address after it.

Try changing it to
cblock 0x20


Mike.
 
maybe I missed something but it looks like you are using GOTO to go to a piece of code and then a return instruction at the end. where you return to is anyones guess.

reset executes to mainloop which, when the switch is pressed jumps to PowertonTimer which jumps to resetdelay which then executes to a return instruction but there is no return frame on the stack. I bet it winds up executing at 0. there appear to be several other cases of this.
 
Made the change you suggested, it still doesn't do anything. However I made a few changes. I've added a status indicator and adjusted a few from goto's to call's to mirror what Nigel originally had (as I'm not sure if the btfss command needs calls following it).

Here's the updated code:

Code:
;Based on original 'Tutorial 2.1' by Nigel Goodwin

LIST	p=16F628		;tell assembler what chip we are using
include "P16F628.inc"		;include the defaults for the chip
__config 0x3D18			;sets the configuration settings (oscillator type etc.)


LEDPORT	Equ	PORTA			;set constant LEDPORT = 'PORTA'
SWPORT	Equ	PORTA			;set constant SWPORT = 'PORTA'
LEDTRIS	Equ	TRISA			;set constant for TRIS register
SW1	Equ	7			;set constants for the switches
SW2	Equ	6
SW3	Equ	5
SW4	Equ	4
LED1	Equ	3			;and for the LED's
LED2	Equ	2
LED3	Equ	1
LED4	Equ	0

;// START - DEFs from the delay generator
cblock 0x20				; Added 0x20 per Pommie on ETO
d1
d2
d3
endc
;// END - DEFs from the delay generator

;end of defines
	
	org	0x0000			; org sets the origin, 0x0000 for the 16F628,
					; this is where the program starts running	
	movlw	0x07
	movwf	CMCON			; turn comparators off (make it like a 16F84)

   	bsf 	STATUS,		RP0	; select bank 1
   	movlw 	b'11110000'		; set PortA 4 inputs, 4 outputs
   	movwf 	LEDTRIS
	bcf	STATUS,		RP0	; select bank 0
	clrf	LEDPORT			; set all outputs low


MainLoop
	bsf	SWPORT,	LED2		; turn LED2 on to indicate stand-by
	
	btfss	SWPORT,	SW1		; Loop until reset / power on is triggered
	call	PowerOnTimer		;If pushed, jump into the power on timer
	
	goto	MainLoop		; Loop back to the top of the main loop

ResetDelay
	;4999993 cycles
	movlw	0x2C
	movwf	d1
	movlw	0xE7
	movwf	d2
	movlw	0x0B
	movwf	d3
	retlw	0x00
	
PowerOnTimer
	call	ResetDelay		; Reset the delay values back to 5 seconds
	clrf	LEDPORT			; turn all LED's off
	bsf	SWPORT,	LED1		; turn LED1 on
	goto	Delay_0			; Jump into the delay loop
	clrf	LEDPORT			; turn all LED's back off
	retlw	0x00
	
Delay_0
	btfss	SWPORT,	SW1		; Check for button push, and reset if necessary
	call	ResetDelay		; This line gets skipped over if the switch isn't pushed
	
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3, f
	goto	Delay_0

	;3 cycles
	goto	$+1
	nop

	;4 cycles (including call)
	return

	end

However, I'm excited now because I'm getting SOMETHING that's working!!!

Here's the interesting thing that happens now. When the circuit first powers on, the standby indicator (A6) is lit up, which is good. Now, if I press the button to reset it, the power indicator comes on and the status light goes off, also good. But, after the 5 second delay, both lights stay on and the power to A0 never shuts off.

After the delay loop, I have a reset goto but it doesn't seem to be doing the ticket.

[edit] Whoops, sorry - I was posting a reply before I saw your post Phil...
 
WHOHOO - it works!!!

I changed the goto to a call for the delay reset, and it works!!!

Code:
;Based on original 'Tutorial 2.1' by Nigel Goodwin

LIST	p=16F628		;tell assembler what chip we are using
include "P16F628.inc"		;include the defaults for the chip
__config 0x3D18			;sets the configuration settings (oscillator type etc.)


LEDPORT	Equ	PORTA			;set constant LEDPORT = 'PORTA'
SWPORT	Equ	PORTA			;set constant SWPORT = 'PORTA'
LEDTRIS	Equ	TRISA			;set constant for TRIS register
SW1	Equ	7			;set constants for the switches
SW2	Equ	6
SW3	Equ	5
SW4	Equ	4
LED1	Equ	3			;and for the LED's
LED2	Equ	2
LED3	Equ	1
LED4	Equ	0

;// START - DEFs from the delay generator
cblock 0x20				; Added 0x20 per Pommie on ETO
d1
d2
d3
endc
;// END - DEFs from the delay generator

;end of defines
	
	org	0x0000			; org sets the origin, 0x0000 for the 16F628,
					; this is where the program starts running	
	movlw	0x07
	movwf	CMCON			; turn comparators off (make it like a 16F84)

   	bsf 	STATUS,		RP0	; select bank 1
   	movlw 	b'11110000'		; set PortA 4 inputs, 4 outputs
   	movwf 	LEDTRIS
	bcf	STATUS,		RP0	; select bank 0
	clrf	LEDPORT			; set all outputs low


MainLoop
	bsf	SWPORT,	LED2		; turn LED2 on to indicate stand-by
	
	btfss	SWPORT,	SW1		; Loop until reset / power on is triggered
	call	PowerOnTimer		;If pushed, jump into the power on timer
	
	goto	MainLoop		; Loop back to the top of the main loop

ResetDelay
	;4999993 cycles
	movlw	0x2C
	movwf	d1
	movlw	0xE7
	movwf	d2
	movlw	0x0B
	movwf	d3
	retlw	0x00
	
PowerOnTimer
	call	ResetDelay		; Reset the delay values back to 5 seconds
	clrf	LEDPORT			; turn all LED's off
	bsf	SWPORT,	LED1		; turn LED1 on
	call	Delay_0			; Jump into the delay loop
	clrf	LEDPORT			; turn all LED's back off
	retlw	0x00
	
Delay_0
	btfss	SWPORT,	SW1		; Check for button push, and reset if necessary
	call	ResetDelay		; This line gets skipped over if the switch isn't pushed
	
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3, f
	goto	Delay_0

	;3 cycles
	goto	$+1
	nop

	;4 cycles (including call)
	retlw	0x00

	end

Thanks Phil! You guys are awesome!!!
 
Last edited:
I spoke too soon, while everything functions perfectly, the timing is off - I'm assuming because of my two additional lines I added to check for the reset button press in the delay routine generated from .

Any suggestions on how I should adjust the timing? While it's not a big deal for 10 second routines, at 30 seconds I get about 10 extra seconds. I'd bet if I used the original routine for the hour it would be considerably more than an hour.

Thanks again!!
 
Are you using MPLAB?

If so, there is a stopwatch windows (I think View stopwatch). Open that windows, and set a break point on your call delay routing. Run to the breakpoint. Clear the stop watch, press F8 and see how long the delay is. Then adjust it to what you need.
 
It's basically because you're checking the button FAR too often, there's no point checking it ever couple of micro-seconds - every 100mS would be plenty.

I suggest you create a 100mS delay routine, then call that in a loop 50 times to get your 5 seconds - check the button in this outer loop, every 100mS.

Or some variation on this scheme.
 
I would do this whole thing differently. using a watch crystal (32K), I'd set up timer 0 with a 1:128 prescalar. that will give you an overflow (FF to 0) every second.

the main loop would watch the timer register. when it goes to 0, increment your elapsed time counter and compare to the preset value (2 hrs). You can also toggle an LED at that time or what ever you want to do. In the loop, check the switch, if it was pressed, clear the elapsed time counter. the advantage is you don't have to deal with counting instruction cycles (a pain when you keep making changes...).

pseudo code
Code:
setup timer, prescalar to 1:128
set timer to 1

loop 
   if timer is 0 then
        increment elapsed time counter
        wait for timer to reach 1
   endif
   if elapsed time counter is 2 hrs (or whatever) then
       do what needs to be done
   endif
   if switch is pressed then
      reset elapsed time counter
   endif
end loop
obviously, there are variations on this. If you use the internal 4 mhz oscillator you will have to change the size of your elapsed timer increment.
 
Last edited:
Phill,

Wow... um, I'm completely lost! Did I mention I was overjoyed that I even got it working in the first place!! If I hadn't already been through some of Nigel's tutorials - I would have been really REALLY lost.

I've got some more reading up to do as I'm not familiar with prescalar's or using an external clock.

Any suggestions on where some good reading material on them would be?

Thanks again everyone!!!
 
look at the datasheet. the timer is a register that you can write to. it starts counting at the same rate as single clock instructions are executed. it's only 8 bits so it when it gets to 255 (FF hex), it rolls over to 0 and keeps going.

the prescalar is a counter that delays the timer count by a certain number of clocks. a pre-scale of 1:2 means the timer counts every other clock tick. 1:128 means 128 clock ticks make for 1 timer tick. 128 * 256 = 32K (er, 32768, actually) ticks per second. this is the frequency of a watch crystal. so it will hit 0 once a second! you select this in the option register.

good luck
 
Well I'm trying to work on the more efficient embedded loop to get my feet wet and was curious what exactly these two lines do:

decfsz d1, f
goto $+2

I know decfsz is a decriment, but what does the "f" do? And with the goto, from what I was able to find, I think that the goto like that just makes the program eat 2 clock cycles?
 
decfsz stands for "decrement file skip if zero"

The ,F after the location tells the assembler where to put the result. F = put it back in the file. W = put it in the W reg.

The goto $+2 will jump past the next instruction.

So, in you original code, after d1 is decremented the code will execute as follows,
Code:
Delay_0
	decfsz	d1, f;		if after decrement d1 is not zero
	goto	$+2;		it will execute this instruction
	decfsz	d2, f;		and skip this one
	goto	$+2;		execute this one
	decfsz	d3, f;		skip this one
	goto	$+2;		execute
	decfsz	d4, f;		skip
	goto	Delay_0;	Finlay jump back to do it all again

It will do the above path 255 times until d1 is zero and then it will skip the first goto and decrement d2. It will keep on doing this until d1, d2 & d3 are all zero and then it will return.

I prefer to do a delay loop as follows,
Code:
Delay	decfsz	d1,F
	goto	Delay
	decfsz	d2,F
	goto	Delay
	decfsz	d3,F
	goto	delay
	return

I think it makes more sense and is much easier to read.

HTH

Mike.
 
The reason of using the goto$+2 construct is to make the looping with counts linearly proportional to the values of the count variables d1, d2....

For the second example, it is more difficult to work out the initial values of the count variables, given a certain timing delay.

Say how can one find out the values if one need 0.785s delay at 4MHz clock?
 
eblc1388 said:
The reason of using the goto$+2 construct is to make the looping with counts linearly proportional to the values of the count variables d1, d2....

For the second example, it is more difficult to work out the initial values of the count variables, given a certain timing delay.

Say how can one find out the values if one need 0.785s delay at 4MHz clock?

I didn't appreciate the linear nature of the above code. The second version is not as linear but the values can be worked out.

The following code will use 784999 clock cycles. (excluding the call and return)
Code:
Delay		movlw	.118
		movwf	d1
		movlw	.252
		movwf	d2
		movlw	.4
		movwf	d3
DelayLoop	decfsz	d1,F
		goto	DelayLoop
		decfsz	d2,F
		goto	DelayLoop
		decfsz	d3,F
		goto	DelayLoop
		return

The values are worked out from the following.

Delay = d1*3 + d2*770 + d3*197122 - 197883

So, for your example, you first find d3
(785000+197883)/197122 = 4 rem 194395
Then d2
194395/770 = 252 rem 355
Then d1
355/3 = 118 rem 1

It is a hell of a lot simpler in excel :rolleyes:

Mike.
 
The delay time is linear because each pass takes a constant number of clock cycles.

Therefore the delay for 0.785s is simply:

Delay(clock cycles) = mX + mC ;m= clock cycles per pass

where m is the proportional constant in this case is 7, X is the required value of count variable and C is a constant with negative value, in this case 0x10101.

Taking away the clock cycles needed to setup the variables, call and return, 0.785s comes to 784987 clock cycles. Thus:

784987 = 7 *( X - 0x10101)

which gives X = 0x2B70E

So d1=0x0E , d2=0xB7 and finally d3=0x02 if one use the "goto$+2" construct.

The negative constant C is the direct result of using decfsz which takes a jump when the value in d1, d2.. is one.

Edited: correct mistake formula
 
Last edited:
I still don't like the idea of using "goto $+2" in code that is meant for beginners as it requires a high level of knowledge to understand what it is doing. I think the "goto Label" way is far more readable and easier to understand.

Mike.
 
Pommie said:
I think the "goto Label" way is far more readable and easier to understand.

Mike.

Totally agree. The calculation with "goto$+2" is very easy to get wrong.
 
with an available timer, why deal with code cycle counting at all? seems so much easier to wait for a timer to reach a desired value.

Phil
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top