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 16F877 timer

Status
Not open for further replies.

falleafd

New Member
h'11' = b'00010001' not b'00100001', that is rb0 and rb4 are inputs.

I don't remember exactly, but if i'm right, there is a problem that if a pin of a port is set to output, the pull up resistor will be removed. Therefore, you cannot push portB <1> if you are setting it as output.

Be careful with this.

Why don't you movlw h'ff' or you can use binary numbers for sure in this case?

scan the port is good, no problem. Because as you push, you must hold down it longer than your short program takes to re-scan. However, if you write a long program, it may causes problems. Because as you push the button, the program is still running somewhere, and you lift your finger up, the program is still running somewhere. It cannot detect the changes at the port. In this case, you must use interrupts.
 

Exo

Active Member
Afther the bit tests i see a GOTO B1_Routine and B2_Routine, where are these? I can only see a B1_Response and a B2_Response further down...

Did you mix them up?

Secondly how did you connect your inputs? Do remeber that the pic's inputs must always be in a known state. So just connecting an input to VDD with a switch isn't enough. When you release the button the pin will be floating (connected to nothing) wich will cause strange behaviour.

I recomment putting a pull-up resistor from about 10K from the input pin to VDD and then connecting the input pin to ground with a switch.
When the button is not pressed the input will be 5V (trough the resistor) and if you press then the input will be ground (with the resistor preventing short circuit)
 

Exo

Active Member
falleafd said:
No need. PIC has internal pull up resistors. And as you set it outputs, the resistors are automatically removed, and if you set it inputs. The pull up resistors are available.

Pull up resistors are only needed for 89C51. Some modern MC such as AVR or 89C51 of Phillips have their internal pull ups.

In his code is is testing for a set bit (BTFSC), not for a cleared bit. So i assume he has connected the switch to VDD. Eighter he doesnt use the internal pullups and has a high/floating situation. Or he uses internal/external pullups and he always has a logic '1'.

So no matter if he uses internal or external pullups, he probably connected the switch wrong. It needs to go to ground and the code must be modified to test for a cleated bit (BTFSS)
 

patricktran

New Member
oops, sorry. The original code was B1_routine, B2_routine. But when I pasted it into this, I feel bad as this is not a routine (I didnt use call, but goto), then I changed it to B1_response. But surely, the original code has not that conflict.

In his code is is testing for a set bit (BTFSC), not for a cleared bit. So i assume he has connected the switch to VDD. Eighter he doesnt use the internal pullups and has a high/floating situation. Or he uses internal/external pullups and he always has a logic '1'.

So no matter if he uses internal or external pullups, he probably connected the switch wrong. It needs to go to ground and the code must be modified to test for a cleated bit (BTFSS)

Ohh, I did connect the switch to a resister and then to VDD, and the pin itself to ground. So I think if I dont push the button, it is ground (bit is clear), if I push, then the button is ....still ground!!! hic hic, this is my first experience with push button. :oops:
Ok, so according to Exo, I should
I recomment putting a pull-up resistor from about 10K from the input pin to VDD and then connecting the input pin to ground with a switch.
When the button is not pressed the input will be 5V (trough the resistor) and if you press then the input will be ground (with the resistor preventing short circuit)
But like falleafd said,
No need. PIC has internal pull up resistors. And as you set it outputs, the resistors are automatically removed, and if you set it inputs. The pull up resistors are available.
So should I use a resister addtion to the button?
And if yes, I will connect it like Exo advised with a btfss in my code.
Thanks
 

Nigel Goodwin

Super Moderator
Most Helpful Member
Try looking at my tutorials, they show how to read buttons simply - they are written for the 16F628, but it uses exactly the same 14 bit core instructions - only setting of the various extra hardware is different.
 

Exo

Active Member
patricktran said:
But like falleafd said,
No need. PIC has internal pull up resistors. And as you set it outputs, the resistors are automatically removed, and if you set it inputs. The pull up resistors are available.
So should I use a resister addtion to the button?
And if yes, I will connect it like Exo advised with a btfss in my code.
Thanks

The pullup resistors falleafd talked about are only available on portB. So if you want you can use them, but only on that port.

I would just use an external resistor for know. You can always play around more with the internal pullups once you better understand the pic.
 

patricktran

