cooperative m*ultitasking + Precise timing

MMcLaren

Joined Feb 14, 2010
861
I have a feeling you make this way to complicated.
If you think about it, it's a relatively complicated task but it could be a good experience building exercise that may help him design smaller, simpler, faster, and more efficient code in the future.

As I understand your project is to make clock. The most important thing here will be keeping the time. All that has to do with that, you put in the ISR. Less important things like updating the displays scanning the switches you put outside the ISR.
I suspect no two programmers would agree on design. Refreshing multiplexed LED displays and sampling/debouncing switches at precise intervals is easily handled in the ISR.

Some tips! When you are in the process of setting the time, turn off the ISR as it is not needed at that moment.
This really depends on the design. If you're refreshing a multiplexed LED display in the ISR then obviously you don't want to turn off interrupts.

The moral, if any, is there are hundreds of ways to accomplish the same task.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
If you think about it, it's a relatively complicated task but it could be a good experience building exercise that may help him design smaller, simpler, faster, and more efficient code in the future.
Yes, I agree! it a really good exercise and I have a strong feeling that I can achieve this BUT my only problem is the time!! 24 hours left!:(

I also believe and realised this lately that if you are *very good* with Maths, you can (or have the potentials) to be a very good programmer! anyone agree!?:)

I suspect no two programmers would agree on design. Refreshing multiplexed LED displays and sampling/debouncing switches at precise intervals is easily handled in the ISR.
Yes lots of arguments had happened on *better design* on this forum ;) and I like that!!

This really depends on the design. If you're refreshing a multiplexed LED display in the ISR then obviously you don't want to turn off interrupts.
Ok!

The moral, if any, is there are hundreds of ways to accomplish the same task.
Agree totally!

And some for some unknown reasons *maybe jalousy* do Not appreciate at all the way other people do their thangs! Like my instructor never appreciate the way i do thangs and always say that I have a complicated mind! And of course He got more experience than I do BUT for a skinny experience I have *lol* I sometimes *totally* disagree with a few thangs He says but as he's the instructor i can't do much!

thanks Mike!
 

BMorse

Joined Sep 26, 2009
2,675
Attached is my routine for setting the minutes by a single press of a button that increment a register...

actually it counts from 00 to 59 when button is pressesd! hope it makes sense...

But my problem is coming up with a good algorithm that counts from 00 to 23 on button press..

index1t ; array index 0 - 9 for the ones of minutes (current time)
index2t ; array index 0 - 9 for the tens of minutes (current time)
index3t ; array index 0 - 9 for the ones of hours (current time)
index4t ; array index 0 - 9 for the tens of hours (current time)

minutesl_t ; time ones minutes segment data register
minutesh_t ; time tens minutes segment data register
hoursl_t ; time ones hours segment data register
hoursh_t ; time tens hours segment data register

h refers to higher
l refers to lower
t refers to time

thanks

seems like there is a lot going on for just incrementing minutes.....


Here is an example of a time set routine I have written in assembly, but used for a propeller clock.... I just used the regular "time" variables to hold the count value then used a lookup table to display them on the LED's 1 column at a time (5 columns of 8 bits make 1 char/digit)

This is the interrupt routine that updates the time:
Rich (BB code):
;****interrupt subroutine for timekeeping of hrs mins secs**************
irq	clrwdt			;clear the watchdog timer
	btfss	control,1	;check time-set sensor, skip if high
	bsf	setbit,0	;yes, index = low so set setbit: go into time set mode
	incf	count3,1	;no index = high; count3 = count3 + 1 
	movlw	h'32'		;check if count3 > 100 !!!!temporarily 02, must be 64h!!!!
	subwf	count3,0
	btfsc	status,0
	goto	divup		;yes, > 100 so do count4 = count4 + 1
	goto	irqend		;no,<= 100 leave interrupt routine
divup	incf	count4,1	;count4 = count4 + 1
	clrf	count3		;reset count3 to 0
	movlw	h'64'		;check if count4 > 100 !!!!temporarily 02, must be 64h!!!!
	subwf	count4,0	;
	btfsc	status,0	;
	goto	secsup		;yes, > 100 so do secs = secs + 1
	goto	irqend		;no, <= 100 so leave interrupt routine
