Using Interrupts to scan Keypad
Moderator: Benj
- Eric Brouwer
- Posts: 20
- Joined: Sat Oct 30, 2010 10:17 am
- Has thanked: 3 times
- Been thanked: 11 times
Using Interrupts to scan Keypad
Setting up a keypad in Flowcode with interrupts.
Using interrupts to determine if a key was pressed, frees up the PIC to continue with normal operation, without the need to periodically scan for key
presses. The attached Flowcode sample makes use of the PORTB interrupt, which will automatically jump to the Keypad interrupt routine to determine which key was pressed.
Create CUSTOM interrupt, with the follwing code:
CUSTOM INTERRUPT NAME: Keypad
ENABLE CODE:
portb = 0b00001110;
trisb = 0b11110001;
intcon.RBIE = 1;
intcon2.RBIP = 1;
intcon2.RBPU = 1;
rcon.IPEN = 0;
DISABLE CODE:
intcon.RBIE = 0;
HANDLER CODE:
if (intcon & (1 << RBIF))
{
FCM_%n();
portb = 0b00001110;
trisb = 0b11110001;
wreg= portb;
clear_bit(intcon, RBIF);
}
Overview.
+++++++++
With the standard Flowcode Keypad, the ROWS are set up as inputs, and connected to pull-down resistors (10K) to 0V. Columns are connected to output pins,
which must be 5V. Pressing a button, will result in the key placing 5V to the corresponding input pin.
On most PICs, the standard PORTB Interrupt uses PORTB.7..4 as inputs, generating the interrupt flag PBIF when the status on PORTB.7..4 changes. If we then
connect the keypad ROWS to PORTB.7..4, we can use the PORTB interrupt to determine if a key was pressed.
Below is the explanation of each command.
ENABLE CODE:
++++++++++++
portb = 0b00001110; //Set outputs of PORTB.3..1 to 1.
trisb = 0b11110001; //This sets up the IO direction, PORTB,7.4 as inputs, PORTB,3..1 as outputs, PORTB.0 to be set up us per user requirements.
intcon.RBIE = 1; //Enable PORTB interrupts, by setting RBIF in register intcon.
intcon2.RBIP = 1; //On some chips, set up the interrupt priority of PORTB interrupts. Not needed on smaller chips.
intcon2.RBPU = 1; //Disable PORTB.7..4 internal weak pull-ups (Flowcode uses pull-downs).
rcon.IPEN = 0; //Disable interrupt priority on some chips. Not needed on smaller chips.
DISABLE CODE:
+++++++++++++
intcon.RBIE = 0; //Disable PORTB interrupt by clearing RBIE in register intcon.
HANDLER CODE:
+++++++++++++
if (intcon & (1 << RBIF)) //See if interrupt was due to PORTB interrupt flag.
{
FCM_%n(); //if so, call macro stated in Interrupt "Will Call Macro" field.
portb = 0b00001110; //After interrupt was handled, ensure PORTB.3..1 is set to 1 again for next scan.
trisb = 0b11110001; //Ensure correct IO direction on PORTB.
wreg= portb; //Read PORTB to reset any mismatches on PORTB, thus enabling to scan for next changes on PORTB.
clear_bit(intcon, RBIF); //Clear RBIF in intcon register, thus enabling next interrupt.
Using interrupts to determine if a key was pressed, frees up the PIC to continue with normal operation, without the need to periodically scan for key
presses. The attached Flowcode sample makes use of the PORTB interrupt, which will automatically jump to the Keypad interrupt routine to determine which key was pressed.
Create CUSTOM interrupt, with the follwing code:
CUSTOM INTERRUPT NAME: Keypad
ENABLE CODE:
portb = 0b00001110;
trisb = 0b11110001;
intcon.RBIE = 1;
intcon2.RBIP = 1;
intcon2.RBPU = 1;
rcon.IPEN = 0;
DISABLE CODE:
intcon.RBIE = 0;
HANDLER CODE:
if (intcon & (1 << RBIF))
{
FCM_%n();
portb = 0b00001110;
trisb = 0b11110001;
wreg= portb;
clear_bit(intcon, RBIF);
}
Overview.
+++++++++
With the standard Flowcode Keypad, the ROWS are set up as inputs, and connected to pull-down resistors (10K) to 0V. Columns are connected to output pins,
which must be 5V. Pressing a button, will result in the key placing 5V to the corresponding input pin.
On most PICs, the standard PORTB Interrupt uses PORTB.7..4 as inputs, generating the interrupt flag PBIF when the status on PORTB.7..4 changes. If we then
connect the keypad ROWS to PORTB.7..4, we can use the PORTB interrupt to determine if a key was pressed.
Below is the explanation of each command.
ENABLE CODE:
++++++++++++
portb = 0b00001110; //Set outputs of PORTB.3..1 to 1.
trisb = 0b11110001; //This sets up the IO direction, PORTB,7.4 as inputs, PORTB,3..1 as outputs, PORTB.0 to be set up us per user requirements.
intcon.RBIE = 1; //Enable PORTB interrupts, by setting RBIF in register intcon.
intcon2.RBIP = 1; //On some chips, set up the interrupt priority of PORTB interrupts. Not needed on smaller chips.
intcon2.RBPU = 1; //Disable PORTB.7..4 internal weak pull-ups (Flowcode uses pull-downs).
rcon.IPEN = 0; //Disable interrupt priority on some chips. Not needed on smaller chips.
DISABLE CODE:
+++++++++++++
intcon.RBIE = 0; //Disable PORTB interrupt by clearing RBIE in register intcon.
HANDLER CODE:
+++++++++++++
if (intcon & (1 << RBIF)) //See if interrupt was due to PORTB interrupt flag.
{
FCM_%n(); //if so, call macro stated in Interrupt "Will Call Macro" field.
portb = 0b00001110; //After interrupt was handled, ensure PORTB.3..1 is set to 1 again for next scan.
trisb = 0b11110001; //Ensure correct IO direction on PORTB.
wreg= portb; //Read PORTB to reset any mismatches on PORTB, thus enabling to scan for next changes on PORTB.
clear_bit(intcon, RBIF); //Clear RBIF in intcon register, thus enabling next interrupt.
- Attachments
-
- Keypad_Standard_1.fcf
- How to use interrupts to read a keypad
- (10 KiB) Downloaded 447 times
- fotios
- Posts: 458
- Joined: Mon Feb 08, 2010 10:17 am
- Location: Greece
- Has thanked: 109 times
- Been thanked: 117 times
Re: Using Interrupts to scan Keypad
I don't know if this is a general issue of Flowcode simulator, but in mine case simulator responds only in interrupts caused from Port RB.5 up to Port RB.7. In the actual project, interrupt of all pins of Port B works just fine. I have to clear up that i use a P16F887 and its IOC (Interrupt On Change state) feature of Port B. I don't know if there is a difference in interrupt handler priority between PortB IOC and the custom interrupt of this example. Is there any special reason that you don't use the Port B.4-B7 "IOC" feature of P18F4520?nmindana wrote:Hi Eric,
Your programme doesn't seem to work on simulation?.
No interrupt occurred!.
May be its's my copy of flowcode, I don't know.
Regards
Indana
Regards
Fotios
Best Regards FOTIS ANAGNOSTOU
- Steve
- Matrix Staff
- Posts: 3434
- Joined: Tue Jan 03, 2006 3:59 pm
- Has thanked: 114 times
- Been thanked: 422 times
Re: Using Interrupts to scan Keypad
Yes - this is a limitation of the simulator. It was originally written around the interrupt facilities of the 16F84 chip and similar older devices where the "PORTB change" interrupt was only available on RB4-7.
- fotios
- Posts: 458
- Joined: Mon Feb 08, 2010 10:17 am
- Location: Greece
- Has thanked: 109 times
- Been thanked: 117 times
Re: Using Interrupts to scan Keypad
I tried this flowcode example in real mode using EB006v.7 programmer, EB005 LCD board and EB014 Keypad board. The first time i used a P18F4520 (like in the original *fcf file) and the second time i used a P16F887 (both offer precision internal oscillator). In both PICs the project works just fine. Although i am used to use the ready offered "IOC" interrupt, Eric Brouwer's example code offers an insightful look on the interrupt mechanism of microcontrollers. Very didactic!
Thanks Eric!
Fotios
Thanks Eric!
Fotios
Best Regards FOTIS ANAGNOSTOU
- Eric Brouwer
- Posts: 20
- Joined: Sat Oct 30, 2010 10:17 am
- Has thanked: 3 times
- Been thanked: 11 times
Project in test phase
You are correct. The keypad does not work on the simulation, but works 100% in the project. I am working on a 8 channel timer project, which makes use of a keypad, DS1307 real time clock, custom LCD characters, C and ASM block, and I2C. Due to the eeprom and RTC being too much effort to test in the simulation, and Flowcode that does not simulate ASM or C, I am using my breadboard to test all the functions. Thus the reason that I did not spend too much time getting the keyboard with interrupts working correct in Flowcode.nmindana wrote:Hi Eric,
Your programme doesn't seem to work on simulation?.
No interrupt occurred!.
May be its's my copy of flowcode, I don't know.
Regards
Indana
The simulation is great for testing purposes, but will not give the correct response compared to real components. I2C for example, will simulate correct, even if you enter the wrong slave address. That is why I always do my development with real components.
With the project connected to a PicKit 3, it is quick to make changes in Flowcode, and compile to PIC afterwards. As i used to do all my programming in assembler, I am still struggling to use Flowcode to take full advantage of the PIC functions. Flowcode does take of days in the developing, so I really do not mind building my circuits on breadboard.
- Attachments
-
- IMGP7921.JPG (188.54 KiB) Viewed 11851 times
- Eric Brouwer
- Posts: 20
- Joined: Sat Oct 30, 2010 10:17 am
- Has thanked: 3 times
- Been thanked: 11 times
Re: Using Interrupts to scan Keypad
Hi fotiosfotios wrote: Although i am used to use the ready offered "IOC" interrupt...
I tried the "PORT" interrupt in Flowcode, but could not get it to generate an interrupt in the simulation, thus the custom interrupt. I am not sure what the IOC is you are referring to, but will look into it. I am still very new using Flowcode, and learn all the functions as I go along.
The only options I have in the Interrupts are:
TMR0
RB0/INT0
PORT
TMR1
RB1/INT1
RB2/INT2
RXINT
TMR2
I must state that I am also using RB0/INT0 for time keeping, with a 1Hz pulse from the DS1307 RTC connected to this pin. I was not too sure about the PORT interrupt, and thought it will generate an interrupt on change of any of PORTB pins. I did not want to share a single interrupt for the keypad and RTC.
The custom interrupt uses the intcon.RBIF, which only responds to changes on PORTB:7..4. This is what I used in the custom interrupt.
Any info on the IOC will be appreciated.
- Attachments
-
- 1.JPG (27.09 KiB) Viewed 11850 times
- fotios
- Posts: 458
- Joined: Mon Feb 08, 2010 10:17 am
- Location: Greece
- Has thanked: 109 times
- Been thanked: 117 times
Re: Using Interrupts to scan Keypad
Hi Eric
The term "IOC" (Interrupt On Change state) it comes from the Microchip's datasheets for PICs. It corresponds to "PORT" interrupt of Flowcode for PICs. I am also newbie in Flowcode (1 year experience) and i don't know almost nothing about the RISC code of PICs. I know few things about C, so you are far better from me in programming of PICs! For this reason i bought Flowcode, for its visual programming interface and for the plentiful help offered from Matrix tech team and the experienced members on this forum. I had no idea that you also use the "RB0/INT0" interrupt in your project. In my only and one Flowcode working project so far, i also use the RB0 interrupt caused from an IR receiver connected at Port B.0. I use a P16F887 that offers IOC on all pins of Port B, instead P18F4520 offers IOC only from RB.4 - RB.7. BTW, the only PICs that i tried so far are the P16F887 and - like you - the P18F4520 but the later just for its big program memory of 32KB. Activation of "PORT" (or IOC according to Microchip) interrupt is quite simple, like RB0/INT0 interrupt, thanks to the ready code offered from Flowcode. In my project, except the IR (infrared receiver) that i have connected in RB.0, i have also connected 6 momentary switches from RB.1 up to RB.6 of P16F887. This because i wanted the use of the "ready assembled" from Flowcode PORT (IOC) interrupt of this PIC. In P16F887, if you enable the PORT interrupt then it is applicable on all 8 pins of Port B (included RB.0/INT - P16F887 offers only this Port for an external interrupt source instead the 3 Ports offered from P18F4520), while in P18F4520 when "PORT" (IOC) interrupt is enabled it is applicable only on RB.4 to RB.7 and does not affect RB.0 to RB.3. Because the IR receiver interrupt was of big importance, i excluded the PORT interrut and i left only the RB.0 / INT. Then, i developed an extra loop inside the "MAIN" program loop and one extra macro to scan the state of the six switches. The thing works just fine in the actual project but i have spend almost a 80% from the small (8KB) program memory of P16F887!!!
Although i have no knowledge of programming languages, it does not means that i am silly! I had the sense that the arrangement of my - working - program was not the best and probably was a waste of time and program memory.
It is well known that: "One thing the knowledge of a programming language and other thing the logic required for the correct development of an application".
Then, i saw your thread about the "CUSTOM" interrupt which i think is a must for my case. At the same time, i placed a question in forum of how i can use both the "RB0/INT" and the "PORT" (IOC) interrupts. Look please here: http://www.matrixmultimedia.com/mmforum ... f=7&t=8422 where Benj suggests "masking" of Port RB.0. I have not tried it yet, but from what Benj proposes i can suppose that both interrupts could coexist. OTOH maybe you are right on this that you wrote:"I did not want to share a single interrupt for the keypad and RTC". Maybe it can translated in: "I don't like to use different interrupts caused at the same Port"??? So, i have to try both solutions. My problem is - of course - that:
1) I don't know where i can place the C-code "masking" instruction proposed by Benj
2) I should study a bit the PIC assembly so I be able to modify the instructions of your "custom" interrupt to suit in the hardware of mine project. Because i don't use a matrix keypad, i use six separate key switches.
Regards
Fotis
The term "IOC" (Interrupt On Change state) it comes from the Microchip's datasheets for PICs. It corresponds to "PORT" interrupt of Flowcode for PICs. I am also newbie in Flowcode (1 year experience) and i don't know almost nothing about the RISC code of PICs. I know few things about C, so you are far better from me in programming of PICs! For this reason i bought Flowcode, for its visual programming interface and for the plentiful help offered from Matrix tech team and the experienced members on this forum. I had no idea that you also use the "RB0/INT0" interrupt in your project. In my only and one Flowcode working project so far, i also use the RB0 interrupt caused from an IR receiver connected at Port B.0. I use a P16F887 that offers IOC on all pins of Port B, instead P18F4520 offers IOC only from RB.4 - RB.7. BTW, the only PICs that i tried so far are the P16F887 and - like you - the P18F4520 but the later just for its big program memory of 32KB. Activation of "PORT" (or IOC according to Microchip) interrupt is quite simple, like RB0/INT0 interrupt, thanks to the ready code offered from Flowcode. In my project, except the IR (infrared receiver) that i have connected in RB.0, i have also connected 6 momentary switches from RB.1 up to RB.6 of P16F887. This because i wanted the use of the "ready assembled" from Flowcode PORT (IOC) interrupt of this PIC. In P16F887, if you enable the PORT interrupt then it is applicable on all 8 pins of Port B (included RB.0/INT - P16F887 offers only this Port for an external interrupt source instead the 3 Ports offered from P18F4520), while in P18F4520 when "PORT" (IOC) interrupt is enabled it is applicable only on RB.4 to RB.7 and does not affect RB.0 to RB.3. Because the IR receiver interrupt was of big importance, i excluded the PORT interrut and i left only the RB.0 / INT. Then, i developed an extra loop inside the "MAIN" program loop and one extra macro to scan the state of the six switches. The thing works just fine in the actual project but i have spend almost a 80% from the small (8KB) program memory of P16F887!!!
It is well known that: "One thing the knowledge of a programming language and other thing the logic required for the correct development of an application".
Then, i saw your thread about the "CUSTOM" interrupt which i think is a must for my case. At the same time, i placed a question in forum of how i can use both the "RB0/INT" and the "PORT" (IOC) interrupts. Look please here: http://www.matrixmultimedia.com/mmforum ... f=7&t=8422 where Benj suggests "masking" of Port RB.0. I have not tried it yet, but from what Benj proposes i can suppose that both interrupts could coexist. OTOH maybe you are right on this that you wrote:"I did not want to share a single interrupt for the keypad and RTC". Maybe it can translated in: "I don't like to use different interrupts caused at the same Port"??? So, i have to try both solutions. My problem is - of course - that:
1) I don't know where i can place the C-code "masking" instruction proposed by Benj
2) I should study a bit the PIC assembly so I be able to modify the instructions of your "custom" interrupt to suit in the hardware of mine project. Because i don't use a matrix keypad, i use six separate key switches.
Regards
Fotis
Best Regards FOTIS ANAGNOSTOU
- Eric Brouwer
- Posts: 20
- Joined: Sat Oct 30, 2010 10:17 am
- Has thanked: 3 times
- Been thanked: 11 times
Re: Using Interrupts to scan Keypad
Hi Fotis
Thanks, I had a look again at the PORT interrupt, and it is in fact the same as the IOC you are refering to. The main reason that I have created the custom interrupt, was that the Flowcode keypad does not return all the I/O pins to the correct status to make the PORT interrupt work correct.
To be able to scan all keys, and generate an interrupt for any of the 12 keypad buttons, the following is required:
- All ROWS must be inputs (RB7..4)
- All columns must be outputs (RB3..1)
- All columns must be logic 1 (RB3..1)
After a keypad scan, Flowcode leaves the keypad pin status as follows:
- All ROWS correct as inputs (RB7..4)
- All columns correct as outputs (RB3..1)
- All columns NOT logic 1, only RB1 set to logic 1, RB2 & 3 set to logic 0. This means that only a single column of the keypad can be scanned. This is where my problem lies, and the creation of the custom interrupt. In the custom interrupt, I ensure all I/O pins are set correct.
The PIC 18F4520 IOC only work on PORTB:7..4, so in your case, I will also use RB1/INT1 and RB2/INT2 for the buttons. You will then be able to use your 6 buttons, as well as RB0/INT0 for your IR interrupt.
Hope this sample code will assist you.
Thanks for your contribution.
Thanks, I had a look again at the PORT interrupt, and it is in fact the same as the IOC you are refering to. The main reason that I have created the custom interrupt, was that the Flowcode keypad does not return all the I/O pins to the correct status to make the PORT interrupt work correct.
To be able to scan all keys, and generate an interrupt for any of the 12 keypad buttons, the following is required:
- All ROWS must be inputs (RB7..4)
- All columns must be outputs (RB3..1)
- All columns must be logic 1 (RB3..1)
After a keypad scan, Flowcode leaves the keypad pin status as follows:
- All ROWS correct as inputs (RB7..4)
- All columns correct as outputs (RB3..1)
- All columns NOT logic 1, only RB1 set to logic 1, RB2 & 3 set to logic 0. This means that only a single column of the keypad can be scanned. This is where my problem lies, and the creation of the custom interrupt. In the custom interrupt, I ensure all I/O pins are set correct.
The PIC 18F4520 IOC only work on PORTB:7..4, so in your case, I will also use RB1/INT1 and RB2/INT2 for the buttons. You will then be able to use your 6 buttons, as well as RB0/INT0 for your IR interrupt.
Hope this sample code will assist you.
Thanks for your contribution.
- Attachments
-
- Eric_RB0_RB47.fcf
- 6 Buttons & RB0 Interrupts
- (13.5 KiB) Downloaded 338 times
- fotios
- Posts: 458
- Joined: Mon Feb 08, 2010 10:17 am
- Location: Greece
- Has thanked: 109 times
- Been thanked: 117 times
Re: Using Interrupts to scan Keypad
Eric, thank you very much for your labour to write this *fcf file for me! I realy feel flattered, thank you. I can perceive the PORT interrupt problem regarding your project. You had not other way than the custom interrupt to incorporate the matrix keypad on it. In my project, a P18F4520 can resolve the problem by chance! Because its PORT (IOC) interrupt is not applicable on RB.0 when is enabled, so it can be used directly without extra work. Instead, the use of the new P16F887 (BTW is a very nice mcu) demands extra code because the surplus of PORT interrupt! It is some funny!
Anyway, today i looked again on the datasheets of both PICs. In this updated race of PICs (like F887) Microchip has included some ready modules like the internal oscillator. There is another one important module included in P16F887, the internal MCLR which eliminates the need of external RC parts to reset the mcu during start-up. This module, i think is not included in P18F4520 and i don't know if the POR (Power On Reset) can do the job of MCLR in the same way. In P16F887, when the internal MCLR is enabled, the Pin 1 can be used as general I/O port. In my project, i need any available pin of PIC as I/O, because i use it for managing of Latching type relays. Latching relays need double control lines (set - reset) compared to common type relays. My project, is addressed to manage an audio preamplifier: Stand-By, Mute, Input select, Volume control etc. I would like to upload it here, but is very complex. I have included a lot of subroutines (e.g. a Power On sequence, a mains power failure detect etc.) suitable for the correct and safe operation of device, to eliminate possible risks for the loudspeakers. I will do this, after solving the issue of interrupts.
Thanks again Eric
Fotis
Anyway, today i looked again on the datasheets of both PICs. In this updated race of PICs (like F887) Microchip has included some ready modules like the internal oscillator. There is another one important module included in P16F887, the internal MCLR which eliminates the need of external RC parts to reset the mcu during start-up. This module, i think is not included in P18F4520 and i don't know if the POR (Power On Reset) can do the job of MCLR in the same way. In P16F887, when the internal MCLR is enabled, the Pin 1 can be used as general I/O port. In my project, i need any available pin of PIC as I/O, because i use it for managing of Latching type relays. Latching relays need double control lines (set - reset) compared to common type relays. My project, is addressed to manage an audio preamplifier: Stand-By, Mute, Input select, Volume control etc. I would like to upload it here, but is very complex. I have included a lot of subroutines (e.g. a Power On sequence, a mains power failure detect etc.) suitable for the correct and safe operation of device, to eliminate possible risks for the loudspeakers. I will do this, after solving the issue of interrupts.
Thanks again Eric
Fotis
Best Regards FOTIS ANAGNOSTOU
- Eric Brouwer
- Posts: 20
- Joined: Sat Oct 30, 2010 10:17 am
- Has thanked: 3 times
- Been thanked: 11 times
Re: Using Interrupts to scan Keypad
Hi Fotis.
Sorry, but I failed to let you know that I replied to your previous topic http://www.matrixmultimedia.com/mmforum ... f=7&t=8422. I posted the code for RB0 interrupt as well as 6 button interrupts on RB1..6. The code at this link is for the 16F887.
Please let me know if it is working for you. I will be glad to assist you with the interrupts for your project.
Sorry, but I failed to let you know that I replied to your previous topic http://www.matrixmultimedia.com/mmforum ... f=7&t=8422. I posted the code for RB0 interrupt as well as 6 button interrupts on RB1..6. The code at this link is for the 16F887.
Please let me know if it is working for you. I will be glad to assist you with the interrupts for your project.
- Eric Brouwer
- Posts: 20
- Joined: Sat Oct 30, 2010 10:17 am
- Has thanked: 3 times
- Been thanked: 11 times
Re: Using Interrupts to scan Keypad
I am glad to report that I have completed my Timer project. There was still a small problem with the keypad interrupt system. In the Keypad_GetKeypadNumber custom code, the macro Delay_us(10) is called. As this is also used with some other component macros, and the Delay command, it could lead up to Stack Overflow problems. To overcome this, the Delay_us(10) command was replaced with 25 "wreg = porta; " instructions. Now the keypad GetKetpadNumber command can be used inside the keypad interrupt routine.
- Attachments
-
- Keypad Custom Code
- KEYPAD.JPG (48.43 KiB) Viewed 11701 times
- Eric Brouwer
- Posts: 20
- Joined: Sat Oct 30, 2010 10:17 am
- Has thanked: 3 times
- Been thanked: 11 times
Re: Using Interrupts to scan Keypad
In the attached code, the Keypad_GetKeypadNumber custom code was changed.
- Attachments
-
- Keypad_Interrupt.fcf
- (15.17 KiB) Downloaded 301 times