Reading Keypad MPLab Assembly - Page 1
Forum section: electronics / general

author: jpanhalt
author_rank: Super Contributor
timestamp: February 25, 2024, 03:30:36 pm
content: In a previous post I showed a nice box (https://www.eevblog.com/forum/mechanical-engineering/mitutoyo-982-537-1-dro-display-with-series-572-linear-scales/msg5287843/#msg5287843). I'd like to use that keypad now. My device of choice is an enhanced, mid-range PIC16F1xxx using MPLab Assembly 8.92.Attached are two images of how the pads are arranged according to the 9-conductor FFC numbered L to R, 1..9. There seem to be 2 sets: SetA = conductors 1..5 and SetB = 6..9, i.e., 20 combinations for 20 keys.In previous projects reading smaller keysets, I just converted the key/port pin to a number and used a jump table. I could easily do the same with four jump tables or a table of tables as described years ago by Peter Anderson at Johns Hopkins.My question: Is there a simpler, perhaps more obvious way? I am not adverse to adding a new chip that would convert the 9-inputs to a 5-bit number. If so, please recommend a multiplexer chip that can do that.EDIT: Added a single table that may be clearer.

author: jwet
author_rank: Frequent Contributor
timestamp: February 25, 2024, 08:35:41 pm
content: It depends how code starved you are. I did a lot of assembly with <2k or ROM.Here is something to try perhaps, if not smaller, might be easier to understand than just a bunch of RETLW code statements.You can observe that all the numbers are either an 8 or a 9. You could branch somewhere and decode the things. Its likely that all numbers get handled the same way so after decoding them, you'll fall through to some common code (append digit).The cursor keys are almost all 7's, you could do similar two stage decode.You'll probably find that you end up with the same size.Look up tables are pretty efficient, especially if you run them through a c compiler- good C compilers use tricks like folding, etc and can improve your logic. You can do all the same in assy.Have fun.

author: jpanhalt
author_rank: Super Contributor
timestamp: February 25, 2024, 09:24:56 pm
content: I love coding in Assembly. It's fun and relaxing. While modern PIC's have much more room, I enjoy the challenge of keeping the code tight. The instruction set for enhanced 16F PIC's was improved a little.I just worked out a bit of code to do what I want. Basically I need to convert a set PORT pin to a bit position, not binary value, to keep the table small. That doesn't take a lot of code for bits 0..3 (i.e., Set B in the revised single table). From there, it's a typical jump table.When I get something working, I will post it here. Right now, it's about time to receive Sunday calls from my children and start dinner.John

author: Benta
author_rank: Super Contributor
timestamp: February 25, 2024, 11:12:26 pm
content: Dunno why you have a problem with this.It's obviously a 4 x 5 matrix. Super easy to decode (hardware-wise).Whether you then use the result in a table or bitwise is up to you.

author: jpanhalt
author_rank: Super Contributor
timestamp: February 25, 2024, 11:27:10 pm
content: So far as I know, the PIC 16F1xxx chips do not have hardware decoding. Can you give a simple example? It's obvious how to do it with 2 ports and some firmware, and that is what my rough code does.

author: jpanhalt
author_rank: Super Contributor
timestamp: February 26, 2024, 10:23:22 pm
content: UPDATEI've fiddled with the 4x5 table and came up with this. It is untested.Code:Keyboard;Use hypothetical PORTB for the 4 switches of the 4X5 matrix;after key press, jump to ISR, and process PORTB(4) and PORTC (5);delay 40 msecs for debouncelsrf PORTB,w ;STATUS,0 has state of RB0andlw 0x07 ;PORTx > lsrf > if WREG,2 setbtfsc WREG,2 ;0001 0000 0000movlw 3 ;0010 0001 0001;0100 0010 0010;1000 0100 0011btfsc PORTC,S1bra DoS1btfsc PORTC,S2bra DoS2btfsc PORTC,S3bra DoS3btfsc PORTC,S4bra DoS4btfsc PORTC,S5bra DoS5bra Main ;exit ISR or ERR --> exit ISRDoS1brwbra ESCbra _SETbra Num0bra Num7DoS2brwbra ALMbra Rightbra Num3bra Num8DoS3brwbra Decbra ENTbra Num2bra Num9DoS4brwbra Incbra CLRbra Num1bra Num4DoS5brwbra Leftbra ChgSignbra Num6bra Num5ESC_SETALMENTCLRRightLeftIncDecChgSignNum0Num1Num2Num3Num4Num5Num6Num7Num8Num9Errnopbra Main

author: Benta
author_rank: Super Contributor
timestamp: February 26, 2024, 11:03:51 pm
content: I don't know the PIC, nor its assembly language.But the way to do it works like this (you need an input port with interrupt capability!)The ports you're using must be bidirectional.All pins from your keyboard need pull-up resistors, say, 47 kohm.Connect 5 pins to the interrupt capable input port. Connect 4 pins to another port and set the pins to output, low.If a key is pressed, the input port will issue an interrupt.Wait a moment (debouncing) and read the port and store.Reverse the ports, making the first one output, low, and make the the second port input. Read the second port and store.End the interrupt.You now have the coordinates of the pressed key in your 5 x 4 matrix.Decoding it should be trivial.

author: jpanhalt
author_rank: Super Contributor
timestamp: February 26, 2024, 11:45:24 pm
content: Thanks.The PIC16F1xxx ("Enhanced mid-range") are just 14-bit core, 8-bit MCU's, which forces quite a bit of banking and occasional paging compared to 16-bit cores, and of course real 16-bit MCU's. They have limited math, but the instruction set is easy to remember, and they have one level of interrupt. That has not been a problem for me as a hobbyist. (The 12F5xx and 16F5xx do not have interrupts.)I am pretty familiar with using that type of interrupt and will integrate it into my "Main" routine. The whole purpose of this project is to control infeed of a lathe while threading, particularly while doing female threads with a small tpi (i.e., 8 tpi). More than a decade ago, I did that with a simple dial indicator where all I monitored was to detect the change from + to -. That worked, but was clumsy. I am fitting those old Mitutoyo scales from my mill to my lathe, and they output the Mitutoyo SPC format in mm only. So, there is a lot more to entering a preset and testing when that endpoint is reached.The parts of this project are pretty much done. Now, all I have to do is glue them together. Overall, the Assembly code is pretty compact. The limits are 00.000" +/- 0.0005", with a maximum of 99 cm. The Mitutoyo scales read to 0.01 mm, but that's resolution, not accuracy.John

author: Benta
author_rank: Super Contributor
timestamp: February 26, 2024, 11:58:17 pm
content: A tip when decoding:Use shift/rotate instructions to find the right key. That will eliminate the risk of multiple keypresses falsely/out-of-range being decoded.

author: jpanhalt
author_rank: Super Contributor
timestamp: March 10, 2024, 03:26:56 pm
content: UPDATEThe algorithm was implemented on breadboard using IOC registers, but not an interrupt at this time. That made debugging a bit easier. In its final embodiment, it will be interrupt based, so the keyboard can be active most of the time.Attachments show the progress. No picture of the solderless breadboard is included as that would be an embarrassment. I switched to the PIC16F1783 to get 28 pins, all of which have IOC capability. A new LCD 192x64 with SPI capability (ST7525 controller) should be here in a few days and should be mounting-hole compatible with the existing GLCD LCD. I like that series of controller. They are fast and generally require only one CS pin.Attachments:1) Faceplate of the now repurposed device shown earlier (OP320-A/OP320-A-S)2) Keyboard pinout (Word doc)3) Schematic (Eagle)4) Breadboard wiring (Eagle)5) Code (MPLab 8.92 Assembly)EDIT: There's a typo in the 2nd attachment. A and B are reversed, Everything was developed as shown, but I had penciled in PORTB for A and visa versa. When I posted here, I changed one but not the other. I will leave it be and the error should be obvious.EDIT2: Added attachment with dimensions for SparkFun large protoboard so FFC from keypad lines up with holes in the board.