secsup	incf	secs,1		;seconds = seconds + 1
	clrf	count4		;reset count4 to 0	
	movlw	h'0A'		;check if secs > 9
	subwf	secs,0
	btfsc	status,0
	goto	tensup		;yes, > 9 so do tenssecs = tenssecs + 1
	goto	irqend		;no,<= 9 so ;leave interrupt routine
tensup	incf	tensecs,1	;tensecs = tensecs + 1
	clrf	secs		;reset seconds to 0
	movlw	h'06'		;check if tensecs > 6
	subwf	tensecs,0	;
	btfsc	status,0	;
	goto	minsup		;yes, > 6 so do mins = mins + 1
	goto	irqend		;no, <= 6 so leave interrupt routine
minsup	incf	mins,1		;minutes = minutes + 1
	clrf	tensecs		;reset tensecs to 0	
	movlw	h'0A'		;check if mins > 9
	subwf	mins,0
	btfsc	status,0
	goto	tenmup		;yes, > 9 so do tens = tens + 1
	goto	irqend		;no,<= 9 so ;leave interrupt routine
tenmup	incf	tenmins,1	;tenmins = tenmins + 1
	clrf	mins		;reset minutes to 0
	movlw	h'06'		;check if tenmins > 6
	subwf	tenmins,0	;
	btfsc	status,0	;
	goto	hrsup		;yes, > 6 so do hrs = hrs + 1
	goto	irqend		;no, <= 6 so leave interrupt routine
hrsup	incf	hrs,1		;hrs = hrs + 1
	clrf	tenmins		;reset tenmins to 0
	movlw	h'0A'		;check if hrs > 10
	subwf	hrs,0
	btfsc	status,0
	goto	tenhup		;yes, > 10 so increment tenhrs
	movlw	h'02'		;no,  <= 10 now check check if tenhrs > 2
	subwf	tenhrs,0	;(check if 24h is reached)
	btfss	status,0	;
	goto	irqend		;no,  tenhrs < 2 leave interrupt routine
	movlw	h'04'		;yes, tenhrs > 2, now check if hrs > 4
	subwf	hrs,0		;(check if 24h is reached)
	btfss	status,0	;
	goto	irqend		;no hrs < 4, leave interrupt routine
	clrf	hrs		;yes hrs > 4, so clear hrs and tenhrs
	clrf	tenhrs
	goto	irqend		;leave interrupt routine
tenhup	incf	tenhrs,1	;tenhrs = tenhrs + 1
	clrf	hrs		;reset hrs to 0
	goto	irqend		;leave interrupt routine
irqend	movf	statbu,0	;(statbu-->w)
	movf	status,1	;restore status register after interrupt
	movf	wbu,0		;restore w after interrupt
	bcf	intcon,2	;clear interrupt flag for more interrupts
	retfie			;return from interrupt
	goto	start		;or return to start (from timeset)

This is the part of the code for setting the time:
Rich (BB code):
;************timeset routine**********************
timeset clrf	secs		;clear secs
	clrf	tensecs		;clear tensecs
	clrf	setbit		;reset setbit for next time
minsup2	incf	mins,1		;minutes = minutes + 1
	clrf	tensecs		;reset tensecs to 0	
	movlw	h'0A'		;check if mins > 9
	subwf	mins,0
	btfsc	status,0
	goto	tenmup2		;yes, > 9 so do tens = tens + 1
	goto	skipset		;no,<= 9 so ;leave timeset routine
tenmup2	incf	tenmins,1	;tenmins = tenmins + 1
	clrf	mins		;reset minutes to 0
	movlw	h'06'		;check if tenmins > 6
	subwf	tenmins,0	;
	btfsc	status,0	;
	goto	hrsup2		;yes, > 6 so do hrs = hrs + 1
	goto	skipset		;no, <= 6 so leave timeset routine
hrsup2	incf	hrs,1		;hrs = hrs + 1
	clrf	tenmins		;reset tenmins to 0
	movlw	h'0A'		;check if hrs > 10
	subwf	hrs,0
	btfsc	status,0
	goto	tenhup2		;yes, > 10 so increment tenhrs
	movlw	h'02'		;no,  <= 10 now check check if tenhrs > 2
	subwf	tenhrs,0	;(check if 24h is reached)
	btfss	status,0	;
	goto	skipset		;no,  tenhrs < 2 leave timeset routine
	movlw	h'04'		;yes, tenhrs > 2, now check if hrs > 4
	subwf	hrs,0		;(check if 24h is reached)
	btfss	status,0	;
	goto	skipset		;no hrs < 4, leave timeset routine
	clrf	hrs		;yes hrs > 4, so clear hrs and tenhrs
	clrf	tenhrs
	goto	skipset		;leave timeset routine
