4x4 keypad on bus

Discussion in 'Embedded Systems and Microcontrollers' started by sevenfold4, Jan 16, 2015.

  1. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    Hello, i have working on this almost 3 days without any success and i just figure this out.

    Schematics of the system are here
    http://i.imgur.com/FWcJRvP.png
    and the problem part
    http://i.imgur.com/i7vwFXs.jpg

    Everything i have tried has just been trying.
    I think i had to play around with the RD and WR pins to get the chips to work correctly, but i just can not figure this out.
    This is the example code i have, to try and get '2' key working

    Code (Text):
    1.  
    2. volatile __xdata unsigned char * __data keypad =    (__xdata unsigned char *) 0x9000;
    3. #define WR P3_6
    4. #define RD P3_7
    5.  
    6. while(1)
    7.     {
    8.         WR=0;
    9.         RD=1;
    10.         *led=0b11000000;
    11.         *keypad==0b11110000;
    12.      
    13. //*keypad==0b11111110;
    14.             if (*keypad==0b11111110)
    15.             {
    16.                 WR=0;
    17.                 RD=1;
    18.                 *led=0b11000000;
    19.                 vardelay(5);
    20.                 *keypad==0b11111101;
    21.                 if (*keypad==0b11111110)
    22.                 {
    23.                     RD=1;
    24.                     WR=1;
    25.                     lcd_senddata('1');                  
    26.                 }
    27.                 else if (out==0b11111101)
    28.                 {
    29.                     RD=1;
    30.                     WR=1;
    31.                     lcd_senddata('2');
    32.                 }
    33.             }
    34.             else if (*keypad==0b11111101)
    35.             {
    36.                 RD=0;
    37.                 WR=1;
    38.                 if (*keypad==0b11111101)
    39.                 {
    40.                     RD=1;
    41.                     WR=1;
    42.                     lcd_senddata('5');
    43.                 }
    44.                 else if (*keypad==0b11111110)
    45.                 {
    46.                     RD=1;
    47.                     WR=1;
    48.                     lcd_senddata('4');
    49.                 }
    50.             }
    I can get data from buttons 1-c diagonally because they share the address.
    I am getting really frustrated with this. If you could give me some guide or tips, i would be very thankful.
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,606
    So U5 and U15 sit on the same address? You write to U5 to pick a row and read U15 to see which column is on? I'm asking to see if I understand your scheme. I have to ask because in "I can get data from buttons 1-c diagonally because they share the address" I have no idea what address they share beyond U5/U15

    Overall the scheme looks fine, mebby there is a wiring error on the pad or such.

    The row data in U5 is static. You can write a value and use anything (DVM, LED) to see how the keys effect U15 by pressing keys and seeing what happens.
     
  3. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    That is the idea. The system is fine, but my knowledge in C is probably the bad part.
    Ideally, i write a zero to 1 of the pins on U5 to pick a row, and read the output from u15 to see the column, as you said. I have tried that, but the LED just gets the *keypad value i gave to it.
     
  4. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    Well the same as with my previous question, once i asked here, i figured it out.
    Turns out i over complicated things, and the hardware does more work for me than i thought.
     
    ErnieM likes this.
  5. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    In your code, I'd check that the if statements are doing what you expect.

    IMHO

    First, you set *keypad equal to 0b11110000, and then test for 0b11111110 or 0b11111101. The code will never get executed.

    Secondly, you test for a value and then in the if block, test for a second value. That code in that if block won't get executed.
     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,606
    Oft times just phrasing your work into a question will nudge the mental gears into seeing the solution.

    There have been times I talked over my project to my dog as if he could understand what I was saying. It really helped.

    So does going out for Chinese food. Yumm.
     
    sevenfold4 likes this.
  7. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    Heh, for me food does not really bring me good ideas about programming, more about life etc. I do get a lot of help when i ask people like this. Mostly not from them, just something goes right in the head as you said.


    There are some unneeded lines that i just put there out of frustration, hoping something will work differently. But as i stated before, its all good now.
    If you are interested i can write how it works(since i understand it now).
     
  8. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,606
    Please do. That is one way people learn here, not just you but everyone (including the people who just read threads without responding).
     
  9. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    Well basically, i got some bad information, and i tried to control the RD and WR pins, what is actually not necessary.
    Turns out that it picks the pins "automatically" depending on how you use the address.
    A simple code like this will work for the 1st line
    Code (Text):
    1. if        (*keypad=0b11111110)
    2.         {
    3.             out=*keypad;
    4.             if        (out==0b11111110)
    5.             {
    6.             lcd_senddata('1');
    7.             return ;
    8.             }
    9.             else if    (out==0b11111101)
    10.                 lcd_senddata('2');
    11.             else if    (out==0b11111011)
    12.                 lcd_senddata('3');
    13.             else if    (out==0b11110111)
    14.                 lcd_senddata('F');
    Now i am just trying to figure out how can i get all the lines working, If i assign the input address the lines work without any problem, but i am trying to use the interrupt to make it work, i am halfway there (i think) and i will post the end part of the code that matters here.

    I think it is quite fascinating how it works, especially for someone who came from the PIC kits what are quite straight forward.
     
  10. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    I would like to discuss a bit more. A problem that a raised is that it spams the button. Normally i would use a falling edge interrupt, but it seems the 8051 does not have something like this. I tried having a while loop, but that only works on certain keys and others still keep spamming. Any ideas what i could do?

    I have the buttons working with a normal interrupt at the moment.
     
  11. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,606
    I can see the advantage of hitting an interrupt when a button is pressed, though I rarely if ever do this.

    How I do it is I typically have a "tick timer" ISR which updates a variable at regular intervals. It's kinda useful to have that, and in the PIC devices I've been using a 1mS interval is falling off a log easy to generate.

    While inside that routine I also scan my buttons. I cut the scans back to once every 25 ISR's or once every 25mS. The reason for that is I use that time to debounce the buttons: a key press (or release) is only scored as valid if it exists over two subsequent reads. I've found that to be adequate to filter out bounces for the buttons I use, but quick enough not to frustrate the user (ME!).

    The buttons pressed are exposed by a global variable.
     
    sevenfold4 likes this.
  12. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    Thanks, i will check this method out once i get 1wire working.
     
  13. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    So now that i have tried something like that, it is good, unless you have 1wire, then it just does not work. The interrupt can happen when 1wire is writing or reading and when that happens things go sour. So i have to do it with just the interrupt i intended and doing key checks inside the main while loop(which is a pretty bad way of doing it).
     
  14. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,606
    There are many many things that can happen that would interfere or be interfered with when doing periodic button checks. In most of my creations I place the buttons on the same lines as an LCD display and somehow I get them to work together flawlessly, no missed press events, no dropped characters.

    All you need do is let the button scan know when something else is using the hardware or has critical timings, either by reading a pin or checking a flag. When the flag clears then button scans resume.
     
  15. sevenfold4

    Thread Starter Member

    Jan 12, 2015
    80
    7
    The only thing it is interfering at the moment is the 1 wire. LCD and keypad are on the same line and they have no problems with the timing.
    But the 1wire is constantly reading/writing to get the temperature and the timing in there has to be perfect. +/- few us can mess things up
     
  16. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    Do you need an interrupt for the buttons at all? How about not enabling that timer interrupt, but in the endless loop in your main() routine, just check the interrupt flag and if it's found to be set, do the keyboard scan routine and clear the flag. Sure, it will operate at a somewhat irregular rate, but you aren't likely to notice it in actual use.

    People think everything needs an interrupt, and then they get into trouble with conflicting interrupts. If you decide which item in the program truly needs to happen at an exact time, then you can let that one have an interrupt and handle other events some other way. Human-activated controls are typically very low priority as far as timing is concerned--a millisecond is forever to a processor and nothing to a human.

    But if you follow this scheme, be aware that the keypad scan might get interrupted part-way through, so you have to be certain that you won't change anything (port pins?) that affects its operation if that happens.

    (Edited to say that checking the interrupt flag is easy on a PIC processor, which is what I use, and this is an 8051-type processor, and I don't know if it's possible.)
     
    Last edited: Jan 30, 2015
  17. MrChips

    Moderator

    Oct 2, 2009
    12,446
    3,362
    Where is the 1-wire connected?
     
  18. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,689
    2,750
    Even better, Ernie, is to just set a flag that a period of time has elapsed in the ISR. Then, poll that flag in your main loop to activate the keypad polling routine synchronously with the main program.

    In fact, every application I write has the following timer 0 code:

    Code (Text):
    1.  
    2. ;********************************************************
    3. ;** Timer 0 -- Main Program Heartbeat Every 1.024ms    **
    4. ;********************************************************
    5.  
    6. tmr0int bcf intcon,tmr0if       ;turn off t0 int
    7.  
    8.     movf    _timer,w        ;get current time
    9.     incf    _timer,f    ;and increment it
    10.     xorwf   _timer,w        ;compare with last
    11.     iorwf   _tmrchg,f       ;and save changed bits
    12.  
    13.     bra intdone         ;and getout
    14.  
    This gives me a set of bits in _tmrchg that represent elapsed time of 1,2,4 ... ms that I can use to trigger events in the main code.

    The first routine of the main loop looks like this:

    Code (Text):
    1. ;******************************************************************
    2. ;** GETTIM -- Get current time and changed bits since last check **
    3. ;******************************************************************
    4.  
    5. gettim  clrf    tmrchg1         ;clear bits from previous pass
    6.  
    7.     bcf intcon,tmr0ie       ;disable ints
    8.     movff   _timer,timer        ;copy timer data
    9.     movff   _tmrchg,tmrchg
    10.     clrf    _tmrchg     ;clear for next time
    11.     bsf intcon,t0ie     ;and reinable ints
    12.  
    13.     return
    14.  
    15.  
    I give each bit of tmrchg a name using #define, and then I can do this:

    Code (Text):
    1.  
    2. ;*****************************************
    3. ;** GETKEY -- Process key every 32 ms   **
    4. ;*****************************************
    5.  
    6. getkey  clrf    keychg          ;clear changed keys
    7.     clrf    keypr           ;clear press and release registers
    8.     clrf    keyph           ;clear press and hold registers
    9.     clrf    keyrpt          ;clear key repeat register
    10.  
    11.     retbc   TC4ms           ;process kbd row every 4 ms (total 32 ms debounce time)
    12.  
    13.     ...
    14.  
    15.  
    where the flag bit TC4ms is set for the loop every 4.096ms.
     
  19. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,606
    Good advice joey. I too *love* the utility of having a tick timer running in the background (that in my case also handled the external button read and debounce). I talk about that back in post 11.

    Using the flag as a semaphore for external business sounds quite useful, though I have not done 1-wire and can't comment if 1ms is sufficient time to do a transaction.
     
  20. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,689
    2,750
    No! The one-wire has to be done as independent tight code, probably with precise software delays (and therefore ints disabled).

    My point of synchronizing the keypad (and display, other UI, and whatever else possible) with the main loop is to eliminate the constraint of the interrupt driven peripherals from mucking with each other unpredictably. This eliminates the question: "Is the LCD being updated? Can I scan my kbd now?"
     
Loading...