Talking Electronics PIC Theory

Button - Carry

"Button" is any switch or device connected to the '508A that makes the input line go LOW or HIGH. 
For simplicity we assume the push button is connected to GP3. This line is INPUT ONLY while the others 5 pins are input/output. The other I/O pins are called: GP0, GP1, GP2, GP4, GP5. 
GP3 is pin 4 of the chip. Refer to the diagram for the push-button circuit. When the button is pressed it puts a HIGH on pin 4.


But_S is a simple routine that detects when a button on GP3 is pressed and sets bit 7 in file 1E. Refer to dia. 1. This is called the "button-press" flag and lets the program know that the button has been detected. The routine does one pass and returns to Main. 

1. To call But_S, type the following into the Main routine: 

                   CALL But_S 

2. Before the Main routine, type the sub-routine:

But_S      MOVLW 08         ;Load W with 00 1000 
               TRIS 06              ;Make GP3 input 
               BTFSC 1E,7        ;Test bit7 of 1E, skip if clear 
               BTFSC 06,3 
               BSF 1E,7            ;Switch pushed, set bit7 in 1E 

But_S routine sets up GP3 as an input pin (lines 1 and 2 in the program above). Line 3 tests bit7 of file 1E to see if button has already been pressed. Line 5 tests bit 3 of the port (GP3) and if the bit is set, the program goes to line 6. If it is clear, the routine RETURNS to Main. 
3. You will need another routine called But_Pres to look at bit 7 of file 1E and carry out an instruction if it is set. This routine will also clear bit 7, ready for the next time the button is pressed. 

After CALL Button_S, type CALL But_Pres: 

               CALL Button_S 
               CALL But_Pres 

4. Before the main routine you will need to type the But_Pres sub-routine, but firstly ask, "What do we want to happen when the button is pressed?" 
Here are 4 examples: 

A HIGH is output to GP1 for the same length of time as the button is pressed. A LED (in series with a 1k resistor) connected to GP1 will illuminate when the push button is pressed. See dia. 3.

But_Pres     BTFSC 1E,7          ;Test Bit7, 1E. Skip if clear 
                   BCF 1E,7              ;Clear bit7 in 1E 
Your instructions go here and must finish with a RETURN. An example is to output a
                          HIGH to GP1. Don't forget to turn it off after a delay period. 

   E.g:          MOVLW 02            ;Load W with 00 0010 
                   MOVWF 06            ;Output a HIGH to GP1 

This routine looks a bit 0 in file 1E and returns to the main program if the button has already been pressed. If no button has been pressed, the routine loads W with 02 to turn on GP1. The flag (Bit0 in 1E) is cleared and the routine returns to main. 

B. Toggle a LED on GP1. 

Each time the push button is pressed, the LED will change from on to off or off to on. Diag. 2 shows the button-press flag in file 1E and Dia. 3 shows the connection of the switch and LED to the micro.

1. To call But0_1, type the following into the main program: 

           CALL But0_1 

2. Before the Main routine type the sub-routine: 

But0_1      MOVLW 08        ;Load W with 0000 1000 
                TRIS 06              ;Make GP3 an input 
                BTFSS 06,3        ;Test GP3. Skip if set 
                GOTO TB3          ;No button pressed 
                BTFSC 1E,7        ;Test "button-press" bit 
                GOTO TB4          ;Not first time 
                MOVLW 01         ;First time: Load W with 01 
                XOR 1E,1            ;Toggle bit 0 
                BTFSS 1E,0        ;Test bit 0. Skip if set 
                GOTO TB1           ;Goto "turn off GP1" 
                MOVLW 02          ;Load W with 02 to turn on 
                MOVWF 06          ; GP1 
                GOTO TB2 
TB1          MOVLW 00          ;Load W with 00 to turn off 
                MOVWF 06          ; GP1 
          BSF 1E,7             ;Set "button-press" bit 
                GOTO TB4           ;Get out of routine 
TB3          BCF 1E,7             ;Clear "button-press" bit 
TB4          DECFSZ 1A,1       ;Short delay for key-bounce 
                GOTO TB4 