tenhup2	incf	tenhrs,1	;tenhrs = tenhrs + 1
	clrf	hrs		;reset hrs to 0
	goto	skipset		;leave timeset routine
This the part where it displays the clock digits on the LED's (remember that this is a Propeller clock and has to display each digits on 5 columns....)

Rich (BB code):
;****display subroutine*************************
display	clrf	colcnt		;reset the column counter
	movwf	tablect		;put the number value in tablect
	addwf	tablect,1	;now add 4 x 
	addwf	tablect,1	;a very crude way to
	addwf	tablect,1	;multiply by 5 :-)
	addwf	tablect,1	;
flash	movf	tablect,0	;now put the mutilplied value in W
	call	table		;and look up the 5 columns to display this number
	movwf	leds		;flash the column with the LEDS
	call	delay		;let them burn for 1 millisecond
	incf	tablect,1	;set pointer to the next column
	incf	colcnt,1	;
	movlw	h'05'		;check if 
	subwf	colcnt,0	;5 columns
	btfss	status,0	;are flashed
	goto	flash		;no, so flash next column
	clrf	leds		;switch off all leds
	call	delay		;add a space between the nubers
	return			;yes, return from display subroutine
;****delay = wait count1 x count2 cycles******************************
delay	movlw	h'4F'		;count1 value
	movwf	count1		;count1 is slow counter	
loop1	decfsz	count1,1	;
	goto	label		;still > 0
	return			;count1 < 0 so get out of the delay loop
label	movlw	h'05'		;count2 value
	movwf	count2		;count2 is fast counter inside count1 loop
loop2	decfsz	count2,1	;
	goto	loop2		;still > 0 so stay in loop2
	goto	loop1		;count1 < 0 go to loop1

And this the look up table routine to convert the time values to the columns data:

Rich (BB code):
;****lookup table for numbers 5 columns = 1 number*******************
table	addwf	2,1			;jump to PC '2' + w
	retlw	b'11000001'		;zero
	retlw	b'10111110'		;turn this page 91 degrees
	retlw	b'10111110'		;and you will see the patterns
	retlw	b'10111110'		;FOR SIMULATION HEX NUMBERS ARE USED!!!!!!!!!!!!!!
	retlw	b'11000001'		;ADD PATTERNS LATER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

	retlw	b'10000000'		;one
	retlw	b'11011111'
	retlw	b'11111111'
	retlw	b'11111111'
	retlw	b'11111111'

	retlw	b'11001110'		;two
	retlw	b'10110110'
	retlw	b'10111010'
	retlw	b'10111100'
	retlw	b'11011110'

	retlw	b'11001001'		;three
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'10111110'
	retlw	b'11011101'

	retlw	b'11111011'		;four
	retlw	b'10000000'
	retlw	b'11011011'
	retlw	b'11101011'
	retlw	b'11110011'

	retlw	b'10111001'		;five
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'10000101'

	retlw	b'11011001'		;six
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'11000001'

	retlw	b'10011111'		;seven
	retlw	b'10100111'
	retlw	b'10111000'
	retlw	b'10111111'
	retlw	b'10111111'

	retlw	b'11001001'		;eight
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'11001001'

	retlw	b'11000001'		;nine
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'10110110'
	retlw	b'11001111'

	retlw	b'11111111'		;double dot
	retlw	b'11111111'
	retlw	b'11001001'
	retlw	b'11111111'
	retlw	b'11111111'
	end;
 

BMorse

