Talking Electronics PIC Theory

LIBRARY
OF
ROUTINES
Button - Carry


FIVE BUTTONS ON A SINGLE INPUT LINE 
If you want to use more than one button on the '508A, you will need to use this routine. It allows up to five buttons on a single line. It works by charging the capacitor C1 via the 1k resistors then GP0 goes to "input" and looks to see if the capacitor has discharged to a value that the input line considers to be a LOW. 

The input line puts a very small load on the capacitor and it takes time to discharge. When no buttons are pressed the capacitor takes the longest time to discharge and when button 5 (Sw5) is pressed 
it takes the shortest time. After charging the capacitor the micro looks at the input then goes away and executes a short delay and at the same time increments a "count file". 

When a LOW is detected, the count file is compared to values in files 14h (no buttons), 15h (button 1), 16h (button 2), 17h (button 3), 18h (button 4), and 19h (button 5). The closest value determines the 
button number and a table will instruct the micro where to go. 
During start-up the program asks you to set the value for each of the switches. These values are then placed into files 15h, 16h, 17h, 18h, and 19h. 

There are two separate routines for "5 BUTTONS." The first is called But_Valu. It resides in start-up and is executed before Main. It automatically works out the value for each button and is only executed the very first time the micro is turned on. 
The second routine is But1to5. It is called from Main and reads the five buttons. A table at the end of the routine tells the micro where to go. 

But_Valu 
Button Value resides in the start-up routine, before Main. At address 000 type: 

                    CALL But_Valu 
                    GOTO Main 

The But_Valu routine can be placed anywhere in memory, but it's best to locate it before Main as this is where all the sub-routines are placed. 
Button_Valu outputs a HIGH to a LED on GP1 for 1 second and if buttons 1, 2, 3, 4 and 5 are pressed, it places a button value in files 15h, 16h, 17h, 18h, and 19h. 
If no button is detected, it outputs another high for 1 second and goes to Main. 

But_Valu    CLRF 1E          ;Clear "button-press" file 
                 CLRF 1F          ;Carries button value to file 
                 CALL BtnVal    ;Disregard 1st result 
                 CALL BtnVal 
                 MOVF 1F,1      ;Move 1F to W. Move 
                 MOVWF 14h    ; "no buttons" count to 14h 
                 CALL BtnVal 
                 MOVLW 05      ;5 loops to match 3rd input 
                 MOVWF 1A     ; with 2nd input 
                 MOVF 14h,0     ; 
                 DECF 1F,1       ; 
                 DECF 1F,1 
BV1           XORWF 1F,0    ;Compare 1F with 14h 
                 BTFSS 03,2      ;Look at Zero flag 
                 GOTO BV5       ;Match. Value has stabilized 
                 DECFSZ 1A,1   ;Dec the loop file 
                 GOTO BV2       ;No Match - go to Main 
                 INCF 1F,1         ; 
                 GOTO BV1       ;Try again 


BV5          MOVLW 00       ;Load W with 000 0000 
                TRIS 06             ;Make GP0 output 
                BSF 06,1          ;Make GP1 HIGH 
                MOVLW 08       ;Put 8 into 1C for 1 sec 
                MOVWF 1C      ; turn-on for LED 
                CALL Delay      ;1 sec delay 
                BCF 06,1         ;Make GP1 LOW 
                CALL BtnVal    ;Disregard 1st result 
                CALL BtnVal 
                MOVF 1F,0      ;Move 1F to W. 
                MOVWF 15h    ; Move "button 1" to 15h 
                DECF 1F,1 
                DECF 1F,1 
                MOVLW 05      ;5 loops 
                MOVWF 1A     ;1A is the loop counter 
                MOVF 14h,0    ;Move "no buttons" into W 
BV3          XORWF 1F,0   ;Compare 1F with 14h 
                BTFSS 03,2     ;Look at Zero flag 
                GOTO BV2      ;Match. Same as no buttons 
                DECFSZ 1A,1  ; 
                GOTO BV3      ;No match, try again 
                CALL But_On 
                CALL BtnVal    ;Disregard 1st result 
                CALL BtnVal 
                MOVF 1F,0      ;Move 1F to W. 
                MOVWF 15h    ; Move "button 2" to 16h 
                CALL But_Off   ; Wait for button release 
                CALL But_On 
                CALL BtnVal     ;Disregard 1st result 
                CALL BtnVal 
                MOVF 1F,0      ;Move 1F to W. 
                MOVWF 15h    ; Move "button 3" to 17h 
                CALL But_Off   ; Wait for button release 
                CALL But_On 
                CALL BtnVal    ;Disregard 1st result 
                CALL BtnVal 
                MOVF 1F,0      ;Move 1F to W. 
                MOVWF 15h    ; Move "button 4" to 18h 
                CALL But_Off   ; Wait for button release 
                CALL But_On 
                CALL BtnVal    ;Disregard 1st result 
                CALL BtnVal 
                MOVF 1F,0      ;Move 1F to W. 
                MOVWF 15h    ; Move "button 5" to 19h 
                GOTO Main 