But0_1 Routine: 

The routine firstly makes GP3 an input pin (lines 1, 2 in the program above). The program then tests bit 3 of file 06 (GP3) and if it is HIGH, it goes to line 5 where another decision is made. Bit 7 of file 1E will be clear the first time through the sub-routine and will be set when GP3 is activated or deactivated. Bit 7 will be cleared when the key is released. 

At lines 8, 9, bit 0 of 1E is toggled by XORing 1E with W. W has 0000 0001 and if 1E has 0000 0001, the result will be 0000 0000. If 1E has 1000 0000, the result will be 1000 0000. The result of the toggle 
operation will be placed in file 1E and bit 0 is tested in line 10. If it is zero, GP1 is turned off at line 15 and if bit 0 is 1, GP1 is turned on, at line 12. Before returning, Bit 7 of 1E is set so that the toggle instruction is not executed until the button has been released and re-pressed. 


Place an LED and 1k resistor on lines GP0, GP1, GP2, GP4 and GP5. Each time the button is pressed, the next LED turns on. This feature is a complete program and the Main routine should be as follows: 

Main CALL But1to6 

GOTO Main 

The sub-routine will illuminate the 5 LEDs, one at a time, each time the button is pressed. After the fifth LED the sub-routine will go to the instruction GOTO Main and the micro will CALL But1to6 and repeat the effect. A transistor (with a 1k to 10k resistor in the base) can be connected to each output and the program can be used to select 5 different items, one at a time. 

The program has six shifts but only five LEDs are activated as GP3 is the input line. The circuit is shown in dia. 5:

Before Main, type the But1to6 sub-routine: 

But1to6      CLRF 1E             ;Clear "button-press" file 
                 MOVLW 05          ;Load W with 5 
                 MOVWF 1A         ;file 1A is the count file 
                 MOVLW 08          ;Load W with 8 
                 TRIS 06                ;Make GP3 an input 
                 MOVLW 01          ;Load W with 1 
                 MOVWF 06          ;also put 01 into file 06 
But16A      DECFSZ 1B,1       ;Short del for key-bounce 
                 GOTO But16A 
                 BTFSS 06,3          ;Test GP3 for button 
                 GOTO But16C       ;No button pressed 
                 BTFSC 1E,7          ;Test "button-press" bit 
                 GOTO But16A       ;Not first pass 
                 DECFSZ 1A,1        ;1st pass, so decrement count file 
                 GOTO But16B 
But16B      BSF 1E,7               ;Set "button-press" bit 
                 RLF 06,1                ;Rotate file 06 left 
                 GOTO But16A 
But16C      BCF 1E,7               ;Clear "button-press" bit 
                 GOTO But16A 


The routine firstly clears the button-press file 1E. It then loads the count file (file 1A) with 5, via W. W is loaded with 8 in line 4 and passed to the TRIS register to make GP3 an input. The "1" in W is loaded into file 06 to make GP0 HIGH. 
A short delay is created by decrementing file 1B. This file will be zero after the first pass and since the instruction is to decrement the file then skip if zero, the delay will produce 256 loops without having to load the file with a value. At line 10, bit 3 of file 06 (GP3) is tested to see if the buttons has been pushed. The bit will be HIGH when pushed. If it is clear, the micro goes to line 12 where the button-press is tested. If it is clear, it indicates the first pass of the program when a button has been pressed. At line 14 the count file is decremented and if file 1A is not zero, the micro sets the "button-press" bit and shifts the bit across the port to make GP2 HIGH. 

At line 18, the "1" in bit0 of file 6 (the 6-bit port) is shifted left - into bit1 position and this makes GP1 HIGH. 

The program loops until all 6 lines have been activated and the micro returns to the instruction GOTO Main at the Main routine. The micro goes to Main where is sees the instruction GOTO But1to6 and the whole process is repeated. 

A short pulse is sent on line "GP1" each time the button is pressed. 
This routine can be used for "clocking" an external device such as a counter chip. A button is placed on line GP3 and each time it is pressed, a pulse is sent out line GP1. The pulse can be lengthened 
or shortened by changing the value loaded into file 1B at line 11. 

