PIC1684A Assembly with keypad and interrupt
PIC1684A Assembly with keypad and interrupt
I am currently writing an assembly code that will count down a
BCD counter (through the 7-segment display). When a key is pressed, the counter will be overridden by the key pad value then the count down continues. For example if the current counter value is ‘8’ then overridden by pressing key 5, the counter sets to ‘5’ then counts down. The counter counts down perpetually and will be overridden anytime a key is pressed on the keypad.
Here is my circuit
And here is the code i've currently written:
COUNT EQU 0CH
ORG 000H ; reset vector
GOTO MAIN ; jump to label main during reset or startup
ORG 004H ; interrupt vector
GOTO INT_RTN ; jump to label INT_RTN or the interrupt service routine
;set up
MAIN BSF STATUS, RP0
CLRF TRISA
MOVLW 0F1H
MOVWF TRISB
MOVLW 0DH
MOVWF OPTION_REG
BCF STATUS, RP0
BSF OPTION_REG, 6 ; interrupt event during rising edge
BCF INTCON, INTF ; clear the RB0/INT interrupt flag
BSF INTCON, INTE ; unmask (enable) RB0/INT interrupt source
BSF INTCON, GIE ; enable all unmasked interrupt
GOTO START
;Interrupt-----------------------------------------------------------
INT_RTN BCF INTCON, GIE ; disable all unmasked interrupt to prevent interrupt overriding
BTFSS INTCON, INTF ; check the RB0/INT interrupt flag is ‘1’ (interrupt source from RB0/INT)
GOTO EXIT ; exit ISR if not RB0/INT interrupt
;interrupt code
CLRW
BTFSC PORTB, 4
ADDLW 01H
BTFSC PORTB, 5
ADDLW 02H
BTFSC PORTB, 6
ADDLW 04H
BTFSC PORTB, 7
ADDLW 08H
CALL KEY_VAL ; call the array KEY_VAL
MOVWF COUNT
INCF COUNT
BCF INTCON, INTF
BSF INTCON, GIE
GOTO CDOWN
EXIT BSF INTCON, GIE ; enable all unmasked interrupt
RETFIE ; return from interrupt routine
;Program Start--------------------------------------------------------------------------------------------
START MOVLW 0AH
MOVWF COUNT
MOVLW 09H
CDOWN MOVWF PORTA
SLEEP
DECFSZ COUNT, 1
GOTO DOWN
GOTO START
DOWN DECF PORTA, 0
GOTO CDOWN
;End of Start-----------------------------------------------------------
KEY_VAL ADDWF PCL, F
RETLW 01H ; returns 01H for key 1 (addr 00H)
RETLW 02H ; returns 02H for key 2 (addr 01H)
RETLW 03H ; returns 03H for key 3 (addr 02H)
RETLW 00H ; returns 00H for key A (addr 03H)
RETLW 04H ; returns 04H for key 4 (addr 04H)
RETLW 05H ; returns 05H for key 5 (addr 05H)
RETLW 06H ; returns 06H for key 6 (addr 06H)
RETLW 00H ; returns 00H for key B (addr 07H)
RETLW 07H ; returns 07H for key 7 (addr 08H)
RETLW 08H ; returns 08H for key 8 (addr 09H)
RETLW 09H ; returns 09H for key 9 (addr 0AH)
RETLW 00H ; returns 00H for key C (addr 0BH)
RETLW 00H ; returns 00H for key * (addr 0CH)
RETLW 00H ; returns 00H for key 0 (addr 0DH)
RETLW 00H ; returns 00H for key # (addr 0EH)
RETLW 00H ; returns 00H for key D (addr 0FH)
END
So naturally the bcd counts down, and when a button is pressed the interrupt occurs, reads the input in RB4 - RB7 finds the data in the address given in KEY_VAL and loads it to PORTA
However, my problem is, When i press a button in the keypad and the interrupt is started. When i read, pin RB4-RB7 to get the address given by the IC. All i get is all high so i always get 15 (address for D).
If i dont press a button, pin A B C D of MM74c922 is naturally high and when a button is pressed in the keypad, pin 12 of the ic turns high and the address is sent to rb4-7. The problem is i think the pic controller cannot read the shift in rb4-7 and so it always reads the data before the interrupt which is always high so i cant get the address i want.
I tried setting the interrupt to toggle during falling edge but the same thing occurs im out of ideas and i need help
if it helps this is the address for the buttons
Address: 00H 01H 02H 03H 04H 05H 06H 07H 08H 09H 0AH 0BH 0CH 0DH 0EH 0FH
Key: 1 2 3 A 4 5 6 B 7 8 9 C * 0 # D
I tried changing ckbm to 10uF following the equation ckbm=10*cos(c). I also check the outputs with a scope and since my interrupt was set into rising edge I looked at the first rising edge of the scope and saw that the DA rises first then the outputs. However it looks like in my case it would be better if the outputs trigger first then DA. I only used the simulators Osci, so i cant really get very accurate readings
– JezT
Jul 1 at 8:10
i tried connecting one output pin to interrupt and viola it works! problem is since i connected the 1st bit of the output only outputs that uses the lsb works but now i know its not a code problem but a hardware one. Perhaps I can alter my code to compensate for the difference in the late output since i cant change my circuit for it is a requirement that the circuit stays the same. since our professor did it. also i was mistaken in the capacitor part ckbm should be 0.1uf and c is 0.01uf
– JezT
Jul 1 at 8:31
By the way, in your interrupt routine missing "Context Saving" part! Check datasheet 6.9 "Context Saving During Interrupts".
– GJ.
Jul 1 at 9:27
3 Answers
3
Your Interruptroutine looks a little bit crazy. Try someting like:
; Save Data Space
Bank_shr udata_shr 0x70
W_safe RES 1
S_safe RES 1
.....
;Interrupt-----------------------------------------------------------
INT_RTN
MOVWF W_safe
SWAPF STATUS, W
BCF STATUS, RP0
MOVWF s_safe
Interrupt_code
.......
Interrupt_End
SWAPF s_safe, w
MOVWF STATUS
SWAPF w_safe, F
SWAPF w_safe, w
RETFIE ;GIE will set automatically
Please have a look for more details in the datasheet, there are some examples
Returning from a interrupt with GOTO isnt wise man. When u get in the interrupt it send the location where it was to stack and when u return with goto PC doesnt use that lvl of stack and direcly jump to GOTO marked Label.
Can u try
RETFIE
RETFIE
instead of
BCF INTCON, INTF
BSF INTCON, GIE
GOTO CDOWN
let me know if there is any change
I did and still it yields the same result. However i have found the answer, instead of adding the values in each bit. I used swap and got the values on the high nibble and sent it to wreg and used refie. Now the system works :)
– JezT
Jul 3 at 10:13
So apparently I found the answer and it was very simple, I edited option reg in bank 0 making the interrupt start at the falling edge useless.
The fix was
MAIN BSF STATUS, RP0
CLRF TRISA
MOVLW 0F1H
MOVWF TRISB
MOVLW 0DH
MOVWF OPTION_REG
BSF OPTION_REG, 6 --move this line here-- ; interrupt event during rising edge
BCF STATUS, RP0
BCF INTCON, INTF ; clear the RB0/INT interrupt flag
BSF INTCON, INTE ; unmask (enable) RB0/INT interrupt source
BSF INTCON, GIE ; enable all unmasked interrupt
GOTO START
now the code works, thank you all for helping me
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
From the datasheet, I see that they suggest to choose Ckbm = 10 * Cosc (section "Typical applications" in web.mit.edu/6.115/www/document/d74c922.pdf, page 7 and 8). However you dimension them as Ckbm = Cosc = 0.1µF. Which yields Fscan = 600Hz and a debounce time of only 1ms, which is shorter than the cycle time of Fscan. In my understanding the debounce time should be much longer than the scan time. Did you check the output of the 74C922 with a scope / logic analyzer?
– Adrian W
Jun 30 at 18:45