Unrepentant Geek (matthew) wrote,
Unrepentant Geek

let's play whack-a-bug

I've been working on a project for the entertainment system. I've cracked open my AV switch and I'm grafting in some extra smarts. Part of this requires me to decode a 2x4 button matrix that is being driven by another chip. Below is part of the code that is doing that decoding with notes in the comments. There's a fairly subtle bug in the code that had me scratching my head for a little while. It's not immediately obvious but it does make sense once you see it. The bug manifests itself as buttons 2, 3 and 4 not working when pressed.

The functions readButtons14() and readButtons58() are attached to interrupt lines and executed when RB2 and RB3 go high respectively.

#define debounce        500
int lastTime = 0;

  The buttons on the system selector use a 2x4 matrix arrangement.
  RB2 and RB3 are the inputs to the matrix and RB4-7 are the outputs.
  RB2 pulses high for 50µs every 33ms (~30Hz)  RB3 then goes low for
  the remainder of the 33ms.
  We can check the states of RB4-7 during these times to see if a
  button has been pressed.  These are pulled low by 10k resistors tied
  to ground so a HIGH value means that a button has been pressed.
  RB2 --- 1 -- 2 -- 3 -- 4
          |    |    |    |
  RB3 --- 5 -- 6 -- 7 -- 8
          |    |    |    |
         RB4  RB5  RB6  RB7

void readButtons14()  //RB2 has gone high
  int now = millis();
  if( lastTime + debounce < now )
    lastTime = now;
    if( digitalRead(RB4) ) { doButton(1); }
    else if( digitalRead(RB5) ) { doButton(2); }
    else if( digitalRead(RB6) ) { doButton(3); }
    else if( digitalRead(RB7) ) { doButton(4); }

void readButtons58()  //RB3 has gone high
  int now = millis();
  if( lastTime + debounce < now )
    lastTime = now;
    if( digitalRead(RB4) ) { doButton(5); }
    else if( digitalRead(RB5) ) { doButton(6); }
    else if( digitalRead(RB6) ) { doButton(7); }
    else if( digitalRead(RB7) ) { doButton(8); }

Can you figure it out?

Select for the answer:
The bug results because millis() takes just under 50µs to execute. By the time we're checking buttons 2,3 and 4 RB2 has already gone low. However since the matrix input RB3 stays high longer than RB2 this timing issue does not affect buttons 6,7 and 8.

The solution? Move the debouncing code into the doButton() function where it should have been in the first place.

Tags: arduino, bugs, code, geeky, mcu

  • I welcome our new cube overlord

    Posted via LiveJournal app for Android.

  • it begins again...

    Tonight I changed the oil and started in on replacing the seat bushing. looks pretty odd without a tank. Posted via LiveJournal app for Android.

  • Makerbot madness

    I finally took some time to poke at my makerbot again. gordonmessmer and I tried to get it working again in a fairly standard config only…

  • Post a new comment


    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded