![]() | ![]() | ![]() |
| |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
![]() |
| | Tools |
| | #1 | |
|
Hi guys, I am a newbie to the forum and I hope that someone can help me keep what hair I have remaining. I am trying to code a project with a Pic 16f877A that has a telephone style keypad with a dedicated keypad decoder chip for debouncing that provides a data valid signal for the interrupt function, an HD44780 based LCD module, and 40 relays for output. The display shows a welcoming message until you press a key on the keypad, at which time it shows a different display with spaces prompting for more keys ( numbers ) to be entered. After the 3rd key is pressed, the code checks for validity and activates the appropriate relay for a set time duration. I am using the PORTB,0 interrupt feature to detect keypresses. I have been able to code each of the routines for the different functions successfully, but when I try to combine the code snippets, I run into problems with the system not responding to keypresses and/or the display showing garbage. I am pretty sure that the multiple timing loops needed for the display are causing the processor to be tied up for too long in some cases which is causing it to miss keypresses and other events. I am going to want to activate the watchdog timer function for the finished device, as well, which means that I may need the pre-scaler for it. My thought is to use Timer 1 or 2 to handle the timing for the display functions and eliminate, or at least reduce the number of delay loops in the code. I expect that I would have to change the timer settings on the fly, depending what times I needed for the various functions and poll the overflow bit(s). Does this sound like the best way to go? Will there be a problem with using either or both of these timers for the delays? How will the keypad interrupt affect the timer(s) as I am polling them? Sorry for the long post. Any help would be greatly appreciated. Cheers, Soundguy
__________________ Quote:
| ||
| |
| | #2 |
|
hi, ![]() Are you using the PIC's Interrupt options within your program OR is it all Polling.?
__________________ Eric " Good enough is Perfect " I will NOT answer PM's requesting technical help, please use the Forum PIC tutorials: Nigel's www.winpicprog.co.uk/ Bill's: www.blueroomelectronics.com/ | |
| |
| | #3 | ||||
| Quote:
![]() Quote:
It sounds like you have the issues without using the relays, is that the case? How are you driving the relays, btw? Quote:
and there are some posters on here doing some incredible things with keypads and LCDs or 7segment displays... if I recall, most of them are polling and debouncing the keys in software... I'd like to know how you are servicing that key press - code snippet, perhaps? Quote:
The long post isn't so bad; you explained the problem. I think you should go into some details to get help with it, though. A link to the relevant data sheet, or at least a number for the chip, and your source, or relevant parts of it... make sure you put it between [code] and [/code] tags to keep your format intact... | |||||
| |
| | #4 | |
|
Hi Eric, guess you were posting while I was typing... ![]() He is... Quote:
| ||
| |
| | #5 |
| hi BeeBop, I thought no one else was going to answer. ![]() Your post is far more useful than mine, I was trying to get a little more detail. [I'll shut up!] ![]() I saw the ref to one Intr but he didnt mention others.
__________________ Eric " Good enough is Perfect " I will NOT answer PM's requesting technical help, please use the Forum PIC tutorials: Nigel's www.winpicprog.co.uk/ Bill's: www.blueroomelectronics.com/ Last edited by ericgibbs; 25th April 2009 at 09:30 AM. | |
| |
| | #6 |
|
I'd be more inclined to manually poll something as simple as the keypad, freeing up interrupt driven overheads for other tasks. A code snippet would help out, other things might be at play such as context saving not incorporated?
__________________ digital-diy.com - Hobby microcontroller projects and tutorials. Assembly, PICBasic and C examples. | |
| |
| | #7 | ||
| Quote:
No, don't shut up.... I thought no one else was going to answer either ![]() Quote:
and I too suspect it has to do with the interrupt he is using... but I think he is trying to service the whole thing in the isr... I has a similar issue a few years back, with an IR rX which blocked.... so it could also be the decoder.... | |||
| |
| | #8 | |
|
Thank you for the quick responses, everyone. I'll try to answer your questions here. The keypad decoder is a 74HC922 decoder chip that handles keypad scanning, debouncing, and binary output conversion. It provides a "data valid" output after the debounce period, that I am using as an interrupt on PORTB,0. The binary output of this chip is a little strange and as such, I am using a lookup table to convert to BCD, as well as masking out unwanted characters/digits. ( * and # ) Once the keypad is decoded, the BCD number for each digit is stored in a seperate register according to whether the digit is the 1st, 2nd, or 3rd entry. The 1st digit is rejected if it is anything other than a 0. The 2nd digit is used with a lookup table that returns the same number multiplied by 10,as well as rejecting any number above 4, which then is placed in a register that is used for the relay decoding routine. The 3rd digit, after decoding is added to the same register that the 2nd digit ,after multiplying, was placed in with the result that the register now holds a number between 1 and 40, which in conjunction with the relay lookup table, will activate the proper relay for the keypad total entry. At the same time, after the digits entered are decoded, they need to be placed in the appropriate locations on the display with the 1st location being entered as part of the routine that changes the displayed message and prompts for keypad input.What I have done in the code is to put the decoded digits into the display as they are received nad before the 2nd digit is multiplied. The display is set for cursor advancement, so I only need to set the location for the 1st digit. The cursor advances to the 2nd and 3rd locations by itself. I have tried both handling the entire keypad routine in the ISR and outside of the ISR by just using flags created when a key is pressed.Both methods did not alleviate the problems. The displayed message has to change when the first keypress is detected, and I think that the delays needed for the display are at the root of my troubles. I am saving the "w" and "STATUS" registers with the Microchip approved method upon entering and exiting the ISR, and the simulation in MPLAB shows that nothing is getting corrupted in those registers. I am using an existing display in a panel that also incorporates the keypad, and is hardwired with the display R/W grounded, otherwise I wopuld have tried polling the display to check if it was ready to accept new data, instead of creating delays to insure that the display could accept new data. With regards to the relays, I am using 74HC138 3 to 8 decoders in a row/column matrix to decode and drive the relays through a ULN2003 for the 8 rows, and transistors for the 5 columns. The decoding for the relays is done in a lookup table that returns the appropriate output on PORTC for the 74HC138's. The lookup table has 40 entries in it to decode for the relays. I have tested all of the routines and they work individually. It is just when I try to stitch them together that I run into problems. Does it make sense to you to create delays as needed with Timer1 polling the overflow bit and then changing the timer loading and re-starting the timer when the next delay is needed? I should have mentioned that the delays that I think are causing the problems are the delays that are used to change the display message repeatedly, i.e. the welcoming message that uses both lines in the display, and has 3 messages the show in sequence, after which the sequence repeats. The delays used for this cause the message lines to display for 1 second before changing to the next message. The delays used for housekeeping for the display are of 1-5 milliseconds in duration depending on what is being done at that time.(Sending commands or characters.) The idea was for the interrupt to clear the display and show a new message with spaces for the entered keypad digits to display with a blinking cursor as a prompt. As I mentioned before, this routine does work, including the response to the interrupt for the first digit. When the second digit is entered, then the problems surface. The display messages are done in lookup tables as well, and as such, it would be a very long snippet of code to include here, but if needed, I will try to condense it down. Otherwise I might have to include the whole listing. Is there some method of loading display data into a register ahead of time and then sending each message in a quick routine? Would it help if I used the "DT" method of putting data in a lookup table instead of having seperate lines for each character in the table along with their respective "RETLW" statements? I thought that this would be a simple project when I started it many months ago. I never dreamed that it could be so hard to create the software needed. As this is something that I need to resolve ASAP, is there anyone in the Vancouver area that I could connect with to try to finish this? I will compensate them for their time. If so, please tell me what I need to do for us to connect. Thank you. Soundguy
__________________ Quote:
| ||
| |
| | #9 |
|
You got me guessing what this is for?? Some type of security access controller with 40 door-lock relays? A mailbox for apartments with 40 little mail doors? A bicycle hire rack!! Darn the intrigue... | |
| |
| | #10 | |
|
You're close. It is a buzz button replacement for an apartment building that has 38 individual, un-reliable, buttons for buzzing the suites.
__________________ Quote:
| ||
| |
| | #11 | |||||
|
hi, Quote:
The decoder latches the key on its outputs, so once you have the first one, you expect more, so polling, and collecting the keys in a buffer before displaying anything on the LCD should (yea right, eh?) work. I'm thinking you have a buffer: Quote:
Quote:
If you could post a snippet which showed how you are collecting the keystrokes, and perhaps your ISR, it would help out a lot. EDIT: I was just having a look at the data sheet for that decoder.. Quote:
Quote:
I can see how the delays in the LCD routines could be an issue. But just putting the digit in the display shouldn't be a problem; I'd think quite a few milliseconds would pass before a human finger would get to the next key. What is the 'displayed message,' and what is it changed to? Are there a lot of characters? You could take the capacitor out of the cct, and poll the keys... Last edited by BeeBop; 26th April 2009 at 06:48 AM. | ||||||
| |
| | #12 | |
|
Hi BEEBOP, You are right that the processor usually just sits there displaying the welcoming message sequence : WELCOME TO (building name), PLEASE ENTER THE RESIDENTS CODE... When a key is pressed, the data valid output from the decoder, which is connected to PORTB,0 triggers an interrupt. The ISR first saves the W and STATUS registers, then checks for the 1st digit to be a zero. If it is not a zero, the routine goes to its exit section, which restores the W and STATUS registers, renables the interrupts and returns to the main loop. (There are no other interrupts enabled in the program besides the PORTB,0 interrupt. I have not yet learned to work with timer based interrupts.) If the 1st digit is a zero, the ISR routine then stores the zero in a buffer labelled for the 1st digit. It then looks for the 2nd digit to be entered during a 5sec countdown delay.If there is no entry within that time, the routiine clears the buffers, and exits as mentioned above. If there is a 2nd digit entered, the routine checks to make sure that the digit is 4 or less. if so, the number is placed in a buffer for the 2nd digit.The multiplication routine that I mentioned before is also invoked. Then there is the 5sec coundown, again, while the routine looks for the 3rd digit. ( Each time a digit is sucessfully entered and checked, a bit is incremented in a flag register that indicates to the main loop how many digits have been entered. This is for the final output routine that activates the appropriate relay.) After the 3rd digit is entered and stored, the routine exits to the main loop which is constantly polling the flag register to see if 3 digits have been entered. If so, the program jumps to the output routine which activates the relay for a few seconds. You are also right in stating that the blinking cursor in the display is actually the prompt to the user to enter the next digit. The display shows a line of asterisks across the top of the display and a line of the same across the bottom display line, broken by blank spaces with the blinking cursor and any already entered digits. I neglected to mention before that there is a directory next to the panel that shows the visitor what code to press to call the intended resident. Regarding debouncing, that was the reason that I used the decoder chip in the first place, so that I wouldn't have to deal withmore delay routines for the keypad. In retrospect, I probably should have stuck with the tried and true method of keyboard scanning/debouncing in view of the needed conversion routine to generate BCD numbers representing the digits. The keypad decoder chip keeps the data on the output lines after a keypress, but the data valid signal only is present while the key is being pressed. Even so, I would think that the signal is present long enough for the chip to generate the interrupt. At least, after the chip responds, it can get the data from the decoder at its leisure. I have tried 2 different ISR routines, one doing all of the keypad decoding, testing, multiplying, storing, and display changing routines withiin the ISR. The other routine I tried just checked for the leading zero, and went back to the main loop, waiting for another interrupt to process the next digit. In both cases I ran into problems with the digits sometimes being ignored, or multiple digits being stored, or the wrong data being displayed on the LCD. In the first ISR routine, I began to think that I was trying to do too much within the ISR, which is why I tried the 2nd routine. The code got so convoluted, that I started to think that I was going about this whole projects code the wrong way. This is why it is difficult to provide a code snippet as there are so many versions of this code now, each with some working parts, and non-working parts. I feel that I am going in circles now. This is also why I was wondering in my original post whether using timer 1 and/or timer 2 for the longer countdown and delay periods might be the answer. I have never tried to do this before, and I was wondering if it is feasible, with having to change the timer functions on the fly all of the time . The 2-5 msec delays I mentioned are mostly to do with allowing the LCD time to process the updated screen displays, and I wonder just how much time I really need to allow for the display to do it's thing. I keep thinking that the processor is so busy decrementing registers for the delays, that it is missing the interrupt sometimes. I am wondering if I should be thinking along the lines of an operating system approach or a state machine approach? So far, most of the code has been linear, aside from the ISR routine, although there are subroutines for the table calls and time delays. ( I guess that it isn't so linear, after all.) Regards, Soundguy.
__________________ Quote:
| ||
| |
| | #13 |
|
This may not be the advice you want to hear. ![]() You took on a difficult and complex project for a beginner, but through intelligence and organisation you're bringing a lot of complex tasks together. So now it's almost working, (hehe) it might be time to re evaluate the whole system. So start with a flowchart, and decide on the basic modules and their interactions now you know more about what their needs are in terms of timing and sequence etc. I really believe it will be less work (and more enjoyable) to rebuild it from scratch but using some of the code modules you have already debugged. This will let you clean up the code and the operation, and might provide you with usable code modules you can use in other projects. I would use one interrupt only, to track your 5 second auto reset. Then a basic flowchart; 1. clear all keys entered 2. display welcome message 3. Wait here for keypress, then; * start 5 sec timer * update buttons (debounce with code delays, no int) * if it gets to 3rd key ok; do relay (int) if 5 seconds times out; goto 1. As for code debouncing, its pretty easy to add a short delay after the button is first pressed (10mS), then if still pressed; update the key (show on LCD for user) then wait for release, add a longer delay (25mS) and then ready to check for next press. This will remove double bouncing but should be fast enough to still catch hasty users who mash the second key before they fully release the first key. I think a rebuilt system like that will be much easier to debug and maintain than an interrupt on keypress system especially a dual int one on your first project. | |
| |
| | #14 | |
|
Hi MR RB, I have to agree that this task was much more difficult than I first thought it would be. I agree that the best way to deal with this is to start again from scratch regarding the code. Regarding the debouncing, I have mentioned before in my posts that the debouncing is taken care of by the 74HC922 decoder chip, so timing overhead for debouncing is not an issue. The time taken to decode the output of the chip, with the sub-routines needed, is however. Again, it seems to come down to the processor having to deal with a lot of decisions, while it is repeatedly doing mundane tasks, i.e. the display messages. I had, at one time, thought of using a seperate processor to handle the display part of things, and have it just put up the appropriate message as needed, whilst having the main processor do the decision making and take care of the input/ouput concerns, but I thought that it shouldn't be necessary to use 2 processors for this project. I guess in a nutshell what I am really asking for help with is how to implement the timer 1 and/or timer2 modules to deal with the delay needs for the LCD messages, (i.e. showing a message, then the next, then the next, repeatedly),while being able to respond to the keypresses and process them, as well as the 5 second timer, and how to change the timer loaded values on the fly, if that is the best way to do things. I assume that the shorter delays needed for initializing the LCD and pulsing the "E" line to the LCD can be taken care of with simple file decrementing type delays, as the initialization routine only happens once, and the "E" pulse can be covered with a NOP or two. I have been coding this project based on a 4MHZ clock, but in thinking about it, I could use a 1MHZ crystal instead, which would simplify pre-scaler and timer setups. I'll keep at it... Soundguy
__________________ Quote:
| ||
| |
| | #15 |
|
Reading the keyboard decoder chip is probably costing more hassle than it is worth, but I can understand you wanting to keep it if you have already built the hardware that way. Writing to the LCD should be almost instant, I checked my LCD functions and you only need a 50uS delay after sending each char to the LCD. To generate a 50uS delay on the fly you only need to reset TMR0, at 4MHz that is 1MHz per timer tick so you need to sense 50 timer ticks. So when TMR0 >50 you're done. You don't need ints or anything fancy for the LCD timing. The LCD initialisation only needs to be done at startup. As for the main 5 second timer, you don't need to change anything on the fly. Ive been building PIC apps for 10 years and these days I rarely even write to a timer, never mind change timer settings on the fly. Setup TMR1 at 1:1 prescale and free running (you never need to clear it or write a value to it) so it overflows at 1M / 256 /256 which is 15 times per second. Everytime it overflows, catch that in your int by checking the TMR1 overflow int flag. In your int, all you do is inc a variable which will happen at 15 times per second. Very simple. When that variable gets to (5sec * 15) ie 75 you have detected the 5 second event and can clear the screen etc (go back to step1). To disable the 5 second timer just keep resetting that variable. The timer is continually reset back to zero seconds. So each time they press a key you reset the variable, giving 5 seconds to press the next key. Thos should be the only things you need timers for? With the LCD initialisation delays you need some 6mS delays if I remember right so you can just reset TMR1H and when it gets to 30 is about 6mS. You won't need the 5 second timer during LCD initialisation of course. Now I read your previous post about the keyboard chip, why do you multiple the second digit by 10?? Why not just store the 2 digits in 2 byte variables as they are. Then you just display each one to LCD as a char? That makes more sense to me and is much better from a systems design point. Then decoding these 2 bytes to control the relay is part of your relay output function. But that's just the way i'd do it. What is the need to write messages to the LCD when they are doing keypresses? Surely you just clear the welcome message and display 0 on receipt of the first keypress, then display the next 2 chars as they are entered? Last edited by Mr RB; 28th April 2009 at 02:18 AM. | |
| |
|
| Tags |
| pic, question, timer |
| Thread Tools | |
| Display Modes | |
| |
Similar | ||||
| Title | Starter | Forum | Replies | Latest |
| Timer for PIC 16F877 MictroController | pal | Micro Controllers | 1 | 5th November 2005 06:56 PM |
| timer on 16f877 | goodpickles | Micro Controllers | 1 | 18th March 2005 08:59 AM |
| Question about the 555 timer | xenoxion | General Electronics Chat | 4 | 22nd June 2004 09:55 PM |
| 16F877 question | TKS | Micro Controllers | 7 | 26th May 2004 11:46 AM |
| PIC 16F877 timer | patricktran | Micro Controllers | 31 | 6th May 2004 02:05 PM |