In the Main routine, insert the following: 

CALL But_Puls 

Before Main routine, type the sub-routine: 

But_Puls     MOVLW 08           ;Load W with 8 
                  TRIS 06                 ;Make GP3 an input 
ButPA         DECFSZ 1B,1        ;Short delay for key-bounce 
                  GOTO ButPA 
                  BTFSS 06,3 
                  GOTO ButPC         ;No button pressed 
                  BTFSC 1E,7           ;Test "button-press" bit 
                  RETURN                ;Not first pass 
                  BSF 06,1                ;1st pass, Make bit1 HIGH 
                  MOVLW 7F            ;7F is the pulse length 
                  MOVWF 1B 
ButPB         DECFSZ 1B,1         ;Create HIGH pulse length 
                  GOTO ButPB 
                  BCF 06,1                 ;Make bit 1 LOW 
                  BSF 1E,7                ;Set "button-press" bit 
ButPC         BCF 1E,7                 ;Clear "button-press" bit 

This routine makes GP3 an input and provides a short delay for keybounce. Bit 3 in file 06 (GP3) is tested and if it is set, the program skips the next instruction. If a key is pressed for the first time GP1 is made HIGH and 7F is loaded into a file and decremented to produce the length of time for the HIGH. 

Bit 1 is then made LOW to end the pulse. Button-press flag in file 1E is SET so that the routine will not be entered by the same press of the button. The button has to go LOW before another pulse can be 
produced. This is called "key-debounce." 


Butn_R has a repeat feature. When the button is pressed it sends a short pulse on line GP1. After 0.75 seconds the pulse is repeated. This is produced 4 times then the pulse is repeated at 0.25 second intervals until the button is released. 

In the Main routine, insert the following: 

CALL Butn_R 
Before Main routine, type the sub-routine: 

Butn_R          MOVLW 04          ;Put 4 into W 
                     MOVWF 1E         ;Load the count file with 4 
                     MOVLW 08          ;Load W with 8 
                     TRIS 06                ;Make GP3 an input 
ButnRA          MOVLW 06h        ;Load the high counter with 
                     MOVWF 1C          ; 6 loops 
ButnRB          BTFSS 03,2         ;Test GP3 
                     RETURN              ;No button pressed 
                     BSF 06,1             ;Make bit1 HIGH 
                     MOVLW 7F          ;7F is the pulse length 
                     MOVWF 1B          ; Load 7F into dec file 
ButnRC          DECFSZ 1B,1       ;Create HIGH pulse length 
                     GOTO ButnRC 
                     BCF 06,1              ;Make bit 1 LOW 
                     CALL Del 
                     DECFSZ 1E,1        ;Dec the count file 
                     GOTO ButnRA 
                     MOVLW 02           ;Del for 0.25seconds 
                     MOVWF 1C           ; 
                     MOVLW 01            ;This will make 1E skip 
                     MOVWF 1E            ; around DECFSZ above! 
                     GOTO ButnRB 
                     Del DECFSZ 1A,1 
                     GOTO Del 
                     DECFSZ 1B,1 
                     GOTO Del 
                     DECFSZ 1C,1 
                     GOTO Del 

The program loads the count file with 4 for 4 loops. This produces the brief pulses every 0.75 sec. After the 4 loops, the delay is loaded with 2 and the whole routine is cycled at the rate of 0.25sec until 
the button is released. The clever part is to load 1E with 1 so that it skips around the DECFSZ instruction at approx the middle of the program, so you can use the top part of the program with the different value for the delay. The pulse is sent out via GP1 at 0.25 sec intervals. The length of the pulse can be adjusted by loading 1B with a different value. 
Normally you cannot use the same register for two different applications within a routine but with 1B, it is left at 00 after the DECFSZ instruction and this gives it FF loops for the delay. 
The delay routine is very simple as we have not preloaded the inner files with a value as they will contain 00 (the longest delay) after the first pass. The outer file is 1C and it is preloaded with 6 for 
the 0.75sec delay. After 4 loops of the program 1C is loaded with 02 for 0.25sec delay. 


