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.

Pic debounce routine

Status
Not open for further replies.
1 - pay more attention and you won't have attention deficit.
2. Use lower case - it is more professional
3. Just do the scan routine I suggested. You will then add things to it later.
4. My delay has 2 less instructions and assumes the register will enter the delay with 00 - which it WILL so why load it?
It's just another clever thing to remember.
5. Put tables in the first 256 bytes of memory where you put all your coding..
Put tables like this:
orig 000
setUp

goto Main

Then put tables:


table1 addwf PCL,F ;02h,1 add W to program counter
retlw .10 ;etc
retlw .50 ;etc

table2 addwf PCL,F ;02h,1 add W to program counter
retlw .10 ;etc
retlw .50 ;etc



then goto table1 so that the value in table1 will return you to the sub-routine: Main


You can also add the LEDs and illuminate them.

To do this you will need a file called LEDs_1

The values in this file will be output during the 4th part of the scan.
Clear the file and make sure the LEDs are off - it depends on the way the LEDs are illuminated.
Then load the file with a value and see if the correct LEDs illuminate.
You will be flashing the LEDs later.

Then name a file keys_on and another keys_off
These will be the flag files to detect when a key is pressed for the first time and when the scan routine has performed another scan and the key is not pressed. This is called debouncing.
You are gradually working up a full scan routine by adding theses items one-at-a-time and getting it to work.
Before . . . . . you created everything at once and it did not work. That's the wrong way to go about it. You must do one thing at a time and get it to work. But you must also know how to create a framework or scan routine that can be added to. Once you understand the concept of a scan routine, you can add things during the time when the displays are illuminated and this will not detract from the brightness of the display.
In your program above you should turn off one display just before turning on the next. You have some few microseconds of program between one and the other and this does not matter at this stage, but when you are desperate for illumination, all the timing matters.





 
Last edited:
4. Put the tables in the first page Page0 and go to them. This will simplify the code to:

movf units,w
goto tableA

.

Just one observation:

I changed the code for the tables to:

Code:
	ORG		0x0000

	GOTO	START

	ORG 0x0004
	GOTO	TIMER1_ISR   ; just case we need it in future...

DECOD_DISPLAY_A:
	ADDWF   PCL,F			; compute the jump value

						;	|7|6|5|4|3|2|1|0| -	Bits PORTA
						;	|-|-|B|E|-|A|-|-|
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	0
	RETLW	B'00010100'	;	|-|-|B|X|-|X|-|-| -	1
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	2
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	3
	RETLW	B'00010100'	;	|-|-|B|X|-|X|-|-| -	4
	RETLW	B'00110000'	;	|-|-|X|X|-|A|-|-| -	5
	RETLW	B'00100000'	;	|-|-|X|E|-|A|-|-| -	6
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	7
	RETLW	B'00000000'	;	|-|-|B|E|-|A|-|-| -	8
	RETLW	B'00010000'	;	|-|-|B|X|-|A|-|-| -	9

DECOD_DISPLAY_B:
	ADDWF   PCL,F			; compute the jump value

						;	|7|6|5|4|3|2|1|0| -	Bits PORTB
						;	|C|F|D|G|-|-|-|-| -
	RETLW	B'00010000'	;	|C|F|D|X|-|-|-|-| -	0
	RETLW	B'01110000'	;	|C|X|X|X|-|-|-|-| -	1
	RETLW	B'11000000'	;	|X|X|D|G|-|-|-|-| -	2
	RETLW	B'01000000'	;	|C|X|D|G|-|-|-|-| -	3
	RETLW	B'00100000'	;	|C|F|X|G|-|-|-|-| -	4
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	5
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	6
	RETLW	B'01110000'	;	|C|X|X|X|-|-|-|-| -	7
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	8
	RETLW	B'00000000'	;	|C|F|D|G|-|-|-|-| -	9

And, in main loop code:

Code:
DISPSHOW:
	BSF		LED_CMN			; Leds off

	MOVF	UNITS,W			; copy units to W
	CALL	DECOD_DISPLAY_A	; convert
	MOVWF	PORTA			; put it in PORTA
	MOVF	UNITS,W			; copy units to W
	CALL	DECOD_DISPLAY_B	; convert
	MOVWF	PORTB			; put it in PORTA
	BCF		DISP1			; display 1 on
	MOVLW	D'2'			;
	CALL	DELAY_MS		; delay 2 ms
	BSF		DISP1			; display 1 off

and so on, for the 3 displays.

I have to use call and not goto, because goto didn't work.
I wil see this tomorrow, because it's 3:23 AM here and I'm going to sleep.
I will also study the way you indicate to make the switches debounce.

Once more thanks.

Sergio
 
Last edited:
ssaquiar,

Did I understand you to say that you're working on an existing design which cannot be changed?
 
Last edited:
Dear Mike:

Yes, unfortunately, the design can't be changed.
If I change the processor or made any changes which implies in an increase of the price of the circuit, the firm will not accept (even an increase in US$ 1.00).
This processor costs US$ 1.6 at Digikey, for example.
The processor that I could use to implement a new design, costs US$ 2.5 (0.9 US$ more). They didn't accept it.

Sergio
 
Dear friends:

I have followed our dear friend colin55 advices and hings are now better than before.
Now, I have the leds and displays ok.
I also continue to use Timer1 interrupt to make led on/off blink because it's working and I am pretty sure I am going to need it when the oven will be cooking, to count the time (from 1 to 240 minutes).
In this application, when we push any key, it will sound a beep.
For the keys Up and Down, the beep will heard only the first time we press the button. If you keep the button pressed, activating the auto increment, the beep will not be fired.
I just tested the code for the keys without any debounce and playing a beep when the key Up is pressed, just to test it.
The problem is that, when this key is pressed and we generate one beep, all the displays and leds timing are messed up.
You can see the picture from the osciloscope attached below.
As you can see, I am beeping just for 35 ms (+-), but the displays and leds blinks (and I am thinking that the beep should be playing for, at least, 250 ms to be heard fine, isn't?
Do I need to make this work using Timer interrupts (timer2 or timer0)? Isn't this better, so we don't have so much problems with the timing?

The code I have until now, is attached to this post

Thanks
 

Attachments

  • leds.jpg
    leds.jpg
    121.1 KB · Views: 129
  • leds&beep.jpg
    leds&beep.jpg
    179.2 KB · Views: 121
  • oven.zip
    4.6 KB · Views: 107
Last edited:
You are still "running away" and doing your own thing. If you want someone to help you, you must follow each request. A micro cannot do two things at the same time. Everything must be fitted into each other.
The beep or beeper must have a flag. When you set the flag and display the first digit, you need to turn on and off the beep line every 500uS or less. Then you go to the second display and look at the flag and do the same thing.
Get the piezo to have the correct sound by doing this and then allocate a certain number of cycles for the time to display each 7-segment. This is how you get the frequency of the scanning routine.
This is the next thing to do.
Your code is already getting far too complex.
I told you before to keep the code as simple as possible because we have a long way to go and the code will become enormously complex by the time you end if you don't keep things simple.
Once you get the beep happening as a continuous tone while the displays are showing, you can add another flag to detect when the key is not pressed and another counter routine to count the number of cycles of tone to produce the 250mS beep.
This beep routine, with all its counting and key detection, will be inside the 1mS delay routine.
This routine will eventually have a lot more in it as it will be doing all the "housekeeping" for detecting the switches and turning on and off the LEDs etc etc etc.
This is where everything will be done as it is not interfering with the display illumination.
But I want to see only a simple routine as Main so I can follow it and see when things go wrong.
Remove the timer interrupt, for a start. You cannot have anything that will interrupt the display routine for an unknown period of time.
 
Last edited:
Ok, removed all stuff that doesn't matter and left only the display showing the initial temperature (180 degrees) and 3 leds on:
Code:
;/****************************************************************************
;* DESCRIPTION: System definitions.
;*****************************************************************************/ 

	ERRORLEVEL -302 ;remove message about using proper bank

	LIST  P=16F677
	INCLUDE <P16F677.INC>
	__CONFIG _BOR_OFF & _FCMEN_OFF & _IESO_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO

;/****************************************************************************
;* DESCRIPTION: Program variables and constant definitions.
;*****************************************************************************/ 

TEMPER		EQU 0x20			; Store temperature
UNITS		EQU 0x24			; UNITS
TENS		EQU 0x25			; TENS
HUNDREDS	EQU 0x26			; HUNDREDS
AUX		EQU 0x27			; GENERAL AUX. REGISTER
TEMPO0		EQU 0x28
TEMPO1		EQU 0x29
FLAGS		EQU 0x2B			; General use flags
TIMER		EQU 0x2D			; Timer register

; Leds
#DEFINE		LED_CMN		PORTC,2		; Leds Anodes

#DEFINE		LED_UP		PORTA,4		; Led UP
#DEFINE		LED_TIMER	PORTB,6		; Led TIMER
#DEFINE		LED_TEMP	PORTB,5		; Led TEMP
#DEFINE		LED_DWN		PORTA,2		; Led DWN
#DEFINE		LED_LIGHT	PORTB,4		; Led LIGHT
#DEFINE		LED_TOASTER	PORTA,5		; Led TOASTER
#DEFINE		LED_ONOFF	PORTC,6		; Led ONOFF
#DEFINE		TRIS_LED_ONOFF	TRISC,6		; Led ONOFF TRIS

; Displays
#DEFINE		DISP1		PORTC,3		; Anode display DIS0
#DEFINE		DISP2		PORTC,4		; Anode display DIS1
#DEFINE		DISP3		PORTC,5		; Anode display DIS2

;/****************************************************************************
;* DESCRIPTION: Got Start of program.
;* return:      none
;* ALGORITHM:   none
;* NOTES:       none
;***************************************************************************** 
	ORG	0x0000
	goto	START

;/****************************************************************************
;* DESCRIPTION: Decodes value in W register to display segments for PORTA.
;* return:      result in W
;*****************************************************************************/ 

DECDISP_A:
	addwf   PCL,F		; compute the jump value
				;	|7|6|5|4|3|2|1|0| -	Bits PORTA
				;	|-|-|B|E|-|A|-|-|
	retlw	B'00000000'	;	|-|-|B|E|-|A|-|-| -	0
	retlw	B'00010100'	;	|-|-|B|X|-|X|-|-| -	1
	retlw	B'00000000'	;	|-|-|B|E|-|A|-|-| -	2
	retlw	B'00010000'	;	|-|-|B|X|-|A|-|-| -	3
	retlw	B'00010100'	;	|-|-|B|X|-|X|-|-| -	4
	retlw	B'00110000'	;	|-|-|X|X|-|A|-|-| -	5
	retlw	B'00100000'	;	|-|-|X|E|-|A|-|-| -	6
	retlw	B'00010000'	;	|-|-|B|X|-|A|-|-| -	7
	retlw	B'00000000'	;	|-|-|B|E|-|A|-|-| -	8
	retlw	B'00010000'	;	|-|-|B|X|-|A|-|-| -	9


;/****************************************************************************
;* DESCRIPTION: Decodes value in W register to display segments, for PORTB.
;* return:      result in W
;*****************************************************************************/ 

DECDISP_B:
	addwf   PCL,F		; compute the jump value
				;	|7|6|5|4|3|2|1|0| -	Bits PORTB
				;	|C|F|D|G|-|-|-|-| -
	retlw	B'00010000'	;	|C|F|D|X|-|-|-|-| -	0
	retlw	B'01110000'	;	|C|X|X|X|-|-|-|-| -	1
	retlw	B'11000000'	;	|X|X|D|G|-|-|-|-| -	2
	retlw	B'01000000'	;	|C|X|D|G|-|-|-|-| -	3
	retlw	B'00100000'	;	|C|F|X|G|-|-|-|-| -	4
	retlw	B'00000000'	;	|C|F|D|G|-|-|-|-| -	5
	retlw	B'00000000'	;	|C|F|D|G|-|-|-|-| -	6
	retlw	B'01110000'	;	|C|X|X|X|-|-|-|-| -	7
	retlw	B'00000000'	;	|C|F|D|G|-|-|-|-| -	8
	retlw	B'00000000'	;	|C|F|D|G|-|-|-|-| -	9

;/****************************************************************************
;* DESCRIPTION: Little Delay to let display show digit.
;* return:      none
;*****************************************************************************/ 

H_keeping:			; Delay routine - W is the number of ms of delay.
	movwf	TEMPO1		; put w in temp variable
	movlw	D'250'
	movwf	TEMPO0
	decfsz	TEMPO0,F
	goto	$-1
	decfsz	TEMPO1,F
	goto	$-5
	return

;/****************************************************************************
;* DESCRIPTION: binary_to_bcd - 8-bits
;* INPUT:	TEMPER   - 8-bit binary number
;* return:      HUNDREDS - the hundreds digit of the BCD conversion
;*		TENS     - the tens digits of the BCD conversion
;*		UNITS    - the ones digits of the BCD conversion
;*****************************************************************************/ 
BIN2BCD:

	movwf	AUX		; save the value to convert in AUX
	clrf	UNITS		;
	clrf	TENS		;
	clrf	HUNDREDS	; RESET variables
	movf	AUX,F		;
	btfsc	STATUS,Z	; Is the value to convert = 0?
	return			; Yes - Return
				; No
	incf	UNITS,F		; Increment unit
	movf	UNITS,W		;
	xorlw	0X0A		;
	btfss	STATUS,Z	; unit = 10d ?
	goto	$+3		; No
				; yes
	clrf	UNITS		; Reset unit
	incf	TENS,F		; Increment tens
	movf	TENS,W		;
	xorlw	0X0A		;
	btfss	STATUS,Z	; Tens = 10d ?
	goto	$+3		; No
				; Yes
	clrf	TENS		; Reset tens
	incf	HUNDREDS,F	; Increment hundreds
	decfsz	AUX,F		; End of conertion ?
	goto	$-.14		; No - go back to continue the convertion
	return			; Yes

;/****************************************************************************
;* DESCRIPTION: Program Initialization
;*****************************************************************************/ 

START:
	bcf	STATUS,RP0	; Bank 2
	bsf	STATUS,RP1	;
	clrf	ANSEL		; digital I/O
	clrf	ANSELH		; "	"	"
	movlw	B'00000000'
	movwf	CM1CON0		; disable comparator
	movlw	B'00000000'	; Not necessary?
	movwf	CM2CON0		; disable 2nd comparator
	movlw	B'00000000'	; Not necessary?
	movwf	CM2CON1		; disable 3rd comparator
	bsf	STATUS,RP0	; Bank 1
	bcf	STATUS,RP1	;
	movlw	B'00001000'	;
	movwf	TRISA		;
	movlw	B'00000000'	;
	movwf	TRISB		;
	movlw	B'10000010'	;
	movwf	TRISC		;
	bcf	STATUS,RP0	; Bank 0
	bcf	STATUS,RP1	;
	bcf	SSPCON,SSPEN	; Disable Synchronous Serial Port

	; Turn off all reles, displays and leds
	bsf	LED_CMN		; Leds off
	bsf	DISP1		; Display1 off
	bsf	DISP2		; Display2 off
	bsf	DISP3		; Display3 off
	movlw	D'180'		; Init temperature with 180 degrees Celsius
	movwf	TEMPER		;
	movlw	D'40'		; Start TIMER with 40 minutes
	movwf	TIMER		;
	clrf	UNITS
	clrf	TENS
	clrf	HUNDREDS

;/****************************************************************************
;* DESCRIPTION: Main Program
;*****************************************************************************/ 
MAIN_LOOP:
	movf	TEMPER,W	; Put temperature in W
	call	BIN2BCD		; Decode Temperature to bcd
	bsf	LED_CMN		; Leds off
	movf	UNITS,W		; copy units to W
	call	DECDISP_A	; convert
	movwf	PORTA		; put it in PORTA
	movf	UNITS,W		; copy units to W
	call	DECDISP_B	; convert
	movwf	PORTB		; put it in PORTA
	bcf	DISP1		; display 1 on
	movlw	D'2'		;
	call	H_keeping	; delay 2 ms
	movf	TENS,W		; copy tens to W
	call	DECDISP_A	; convert
	bsf	DISP1		; display 1 off
	movwf	PORTA		; put it in PORTA
	movf	TENS,W		; copy tens to W
	call	DECDISP_B	; convert
	movwf	PORTB		; put it in PORTA
	bcf	DISP2		; display 2 on
	movlw	D'2'		;
	call	H_keeping	; delay 2 ms
	movf	HUNDREDS,W	; copy hundeds to W
	call	DECDISP_A	; convert
	bsf	DISP2		; display 2 off
	movwf	PORTA		; put it in PORTA
	movf	HUNDREDS,W	; copy hundeds to W
	call	DECDISP_B	; convert
	movwf	PORTB		; put it in PORTA
	bcf	DISP3		; display 3 on
	movlw	D'2'		;
	call	H_keeping	; delay 2 ms
	bsf	DISP3		; display 3 off

	; Leds code:
	bsf	LED_UP		; led UP ON
	bsf	LED_DWN		; led DWN ON
	bsf	LED_TEMP	; led TEMP ON
	bsf	LED_TIMER	; led TIMER ON
	bsf	LED_LIGHT	; led LIGHT ON
	bsf	LED_TOASTER	; led TOASTER ON
	bsf	LED_CMN		; Leds on
	movlw	D'2'		;
	call	H_keeping	; delay 2 ms
	bsf	LED_CMN		; Leds off

	goto	MAIN_LOOP	; Back to main loop

	END

Sergio
 
Last edited:
You still havent simplified things fully.

All the housekeeping will be done in the delay sub-routine as this is called four times during the scanning.
Main will simply consist of turning on a digit and calling delay - three times - then the LEDs and calling delay.
Even the names of the sub-routines can be shortened as everything has to be kept as short and small as possible to give the effect of simplicity.
All the LEDs and keys are off to start-with and when a key is pressed, a flag is set. The routine looks at the flag to deal with the key. This also applies to the LEDs as this is how they will flash.
You can't be going away and doing something separate as this will interfere with the scanning and the sound of the beep. All the scanning must take the same time from now on and so the sub-routines must just be looking for a flag so that a particular operation can be carried out.
You will need to have dedicated files to hold values that will be decremented on each pass of the scan routine, to produce the length of time for the beep and also the length of time for the LED on and LED off flash-rate. Everything will have to fit in with the timing of the scan. So the timing of the scan and the sound of the beep are the first things to organise.
Once this is done, the number of NOPs in the delay will be reduced as more housekeeping instructions are placed in this sub-routine - so the sound of the beep does not change.
 
Last edited:
I changed some of the routines names, in the code which is in my previous post.

Sorry, but I didn't get this:
When you tell:
Main will simply consist of turning on a digit and calling delay - three times - then the LEDs and calling delay.
You mean to put, in the main, just a call to subroutines which will take care of displays and leds?
See if the code in previous post is what you mean. I just edited it.
 
Last edited:
Main looks to be ok.

movlw D'2' ;
call DELAY_MS ; delay 2 ms

will be changed to call H_keeping

which will do all the housekeeping and produce the delay to show each digit.
 
Done.
You can see it in the code in the previous post I told you (just edited the post and tested it - compiled ok).
 
Housekeeping of 2mS will be created by NOPs as well as housekeeping commands.

Change

movlw D'2' ;
call H_keeping ; delay 2 ms


to

call H_keeping ; delay 2 ms

as this will remove 4 unnecessary instructions

the value of "2" will be in the housekeeping sub-routine and may not be 2 as housekeeping will now consist of turning on and off the piezo line and the NOP delay section will only be 500uS or so.

Now work on turning the piezo on and off to get the right sound. That's all you have to do at this stage. Just get the right sound.
Then you add the feature to detect a key to turn it on while the key is kept pressed for 2 seconds and make sure the sound of the piezo does not alter.
Then make the piezo sound for only 250mS no matter how long the key is pressed. Then detect the key is not pressed so the piezo can beep when another key is pressed. In this way you can have the piezo beep every time a key is pressed and be able to control exactly when you want the piezo to beep or not beep.
This is how you add one feature at a time and make sure it works before adding something else.
That's the only way to prevent frustration.
 
Last edited:
Ok, just changed the calls as you asked an put the movlw D'2' in the beginning of the H_keeping to test - compiled and working fine.
Now, I will test the buzzer stuff.
The code for the buzzer is like this one, inside the H_keeping?
Code:
BEEP:
	movwf	BEEPCNT
BEEP0:
	bsf		BUZZER			; beepctl bit
	movlw	4
	call	udelay
	bcf		BUZZER			; beepctl bit
	movlw	4
	call	udelay
	decfsz	BEEPCNT, F
	goto	BEEP0

and, the udelay:
Code:
udelay						; delay W * 100 usec
	movwf	DCNT0
udelay0
	movlw	26
	movwf	DCNT1
udelay1
	decfsz	DCNT1,F
	goto	udelay1
	decfsz	DCNT0, F
	goto	udelay0
	return

For a 1 KHz frequency, I need to make a period on/off of 500 us.
 
Last edited:
Try to keep the number of sub-routines to a minimum.
Put all the beep in the housekeeping sub-routine like this:

H_keeping

Code:
        bsf          buz            ; piezo on
        movlw     .170
        movwf    buz_file
        decfsz     buz_file,f
        goto        $-1
        bcf          buz            ; piezo off        
        movlw     .170
        movwf    buz_file
        decfsz     buz_file,f
        goto        $-1
        bcf          buz            ; piezo off
        decf        buz_length    ; this is a file that you have previously set to 0ffh to create 250mS tone 
        retlw    00
 
Last edited:
That's why I have called it piezo. YOU called it buzzer. I call it piezo diaphragm, to differentiate it from an active device.
 
I misunderstood the post, so I edited mine.
Now, the code is :

In the variables definition:
Code:
buz_file	EQU 0x2E			; Buzzer file
buz_length	EQU 0x2F				; Buzzer length

In the defines:
Code:
; Buzzer
#define		buz		PORTC,0		; Buzzer

For the housekeeping:
Code:
H_keeping:
	movlw	D'255'
	movwf	buz_length

	bsf	buz		; piezo on
	movlw	.170
	movwf	buz_file
	decfsz	buz_file,f
	goto	$-1
	bcf	buz		; piezo off        
	movlw	.170
	movwf	buz_file
	decfsz	buz_file,f
	goto	$-1
	bcf	buz		; piezo off
	decf	buz_length,F	; 
	retlw	00

I can load the buz_length at the start of it, doesn't?
 
Last edited:
No, I can't load the buz_length at the start of house keeping.It will be decremented at each call to it, isn't?
 
Buzzer (piezo) has to be loaded in "SetUP" or if you have a file that simply decrements from 0ffh to zero, (in other words, exactly 256 loops), it gets loaded again as soon as the key is detected as being not pressed.
 
Status
Not open for further replies.

Latest threads

Back
Top