# Using 16f690 pic / interfasing key pad and 2 x 7 segment displays , problem

#### Cristian Cox

Joined May 13, 2017
18
, good afternoon.

I need some help please or ideas.

The code below Works well for 1 7 segment display. I press the number in the key pad and the number is shown without problem.

I am adding a second 7 segment display, and the idea is to control both (multiplexing port C) with 2 transistors (see below)
I have not implemented yet the circuit since I want to have a clear idea how the software should work for the multiplexing and graving the right binary patern to light each display.

In general the code for displaying just one digit, works scanning the keypad, then looking in a table the patern of the leds in the display that need to be turned on.

I dont have a problem to turn on the right transistor, for each display in a secuence, for example if we want to display number 17.

My problem is that W (accumulator) is all the time with a value (even if the key pad was not pushed).

for example, if I want to write the number 17

I think that ideally I would like to pass this number to 2 registers, one for 1 and one for 7.
and from there I could créate a loop with the transistors (on or off according to what display wants to be shown) for showing the information of port C either with the value for 1 or for 7.

The problem is that I have all the time W with a value that repeats on time (since it is a loop), since for example I press 1, the value is shown in the display, but after I reléase the button, the value in W still there, so I dont know how to diferentiate when a real new value is coming, to put it in the other display and turn the right transistor.

If you have a better way how to display a 2 digit number using one port and 2 transistors I would apreciate if you can help me.

regards

Cristian Cox

The following code is made for just one 7 segment display (for 2 x7 segment display should be modified)

Code:
;17/05/2018
;
;
;
#include <p16F690.inc>
__config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)

PC equ h'02'                    ;    The program counter will be refered to as PC - The program counter is
;    a little counter within the microcontroller to let itself know what line number
;    it is upto when running a program. We can make the microcontroller jump to a certain
;    line number by changing the value stored in PC. (we will do this in a later tutorial)

cblock h'20'            ;    Within this cblock and endc, we can define our variables. More info on this, later.
delay_1                        ;    set aside 1 byte for a variable called delay_1
delay_2                        ;    set aside 1 byte for a variable called delay_1
what_button                    ;    this variable is used in identifying which button we have pressed.
conmutador                                      ;       variable que contiene direccion de primer y segundo diplay
endc                        ;    that's the end of defining our variables

;

org h'0000'                        ;    This line just tells the microcontroller what address to start running our program from.
;    It will always be 0000 hex for all the tutorials.
bsf STATUS, RP1
bcf STATUS, RP0

clrf ANSEL                                     ; I/o
clrf ANSELH

clrf CM1CON0
clrf CM2CON0

bcf STATUS, RP1
bcf STATUS, RP0