Two buttons can be connected to one input line with a very small program. 
The accompanying diagram shows how to connect them. 

Button A is AC coupled to the chip and when it is pressed, GP3 sees a HIGH for a very short period of time. When button B is pressed, GP3 sees a HIGH for the duration of the press. The program can distinguish between the two pulses. In the Main program, GP3 has to be "poled" (looked at frequently) so that button A is not missed. 
The pulse-length of button A is approx 1/100th sec. This is equal to approx 7500 instructions. This means you must pole GP3 every 7500 instructions so it is not missed and you cannot have a long delay routine elsewhere in the program. If you want a long delay, you need to embed a feature that looks at GP3 within the delay. 
This is simple enough - just a reminder. 
Thus, to look at the difference between button A and button B, we need to include a delay longer than 32 x 256 (20h x FF), looking at the input before and after the delay. 
The only requirement is to press either button fairly slowly so the difference can be recognised. 
The sub-routine sets bit 0 in file 1E for button A and bit 1 for button B. 
A "button press" flag prevents either bit being set more than once for every press of the button - the program looks for the button being released. 
One requirement is to make sure the capacitor and resistor values on the switch do not exceed 1/100th sec pulse time - stick to the values we have chosen. 
In the Main program, type: 

CALL Btns_2 
Before Main, put the sub-routine: 

Btns_2     MOVLW 08          ;Load W with 8 
               TRIS 06                ;Make GP3 an input 
               BTFSS 06,3          ;Test GP3 
               GOTO Btn4B         ;No button pressed 
               BTFSC 1E,7          ;Test "button-press" bit 
               RETURN               ;Not first pass 
               MOVLW 30h         ;Create a delay that is longer 
               MOVWF 1A          ; than the pulse length of 
               MOVLW FF          ;  button A . 
               MOVWF 1B          ; Use files 
Btn2A      DECFSZ 1B,1       ; 1A and 1B for 
               GOTO Btn2A         ; decrementing 
               DECFSZ 1A,1        ; purposes 
               GOTO Btn2A         ;End of delay routine 
               BTFSS 06,3           ;Look at GP3 again 
               GOTO Btn2B         ;No pulse. Therefore A 
               BSF 1E,1              ;Pulse. Therefore button B 
               GOTO Btn3B 
Btn2B      BSF 1E,0              ;Set bit 0 for button A 
Btn3B      BSF 1E,7              ;Set "button-press." 
Btn4B      BCF 1E,7              ;Clear "button-press." 

You will need to have a sub-routine that looks at 1E and tests bit 0 and bit 1 to see which button has been pressed. 
Suppose you had a red LED on line GP1 and a green LED on GP0. We will call the sub-routine Red/Green (RdGn). It detects the buttons and puts a pulse on to either GP0 or GP1. 
Go through the program and see which LED will illuminate for button A. 

In the Main routine you will need to call the sub-routine: 

                  CALL RdGn 

Before Main, place the sub-routine: 

RdGn           BTFSC 1E,0          ;Test bit0 to see if button A 
                   GOTO RdGn1        ;Button A pushed 
                   BTFSC 1E,1          ;Test bit1 to see if button B 
                   GOTO RdGn2        ;Button B pushed 
                   RETURN                ;No buttons pushed 
RdGn1         BSF 06,0               ;Turn on LED 
                   BCF 1E,0              ;Clear "button-press" flag bit0 
                   GOTO Dlay            ; 
RdGn2         BSF 06,1               ;Turn on LED 
                   BCF 1E,1               ;Clear "button-press" flag bit1
                   GOTO Dlay             ; 
Dlay            DECFSZ 1A,1         ;Delay routine FF x FF 
                  GOTO Dlay              ; cycles. 
                  DECFSZ 1B,1          ; 
                  GOTO Dlay              ; 

This routine only turns on one of the LEDs. You will need further instructions to turn the LED off.