Joined Sep 26, 2009
2,675
and finally the main code loop: (wouldn't all fit in my first post was too long!)

Rich (BB code):
main	bsf	status,5	;switch to bank 1 to set up ports
	movlw	h'00'		; 
	movwf	trisb		;portB is all output
	movlw	h'FF'
	movwf	trisa		;portA is all input
	bcf	optreg,5	;Clear T0CS = option reg bit 5 to enable timer0
	bcf	optreg,3	;clear PSA assign prescaler to timer0 (instead of WDT)
	bcf	optreg,2	;prescaler set to
	bcf	optreg,1	; 000 = 1:2
	bcf	optreg,0	; 111 = 1:256
	bcf	status,5	;switch back to bank0 
	bsf	intcon,7	;GIE=Global Interrupt Enable (1=enable)
	bsf	intcon,5	;T0IE = timer0 interrupt enable (1=enable)
	bcf	intcon,2	;Clear Interrupt Flag Bit just in case 
	clrf	mins
	clrf	tenmins
	clrf	hrs
	clrf	tenhrs
	clrf	secs
	clrf	tensecs
;****main program*****************************
start	clrf	leds		;switch off all leds
	btfsc	control,0	;first check index sensor
	goto	start		;no, index = high so keep waiting
	btfss	setbit,0	;yes index=low, first check if you are in time set	
	goto	skipset		;no, setbit=low, not in time set, so skip time setting
	goto	timeset		;yes setbit = hi so goto timeset routine
skipset	call	delay		;wait few ms to pass the sensor
	movf	secs,0
	call	display
	movf	tensecs,0
	call	display
	movlw	h'0A'
	call	display		;write a double dot
	movf	mins,0
	call	display
	movf	tenmins,0
	call	display
	movlw	h'0A'
	call	display		;write a double dot
	movf	hrs,0
	call	display
	movf	tenhrs,0
	call	display
	goto	start

;****display subroutine*************************
display	clrf	colcnt		;reset the column counter
	movwf	tablect		;put the number value in tablect
	addwf	tablect,1	;now add 4 x 
	addwf	tablect,1	;a very crude way to
	addwf	tablect,1	;multiply by 5 :-)
	addwf	tablect,1	;
flash	movf	tablect,0	;now put the mutilplied value in W
	call	table		;and look up the 5 columns to display this number
	movwf	leds		;flash the column with the LEDS
	call	delay		;let them burn for 1 millisecond
	incf	tablect,1	;set pointer to the next column
	incf	colcnt,1	;
	movlw	h'05'		;check if 
	subwf	colcnt,0	;5 columns
	btfss	status,0	;are flashed
	goto	flash		;no, so flash next column
	clrf	leds		;switch off all leds
	call	delay		;add a space between the nubers
	return			;yes, return from display subroutine
;****delay = wait count1 x count2 cycles******************************
delay	movlw	h'4F'		;count1 value
	movwf	count1		;count1 is slow counter	
loop1	decfsz	count1,1	;
	goto	label		;still > 0
	return			;count1 < 0 so get out of the delay loop
label	movlw	h'05'		;count2 value
	movwf	count2		;count2 is fast counter inside count1 loop
loop2	decfsz	count2,1	;
	goto	loop2		;still > 0 so stay in loop2
	goto	loop1		;count1 < 0 go to loop1
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
thanks so much Bmorse...but decoding your code now looks a bit impossile...10 hours left (i am just a dead man)...actually this project doesn't scare me but time is just not on my side and my brain is freezing..

But I must say that its neat, clean, ...I can feel yur skill in the code!:)
 

BMorse

Joined Sep 26, 2009
2,675
thanks so much Bmorse...but decoding your code now looks a bit impossile...10 hours left (i am just a dead man)...actually this project doesn't scare me but time is just not on my side and my brain is freezing..

But I must say that its neat, clean, ...I can feel yur skill in the code!:)
That is why I tried to break it down into segments for you, and I was hoping that there is enough comments for you to be able to follow it..... Just skip the whole Interrupt routine and check out the time set routine to give you some idea on how to implement a routine (algorithm) to count from 00 to 23 ....
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
seems like there is a lot going on for just incrementing minutes.....
Actualy this routine just increment fron 00 to 59 on pres button...I have not including the real processing of the timeofday yet...just no time! but I'll finish it up just for the fun of it...

will see what I can do for now...miracle happens so...;)
 

takao21203

Joined Apr 28, 2012
3,702
I have taken a look your source code.

Why don't you just write interrupt handler that gives you 50 msec. timebase?

Then in the main function, you simply increment counters.

One for display refresh, one for key testing, and one to update the clock.

They are incremented each cycle, as well tested.
When they have reached the preset value, you execute the sub-functions.

For the key handler, I made suggestions already. Here the assembler code:

Rich (BB code):
l_keytst:
 movf INDF,w
 addwf PCL,f
 
 goto l_key_ph0
 goto l_key_ph1
 goto l_key_ph2
 
l_key_ph0:
 btfsc v_status,c_status_portbit
 retlw 0x00
 incf INDF,f
 retlw 0x00