New Member
Thanks alot for your help guys. :D
After many days of reading, and thinking, lastly, I got some code that uses TMR1 and turns on and off the LEDs every 1 sec. But sadly, it just nothing happened. :(
Could someone please help me out of this trouble? I reckon something wrong with the TMR1 setting up!
Code:
; Use 4 MHz crystal frequency.
	list  P=PIC16F877,  F=INHX8M,  C=160, N=80,  ST=OFF, MM=OFF, R=DEC
	include "C:\MPLAB\MCHIP_Tools\p16F877.inc"
	__config ( _HS_OSC & _LVP_OFF)
	errorlevel -302  

;----------------- Define vaiables ----------------
LBTMR1      equ	H'77'   ;  
HBTMR1      equ	H'EC'   ;  
reg         equ 0x20    ; ON, OFF, ON, OFF Led at bit 0
Temp_W      equ 0x21
Temp_STATUS equ 0x22
;----------------- Vectors -------------------------


	org	H'000'
	goto	Main
	org	H'004'
	goto	ISR

Main
	call Initial

Loop





Initial
        bcf      STATUS,RP0   ; 
        bcf      STATUS,RP1   ; Bank 0 selected 
        clrf     PORTA 
        bsf      STATUS,RP0   ; Bank 1 selected 
        movlw    H'00'        ; All pins of PORTA outputs 
        movwf    TRISA

        bcf      STATUS,RP0   ; 
        bcf      STATUS,RP1   ; Bank 0 selected 
	movlw       b'00000001'
	movwf       reg         ; first interrut of TMR1, turn LED on
	call        TMR1Setup
	return

TMR1Setup
    	bcf	    STATUS, RP0
	bcf	    STATUS, RP1		; Bank 0 selected
	movlw       LBTMR1  		; H'77'
	movwf	    TMR1L
	movlw       HBTMR1  		; H'EC'
	movwf	    TMR1H
	clrf	    FlagsReg
  
	movlw       H'01'		; Timer 1 prescaler set to 1
	movwf       T1CON  		; Turn on TMR1
    	bsf         STATUS, RP0		; Bank 1 selected
	bsf         PIE1,TMR1IE
	bcf	    STATUS, RP0		; Bank 0 selected
        movlw       H'C0' 		; Set GIE, PEIE
	movwf	    INTCON		; Interrupt controller setting
	return







ISR
	call        Context_saving
        call        Display
	call        TMR1Reset
	call        Context_restoring
	retfie



Context_saving
	movwf 	    Temp_W 
	swapf       STATUS, W 
	movwf       Temp_STATUS 
	return

Context_restoring
	swapf Temp_STATUS, W 
	movwf STATUS 
	swapf Temp_W, F 
	swapf Temp_W, W 
	return




TMR1Reset
	movlw   LBTMR1
	movwf	TMR1L
	movlw   HBTMR1
	movwf	TMR1H
	bcf     PIR1,TMR1IF          ; clear the TMR1 interrupt flag
	return

Display
        btfss   reg, 0
        call    Turn_On
        call    Turn_Off
	return

Turn_On
        bsf     reg,0
        movlw   b'11111111'
        movwf   PORTA
	return

Turn_Off
        bcf     reg,0
	movlw   b'00000000'
        movwf   PORTA
	return

Thanks
 

falleafd

New Member
Code:
Main 
   call Initial 

Loop 

Initial 
        bcf      STATUS,RP0   ; 
        bcf      STATUS,RP1   ; Bank 0 selected 
        clrf     PORTA 
        bsf      STATUS,RP0   ; Bank 1 selected 
        movlw    H'00'        ; All pins of PORTA outputs 
        movwf    TRISA 

        bcf      STATUS,RP0   ; 
        bcf      STATUS,RP1   ; Bank 0 selected 
   movlw       b'00000001' 
   movwf       reg         ; first interrut of TMR1, turn LED on 
   call        TMR1Setup 
   return

After you call Initialize, it will implement the next instruction which is the beginning of Initialize routine.

To the end of Initialize, a RETURN will go back to the TOS which is now 0x0000. And your program will in loop forever.

And the timer1 will never be interrupted because your loop will re-install the new value for timer1 register (TMR1L and TMR1H). It then run again and again. TMR1 never get 65535 to 0 to make interrupt.
 

Exo

Active Member
Yes, it needs a 'GOTO Loop' instruction between the lables 'Loop' and 'Initial' like falleafd pointed out

then, there is also a problem with your Display routine
Code:
Display 
        btfss   reg, 0 
        call    Turn_On 
        call    Turn_Off 
   return

If Reg, 0 is set then the led will be turned off like expected, no problem here. But if Reg, 0 is clear then the Turn_On routine will be called, wich turns the led on, but when it returns Turn_Off is called wich turns the led off again, this happens so fast you'll never see the led turn on...

Use something like this instead:
Code:
Display 
        btfss    reg, 0 
        goto     _On

        bcf      reg, 0
        call     Turn_Off
        return

_On 

        bsf      reg, 0
        call     Turn_On
        return
 
:idea:

The other way to record port (switch/button) changes using int's it to use 2 regisiters and a flag in the in sub.......

OLD_PORTB
SW_VALUE_B
SW_FND_FLG (flag bit)

theory for int code, generated via say timer 0 evey 10ms......

*************************************************

read port b

compare port b to OLD_PORTB

same?
Yes, exit int.....

No, Store current port B into OLD_PORTB

is SW_FND_FLG set?
Yes, exit int.....

No, Store current port B into SW_VALUE_B, set SW_FND_FLG

exit int

*************************************************

OK, so how does this help?

well, you code checks the SW_FND_FLG, if set, you know a switch has been pressed sometime between 0->10MS, look at SW_VALUE_B to see which one...... then clear SW_FND_FLG, the int code will set the flag on another change of the switch, this will debounce the switch for you....

Why use the flag?? Well this means that if the switch value changes again before you test the SW_FND_FLG, the change will be saved.....

Why bother with this when I can use int on change on portB??? Well you can use this code on any port also the int on change will pick up every "bounce" on the switch contacts, so you will need to impliment a timer/flag etc to get rid of these anyway. AND if you are using a timer anyway it's like getting extra for free (sort of!) AND it's just nice to do things a bit differnt!! :wink:
 

patricktran

New Member
Oh, thanks alot evryone. I am very appreciate for your helps. I realise that this forum is very useful, speacially to newbies like me.
Thanks :p
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top