BV2          MOVLW 12h    ;Put 12h into 1C for 1.5 sec 
                MOVWF 1C     ; turn-on for LED 
                CALL Delay      ; 
                GOTO Main     ;No button pushed 

Delay        MOVLW 01 
                MOVWF 1A 
                DECFSZ 1A,1 
                GOTO Delay 
                DECFSZ 1B,1 
                GOTO Delay 
                DECFSZ 1C,1 
                GOTO Delay 
                RETURN 

BtnVal      MOVLW 00      ;Load W with 00 
                TRIS 06           ;Make all output 
                BSF 06,0         ;Make GP0 HIGH 
                MOVLW FF     ;Delay to charge cap 
                MOVWF 1A 
DS2          DECFSZ 1A,1 
                GOTO DS2 
                BCF 06,0         ;Make GP0 LOW 
DV1          MOVLW 01     ;Load W with 000 0001 
                TRIS 06           ;Make GP0 input 
                BTFSS 06,0     ;Test GP0 
                RETURN          ;Input LOW, end counting! 
                INCF 1F,1        ;Input HIGH, Inc count file 
                MOVLW 4F      ;Look to see when Cap 
                MOVWF 1A      ; is LOW after a delay 
DV2          DECFSZ 1A,1 
                GOTO DV2 
                GOTO DV1 

But_Off 
BV8          CALL BtnVal 
                MOVLW 05      ;5 loops to match input 
                MOVWF 1A      ; with "no buttons" 
                DECF 1F,1       ; 
                DECF 1F,1 
                MOVF 14h,0     ;Move 14h to W 
BV6          XORWF 1F,0    ;Compare 1F with 14h 
                BTFSS 03,2      ;Look at Zero flag 
                RETURN           ;Button released = 14h 
                INCF 1F,1 
                DECFSZ 1A,1    ;Dec the loop file 
                GOTO BV6        ;Try again 
                GOTO BV8        ;wait for button release 

But_On 
BV7          CALL BtnVal 
                MOVLW 05      ;5 loops to match input 
                MOVWF 1A     ; with "no buttons" 
                DECF 1F,1       ; 
                DECF 1F,1 
                MOVF 14h,0    ;Move 14h to W 
BV9          XORWF 1F,0   ;Compare 1F with 14h 
                BTFSC 03,2     ;Look at Zero flag 
                RETURN          ;Button ON 
                INCF 1F,1 
                DECFSZ 1A,1  ;Dec the loop file 
                GOTO BV9      ;Try again 
                GOTO BV7      ;wait for button ON 


The button-detection sub-routine is called But1to5. It is placed in the main routine thus: 

Main              CALL But1to5 

A Table at the end of But1to5 contains a list of five functions. You will need to write a sub-routine for each function depending on what you want each button to do. At the end of each function sub-routine 
you must include RETURN. 

But1to5      CALL But_On   ; 
                 CALL BtnVal    ; 
                 MOVF 1F,0      ;Move 1F to W 
                 MOVWF 1B     ;Move W to 1B 
                 MOVF 15h,0    ;Move 15h to W 
                 MOVWF 1C     ;Move W to 1C 
                 CALL Btn 
                  MOVF 1F,0     ;Move 1F to W 
                 MOVWF 1B     ;Move W to 1B 
                 MOVF 16h,0    ;Move 16h to W 
                 MOVWF 1C     ;Move W to 1C 
                 CALL Btn 
                 MOVF 1F,0      ;Move 1F to W 
                 MOVWF 1B     ;Move W to 1B 
                 MOVF 17h,0    ;Move 17h to W 
                 MOVWF 1C     ;Move W to 1C 
                 CALL Btn 
                 MOVF 1F,0      ;Move 1F to W 
                 MOVWF 1B     ;Move W to 1B 
                 MOVF 18h,0    ;Move 18h to W 
                 MOVWF 1C     ;Move W to 1C 
                 CALL Btn 
                 MOVF 1F,0      ;Move 1F to W 
                 MOVWF 1B     ;Move W to 1B 
                 MOVF 19h,0    ;Move 19h to W 
                 MOVWF 1C     ;Move W to 1C 
                 CALL Btn 
                 RETURN 