l_key_ph1:
 btfss v_status,c_status_portbit
 retlw 0x00
 incf INDF,f
 retlw 0x00
 
l_key_ph2:
 retlw 0x00
 
 org 0x0100
note you must take care program memory pages when you use computed GOTO.

Rich (BB code):
u_testkeys:
 movlw v_key1
 movwf FSR
 bcf v_status,c_status_portbit
 btfsc PORTA,c_PA_key1
 bsf v_status,c_status_portbit
 call l_keytst
 
 movlw v_key2
 movwf FSR
 bcf v_status,c_status_portbit
 btfsc PORTA,c_PA_key2
 bsf v_status,c_status_portbit
 call l_keytst
 
 movlw v_key3
 movwf FSR
 bcf v_status,c_status_portbit
 btfsc PORTB,c_PB_key3
 bsf v_status,c_status_portbit
 call l_keytst
  
 movlw d'2'
 subwf v_key1,w
 btfsc STATUS,Z
 goto l_key1pressed
 
 movlw d'2'
 subwf v_key2,w
 btfsc STATUS,Z
 goto l_key2pressed
 
 movlw d'2'
 subwf v_key3,w
 btfsc STATUS,Z
 goto l_key3pressed
 
 goto l_main0
And here code to evalute the keys. GOTOs are used here since it is written for a PIC with only 2 stacks.

It is a larger number of lines than your code, but easier to understand.
 

Markd77

Joined Sep 7, 2009
2,806
Just thought I'd summarise BMorse's code in a couple of lines:
Increase the units of hours, if it is 10 increase tens of hours and clear units.
If tens of hours is 2 and units of hours is 4 then reset both to zero.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Thanks y'all for your great help..I'll comment them in a moment!

In the meanwhile, I would like if any of you has a *schematics* of PIC16F690 (or any other 16F series) interfaced with:

- 4 Seven Segment Display (on PortC or PortX)
- 4 push buttons (on PortA or PortX)
- 4 transistor for the multiplexing
- 2 Leds

[edited] and 1 buzzer

The above *schematics* is for what we been discussing...

@BMorse: I sureyou have on, right?

Then I'll tell you my story of today with this project! what a day!
 
Last edited:

MMcLaren

Joined Feb 14, 2010
861
Not exactly what you asked for, but... I have a four digit board that uses a 16F1828 which is similar to the 20 pin 16F690... In fact you could use a 16F690 on the board.





Some differences worth noting... (A) this is a 99 minute Timer demo with a C program but it could be easily converted into a Clock demo with assembly language program, (B) the schematic shows an optional crystal but I used the INTOSC in the project, (C) the schematic shows discrete 'A' and 'B' LEDs which were not used in the project, (D) the displays were incredibly bright so I decided to omit the digit driver transistors and I refresh the display one segment at a time for a 1/32nd duty cycle, and, (E) I use one pin to read the four switches which are driven by the four column/digit driver lines (a column driven switch matrix).

Please tell us what happened?
 
Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
it almost what I am looking for...it still PIC16F series so it ok...but there are no transistor (npn or pnp) + this does not look like a schematics (can et me in trouble if I use it as it going to look like I copied it from somewhere)....I need more like an *eagle* or *multism* or... schematics but if not possible...it ok

Story coming soon:)...typing a report on it...
 

MMcLaren

Joined Feb 14, 2010
861
Eric,

A question about one of your design choices, please? Why did you spread your digit enable signals across two ports (RB4, RB5, RB6, and RC7)?
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Eric,

A question about one of your design choices, please? Why did you spread your digit enable signals across two ports (RB4, RB5, RB6, and RC7)?
Heu...I can't really remember why I did this...but RB4, RB5 and RB6 are on one side of the MCU and RB7 is alone on the other side...

Oh yeah I think I remember it because I used an old project on breabord and edit a lil the harware for this project....AND the old project had a *push button* on RB7(and didnot want to touch that button already in place)...so what I did was I added 3 more buttons on other I/O pins and put the *enable signal* on RC7...

but you are right this is not a good way of doing things...I was in a panic mode...was thinking straight nomore...

But this is nomore a school project to me!!! I will come back to it on my free time and will finish it up and will post a working project (code)!!!

This is not bad...the time just killed me...

I will fix that ...will put all the 4 enable on the same portB!!

Thanks Mike!
 
Top