author: jpanhalt
author_rank: Super Contributor
timestamp: November 14, 2024, 02:22:07 pm
content: PERPLEXING BUGI have continued development of my Mitutoyo project. The PCB used previously was too small to accomodate parts needed for reading the scales, so I wired up another (attached image). Checked it out, plugged it in, no smoke, and it seemed to work with one big exception. RA2 read asif it was RA3. That is, pressing the SET key read as ESC and so forth. ESC (RA3) read as ESC and all the other keys mapped to RA0, RA1, and RA3 read correctly. Head scratching time.No shorts, but the watch window for IOCAF confirmed that setting any key mapped to RA2 was read as if mapped to RA3. Wiring and shorts were tested for more times than I could remember. I pulled up the last working version of the coe (10/20/24) and that worked fine. I compared code for the relevant section and found no changes that could do that. Finally, I compared the entire code, thinking that perhaps I had defined (#Define) something wrong. (All code is MPLAB 8.92 Assembly.) The only difference is that the 10/20 code was running at 8 MHz and the current revised code was at 16 MHz. NB: I usually include an option in Processor Setup for both internal oscillators.I changed the frequency to 8 MHz and bingo, it worked (see attached captures and focus on IOCAF). I tried some NOP delays in the read section, and that didn't help. I have not tested that exhaustively.I can think of some crazy hypotheses for that behavior, like cross talk or bad solder joints, but would first like to throw it out to the crowd and see what you think.John

author: macboy
author_rank: Super Contributor
timestamp: November 14, 2024, 07:50:25 pm
content: I don't see any pull up or pull down resistors on your board, and no mention of using any internal pull ups of the PIC. Are you using any? If not, then inputs not actively connected by the key currently being pressed are just floating in the breeze, and that is a problem.

author: jpanhalt
author_rank: Super Contributor
timestamp: November 14, 2024, 08:23:04 pm
content: Weak pull-ups are enabled in code for inputs (WPUA and WPUB), which is essential for the algorithm to work at all. What concerns me is the frequency dependency. If it was just too fast, then why only one row? Is there that much variance between port pins? And if that, why just RA2 going to RA3 and not something more random?Although I hate to consider it, maybe it is crappy soldering on the input to one or both pins? (I have been soldering wires for over 72 years.) If that, then why the frequency dependency? With a fresh mind (e.g., tomorrow about 1AM ET), I will play more with NOP's. I am the sort of person who simply can't accept operation at 8 MHz and not 16 MHz without understanding why. Once I know why, I will go with what works or change it to work at 16 MHz. (The GLCD screen doesn't work without delays at 32 MHz. There is no way to read the ready bit using SPI.)

author: jpanhalt
author_rank: Super Contributor
timestamp: November 15, 2024, 12:37:10 am
content: @macboyYou may be onto something. The internal pull-ups are quite weak (maybe 50k). I was going to insert nops to delay between setting PORTA as input and clearing IOCAF (P). Then my ICD3 decided to act up, and that usually takes a clear head and a lot of time to rectify. If the nop's help, then it's clearly a speed factor, and RA3 must just be enough slower to be picked up as the signal. That doesn't explain completely why it only happens with row RA2, but it's a start. If that gets to the answer, adding stronger pull-ups will be simple. Will update tomorrow, if possible.ICD3 doesn't act up that frequently, but when it does, I sometimes have to resort to removing and reloading the entire MPLab 8.92 suite. Then, I have to rollback a .jam file because of Microchip's errors in the most recent version affecting that series of chips (16F17xx).John

author: jpanhalt
author_rank: Super Contributor
timestamp: November 15, 2024, 03:17:37 am
content: @macboyI couldn't get to sleep without trying. Spent the past 3 hours getting the ICD3 working again and 5 minutes to test the code.Apparently, that was it. Added a few nop's and it runs fine now at 16 MHz. Now to try some external pull-ups to confirm that's the problem.Here's the modified code, The most of the nop's are right after I make PORTA,0..3 inputs.Code:GetRowmovlb 1 ; |B1movlw b'00011111' ; |B1xorwf TRISB ;set PORTB to output, IOC inactive for OP's |B1movlw b'00001111' ; |B1xorwf TRISA ;change PORTA to input |B1movlb 7 ; |B7;11/14/24nopnopnopnop;end 11/14/24clrf IOCBF ; |B7clrf IOCAF ;should reset only after release |B7nopbtfss INTCON,IOCIF ;wait for positive edge on release |B?bra $-1 ; |B?decf IOCAF,w ;test for valid data |B7andwf IOCAF,w ;check for 2^n |B7btfss STATUS,2 ;zero if single bit set |B7goto Err;convert bit#3 to value = 3 (see note at end for 5 bits)lsrf IOCAF,w ;STATUS,0 has state of IOCAF,0 |B7andlw 0x07 ;if RB4 was set, clears WREG,3 |B7btfsc WREG,2 ;0001 --> 0000 --> 0000 |B7movlw 3 ;0010 --> 0001 --> 0001 |B7;0100 --> 0010 --> 0010 |B7;1000 --> 0100 --> 0011 |B7movlb 0 ; |B0returnEdit: I swapped ports about 2 weeks ago and forget to change the comments The code was correct and comments are now correct.

author: jpanhalt
author_rank: Super Contributor
timestamp: November 15, 2024, 02:09:33 pm
content: Same set up and tested how many NOP's were needed. Only one NOP (250ns) right after setting TRISA,0..3 was needed. Removed all five NOP's and error came back. Added a 22k pull-up to RA3, error disappeared. Added 22k pull-up only to RA2 and error occurred. Added 22k to both and error disappeared. That behavior could be repeated.Conclusion: The internal weak pull-up on RA3 was lazy. For the time being, I will put weak pull-ups only on RA0..RA3. In any final design, weak pull-ups will be added to both RA0..RA3 and RB0..RB4. Lesson learned.EDIT: PIcture to prove it.EDIT2: Another way to see how the Columns and Rows are mapped (attached).

author: Atlan
author_rank: Frequent Contributor
timestamp: November 15, 2024, 10:07:10 pm
content: Put 1k pullup resistors there. On the lathe, there will be all kinds of interference when turning on the motor. The internal pullup resistors will be insufficient, and will cause false button closures. Personally, I also put capacitors to the buttons.P. S. Add 100n to gnd on reset pin