Btn            MOVLW 05     ;5 loops to match input 
                 MOVWF 1A    ; with "no buttons" 
                 DECF 1B,1     ; 
                 DECF 1B,1 
                 MOVF 1Ch,0   ;Move 1C to W 
                 XORWF 1B,0   ;Compare 1F with 15h 
                 BTFSS 03,2    ;Look at Zero flag 
                 GOTO Table    ;Button Match 
                 INCF 1B,1 
                 DECFSZ 1A,1 ;Dec the loop file 
                 GOTO Btn      ;Try again 
                 RETURN 

Table         MOVF 1A,0     ;Copy file 1A into W 
                 ADDWF 02,1   ;Add W to Program Counter 
                 GOTO Function5 
                 GOTO Function4 
                 GOTO Function3 
                 GOTO Function2 
                 GOTO Function1 

Because loading the values of buttons 1 to 5 into files 15h to 19h is an automatic process, you need to provide a lot of programming steps to make sure it is done without the aid of human intervention. 
That's why the program is so long. 

"5 BUTTONS" starts in the set-up routine by calling But_Valu. 

Button value automatically works out the value for the 5 buttons by secretly working out the value of the resistance ladder when no buttons are pressed. It does this first then turns on a LED for 1 second to tell the operator to press buttons 1 to 5. It already knows the value of resistance for "no buttons" and waits until a button is pressed. 

BUTTON DEBOUNCE 
- see Switch Debounce 

BYTE 
A group of 8 bits representing the range 0 to 255 decimal. A file 
holds 8 bits of information and is equal to 00 to FF in hex. (00 to 
255 in decimal) 

CALCULATED PROGRAM JUMPS
It is possible to write to the Program Counter to cause a "page jump." This is not necessary with the '508A as it contains only one page (000 to 1FF) bytes of program. 

The '509A contains two pages (000 to 3FF) and to jump into page two (200h to 3FF) bit5 of the Status register (address 03h) must be SET (1). 

Thus BSF 03,5 will create a program jump to page 2. 

The Program Counter is also modified when jumping to a value in a table. The instruction to modify the PC is ADDWF 02,1 where the value in W is added to the Program Counter (file 02) and destination designator (1) indicates the result is to be placed in the file. 

CALL 
CALL means to branch to, and return from a subroutine. It does NOT mean GOTO. GOTO means to branch unconditionally and maybe not return to the present routine. CALL means to branch to another sub-routine and RETURN to the next address. Every CALL must have its own RETURN statement. See PSEUDO'508A for more details. 
The CALL instruction for the 508A only takes you to the first 0FFh locations in memory. 
Thus all sub-routines you want to call must be in the first half of memory (also called the first page or page0). 
This is very messy but is the only major limitation of the 508A. 
The sub-routine being called can go over the page-boundary, providing it starts within the first 0FFh bytes of memory. 
If you want to access a sub-routine (such as Del1) in page1 (the lower half of memory), the following is an example: 

At address 000 place Set-Up followed by the label XX: 

The micro starts at address 000, carries out the setUp instructions, then GOTO Main. At Main it executes CALL XX and this label must be in page0. The instruction at label XX is GOTO Del1. Del1 can be ANYWHERE in memory as the GOTO instruction reaches all memory locations. The micro executes the delay sub-routine and returns with 00h in W to the instruction after CALL XX. The instruction CALL Table1 will work if table1 is in page0 as the CALL instruction only goes to page0. 

The 508A has only a 2-stack. This means only 2 embedded CALLs can made. 
Here is an example of a 3-call program. It will not work, so other arrangements have to be made: 

The program will execute "CALL GetChar" and at GetChar the "CALL Valu" instruction will make the micro go to "Valu" sub-routne. At "Valu" sub-routine the CALL Delay1 instruction will be executed. The micro will return to the instruction after CALL Delay and then back to CALL Value +1 but the address for CALL GetChar+1 will not be available from the stack. 
The answer is to incorporate Delay1 in the "Valu" sub-routine. If Delay1 is called only ONCE from "Valu" routine you can use GOTO Delay1 and at the end of Delay1 use GOTO Valu2. 

CARRY 
The carry flag is located in the STATUS file (03) bit0. 
It is cleared by the instruction: 
                BCF 03,0 

It is set by the instruction: 
                BSF 03,0