bsf STATUS, RP0             ;    select bank 1 (to enable us to change the Input / Output status of our ports)
movlw b'11000000'             ;    set PORTB all outputs (A '0' means output, A '1' means input. We can set each (se cambio bit 7 a input)
movwf TRISB                    ;    We can set each bit individualy. Each port having 8-bits or 8 pins.
movlw b'00000000'
movwf TRISC
movlw b'00011000'             ;    set PORTA pins 0, 1, and 2 outputs (col1 col2 col3). pins 3 raw1, 4 raw2, 5 raw3, 6 raw4 (RB7) and 7 inputs
movwf TRISA                 ;    remember PORTA pin 5 cannot be an input.
bcf STATUS, RP0             ;    select bank 0

goto setup                    ;    Now skip straight to setup.

digit_data                    ;    This routine holds all the data for our various digits.
movf what_button, w            ;    before we get here, the what_button variable will contain
;    a certain number that we copy into the w register.
addwf PC                    ;    We then add this number to our program counter which will jump
;    us straight to a certain retlw statement which will correspond
;    to the number that we pressed on the keypad.
retlw b'11000000'            ;    this is the data for the number 0
retlw b'11110011'            ;    this is the data for the number 1
retlw b'10100100'            ;    this is the data for the number 2
retlw b'10100001'            ;    this is the data for the number 3
retlw b'10010011'            ;    this is the data for the number 4
retlw b'10001001'            ;    this is the data for the number 5
retlw b'10001000'            ;    this is the data for the number 6
retlw b'11100011'            ;    this is the data for the number 7
retlw b'10000000'            ;    this is the data for the number 8
retlw b'10000001'            ;    this is the data for the number 9
retlw b'11010010'            ;    this is the data for *
retlw b'10101101'            ;    this is the data for #

setup                            ;    I always have a title labeled 'setup' this is where we set everything up
clrf what_button        ;    this ensures that we will display '0' on the display at startup
clrf PORTA
clrf PORTB                          ;    we are not scanning for any keypresses yet, so make PORTA all zero's
bcf PORTA, 0            ;    turn OFF the first display (by disconnecting +5v from the anodes)
bcf PORTA, 1            ;    turn OFF the second display (by disconnecting +5v from the anodes)

begin                            ;    and here is our main program
call display_digit            ;    call the display_digit routine and then return
goto begin                    ;    go back to the beginning and do it all again.

check_keypad                ;    This routine will scan the keypad for any key presses.

movf what_button, w        ;    we want to copy our last digit that was pressed into w
;    so just in case we DON'T press a key in this keypad scan
;    because at the end of this sub-routine, we will automatically
;    w back into what_button variable. This ensures that we keep the
;    last digit pressed on the display.

bsf PORTA, RA0            ;    lets scan the first column of keys
btfsc PORTA, RA3            ;    has the 1 key been pressed? if yes then
movlw d'01'                ;    copy decimal number 01 into w. but if not then continue on.
btfsc PORTA, RA4            ;    has the 4 key been pressed? if yes then
movlw d'04'                ;    copy decimal number 04 into w. but if not then continue on.
btfsc PORTB, RB7            ;    has the 7 key been pressed? if yes then
movlw d'07'                ;    copy decimal number 07 into w. but if not then continue on.
btfsc PORTB, RB6            ;    has the * key been pressed? if yes then, aqui se cambio portA por port B
movlw d'10'                ;    copy decimal number 10 into w. but if not then continue on.
bcf PORTA, RA0            ;    now we have finished scanning the first column of keys

bsf PORTA, RA1            ;    lets scan the middle column of keys
btfsc PORTA, RA3            ;    has the 2 key been pressed? if yes then
movlw d'02'                ;    copy decimal number 02 into w. but if not then continue on.
btfsc PORTA, RA4            ;    has the 5 key been pressed? if yes then
movlw d'05'                ;    copy decimal number 05 into w. but if not then continue on.
btfsc PORTB, RB7            ;    has the 8 key been pressed? if yes then
movlw d'08'                ;    copy decimal number 08 into w. but if not then continue on.
btfsc PORTB, RB6            ;    has the 0 key been pressed? if yes then
movlw d'00'                ;    copy decimal number 00 into w. but if not then continue on.
bcf PORTA, RA1            ;    now we have finished scanning the middle column of keys

bsf PORTA, RA2            ;    lets scan the last column of keys
btfsc PORTA, RA3            ;    has the 3 key been pressed? if yes then
movlw d'03'                ;    copy decimal number 03 into w. but if not then continue on.
btfsc PORTA, RA4            ;    has the 6 key been pressed? if yes then
movlw d'06'                ;    copy decimal number 06 into w. but if not then continue on.
btfsc PORTB, RB7            ;    has the 9 key been pressed? if yes then
movlw d'09'                ;    copy decimal number 09 into w. but if not then continue on.
btfsc PORTB, RB6            ;    has the # key been pressed? if yes then
movlw d'11'                ;    copy decimal number 11 into w. but if not then continue on.
bcf PORTA, RA2            ;    now we have finished scanning the last column of keys

movwf what_button        ;    When we get here, we will have a certain number in our w register,
;    we then copy it from w into what_button so we can use it to jump
;    to a certain retlw instruction to grab the relevant data to display
;    the digit that we pressed.

display_digit                    ;    This sub-routine will show the digit on the display
call digit_data                ;    call digit_data to grab our relevent 8-bits of info
;    for whatever button we had pressed.
movwf PORTC                    ;    and move this 8-bits of data to PORTC for display on the display

delay                            ;    here is a nice and simple delay routine
movlw d'255'                ;    copy the maximum number to our working register (decimal 255)
movwf delay_1                ;    and now copy it from the w register to delay_1 and delay_2
movwf delay_2                ;    Now the rest of the routine will focus on counting down to zero.
delay_loop                        ;    We come back to this label when we have not yet reached zero.
decfsz delay_1, f            ;    decrement whatever is in delay_1 by 1 and store the answer back in delay_1
goto delay_loop            ;    if the answer is not zero, then go back to the delay_loop label. but if the
decfsz delay_2, f            ;    answer is zero then decrement delay_2 by one and store the answer in delay_2
goto delay_loop            ;    if the answer is not zero, then go back to delay_loop label. but if the answer
return                        ;    is zero, then we have completed our delay and now we can return to our main program!

end                            ;    We always need to have end at the end, even if we don't want the program
;    to actually end, it still must be here!

#### Attachments

• 8.2 KB Views: 3

#### jpanhalt

Joined Jan 18, 2008
7,893
The problem is that I have all the time W with a value that repeats on time (since it is a loop), since for example I press 1, the value is shown in the display, but after I reléase the button, the value in W still there, so I dont know how to diferentiate when a real new value is coming, to put it in the other display and turn the right transistor.
I have not gone though your entire code nor tried to simulate it. But, using just your statement of the problem, you are trying to base a response on a previous response/result . For example, where did the value in WREG come from, was it a ones or a tens? One way is to set a flag, e.g., flag0,0 clear = ones , flag0,0 set = tens source. I do not like doing that, but it works. Another way is to write loops and calls. Thus, when in the ones loop, a call to putchar routine with "chip select" low (done in the loop), the ones are turned on. When in the tens loop, a call to the same putchar routine with with a "chip select" bit high lights the tens digit. If your call involves less than an 8-bit register (as ascii characters do), then your chip select can be part of what you send to your "putchar" routine. It is just like a flag, but without the extra register.

I do not think you want to "erase" WREG. There is no such thing.

#### Cristian Cox

Joined May 13, 2017
18
I have not gone though your entire code nor tried to simulate it. But, using just your statement of the problem, you are trying to base a response on a previous response/result . For example, where did the value in WREG come from, was it a ones or a tens? One way is to set a flag, e.g., flag0,0 clear = ones , flag0,0 set = tens source. I do not like doing that, but it works. Another way is to write loops and calls. Thus, when in the ones loop, a call to putchar routine with "chip select" low (done in the loop), the ones are turned on. When in the tens loop, a call to the same putchar routine with with a "chip select" bit high lights the tens digit. If your call involves less than an 8-bit register (as ascii characters do), then your chip select can be part of what you send to your "putchar" routine. It is just like a flag, but without the extra register.

I do not think you want to "erase" WREG. There is no such thing.

Thanks for the info, I Will check it