Solved: 4x4 keypad arduino non blocking

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1. I am using ATMega 2560 arduino board & want to interface 4x4 keypad in it.
It has lots of other peripherals like graphical lcd, relay, 3 uart peripherals. SO bit of large code in it.

 

2. Need to interface 4x4 keypad. Was looking at this library.
https://playground.arduino.cc/Ma...

 

3. On this page, its written that:
" If key presses seem to take a long time to show up then you are probably using long delay()'s in your code. The same thing can happen if you use too many small delay()s like delay(10)."

 

4. In my code, there are lots of peripherals connected, in many places I need to add delay for some functions.

 

5. Is there any other keypad library, which is completely independent of this. So that I can read it in main without this delay issue & it should be non blocking

Last Edited: Mon. Jun 12, 2017 - 01:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm a bit confused, have you tried this library with your keypad and found it to be a problem, or have you not yet tried it?

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Vindhyachal Takniki wrote:
I need (sic?) to add delay for some functions.

Do you really?

 

Or could you design your code to be "non-blocking" ... ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Solved this by using a Timer interrupt of 20ms & in it used state machines to scan keyboard.
Code is working fine for 4x4 keyboard

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very Good, If you can, please post your code (here or in project section w/ link) for others to learn from! 

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Vindhyachal Takniki wrote:
Solved this by using a Timer interrupt of 20ms & in it used state machines to scan keyboard. Code is working fine for 4x4 keyboard

So you are sitting in the ISR, and doing all the scanning?

 

IME I'll do one "column" every e.g. 2.5ms.  That gives time for the next column setup to settle before reading.  After all columns are scanned (e.g. about 10ms) then I enter the composite into my debouncing routine.  3x or 4x debouncing to confirm the makes and breaks.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I might need this on our set up, would appreciate the code!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

below is the code, max time I found was 160us, when key in postion 4,4 is pressed.
Time is measured from start of isr to end of isr as u can see in code.
 

 

 

#include "TimerOne.h"

const uint8_t no_key = 0U;

const uint8_t keys_val[4][4] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

volatile uint8_t key_main_access;
volatile uint8_t key_state;
volatile uint8_t old_col;
volatile uint8_t new_col;
volatile uint8_t new_row;
volatile uint8_t main_read;
volatile uint8_t main_interrupted;
volatile uint8_t key1;
volatile uint8_t key2;

const int row_1 = 33;
const int row_2 = 35;
const int row_3 = 37;
const int row_4 = 39;
const int col_1 = 41;
const int col_2 = 43;
const int col_3 = 45;
const int col_4 = 47;

volatile uint32_t old_time, new_time, diff = 0U;

void setup()
{
    Serial.begin(9600);

/* init all vars for keypad in default state */
    init_all_vars__key_c();

/* 20ms timer interrupt */
    Timer1.initialize(20000);
    Timer1.attachInterrupt(isr_key_callback); 

/* all colums inout high */
    pinMode(col_1, INPUT_PULLUP);
    pinMode(col_2, INPUT_PULLUP);
    pinMode(col_3, INPUT_PULLUP);
    pinMode(col_4, INPUT_PULLUP);    

/* all rows output HIGH */
    pinMode(row_1, OUTPUT);
    pinMode(row_2, OUTPUT);
    pinMode(row_3, OUTPUT);
    pinMode(row_4, OUTPUT);

    digitalWrite(row_1, HIGH);
    digitalWrite(row_2, HIGH);
    digitalWrite(row_3, HIGH);
    digitalWrite(row_4, HIGH);

}

void isr_key_callback()
{
    //old_time = micros();

    uint8_t check;

    if(0U == key_main_access)   /* if main is not accessing keypad variable, will happen if main wants to reset keypad varaibles */
    {
        if(0U == key_state)    /* ground all rows & check for any col low */
        {
            digitalWrite(row_1, LOW); digitalWrite(row_2, LOW); digitalWrite(row_3, LOW); digitalWrite(row_4, LOW);  

            if(!digitalRead(col_1))  /* if found store the col & move to next state */
            {
                old_col = 1U;
                key_state = 1U;
            }
            else if(!digitalRead(col_2))
            {
                old_col = 2U;
                key_state = 1U;
            }
            else if(!digitalRead(col_3))
            {
                old_col = 3U;
                key_state = 1U;
            }
            else if(!digitalRead(col_4))
            {
                old_col = 4U;
                key_state = 1U;
            }
            else
            {
            }                        

        }
        else if(1U == key_state)  /* ground one row at a time & check for col low  */
        {
            check = 0U;   /* assume row 1 is found to be low */
            digitalWrite(row_1, LOW); digitalWrite(row_2, HIGH); digitalWrite(row_3, HIGH); digitalWrite(row_4, HIGH);
            if(!digitalRead(col_1))   /* if found store the col & row */
            {
                new_col = 1U;
                new_row = 1U;
            }
            else if(!digitalRead(col_2))
            {
                new_col = 2U;
                new_row = 1U;
            }
            else if(!digitalRead(col_3))
            {
                new_col = 3U;
                new_row = 1U;
            }
            else if(!digitalRead(col_4))
            {
                new_col = 4U;
                new_row = 1U;
            }
            else
            {
                check = 1U;  /* initial assumption that this row found to be false, so now check next row */
            } 

            if(1U == check)   /* repeat same as row 1 */
            {
                check = 0U;
                digitalWrite(row_1, HIGH); digitalWrite(row_2, LOW); digitalWrite(row_3, HIGH); digitalWrite(row_4, HIGH);
                if(!digitalRead(col_1))
                {
                    new_col = 1U;
                    new_row = 2U;
                }
                else if(!digitalRead(col_2))
                {
                    new_col = 2U;
                    new_row = 2U;
                }
                else if(!digitalRead(col_3))
                {
                    new_col = 3U;
                    new_row = 2U;
                }
                else if(!digitalRead(col_4))
                {
                    new_col = 4U;
                    new_row = 2U;
                }
                else
                {
                    check = 1U;
                }
            }

            if(1U == check)    /* repeat same as row 1 */
            {
                check = 0U;
                digitalWrite(row_1, HIGH); digitalWrite(row_2, HIGH); digitalWrite(row_3, LOW); digitalWrite(row_4, HIGH);
                if(!digitalRead(col_1))
                {
                    new_col = 1U;
                    new_row = 3U;
                }
                else if(!digitalRead(col_2))
                {
                    new_col = 2U;
                    new_row = 3U;
                }
                else if(!digitalRead(col_3))
                {
                    new_col = 3U;
                    new_row = 3U;
                }
                else if(!digitalRead(col_4))
                {
                    new_col = 4U;
                    new_row = 3U;
                }
                else
                {
                    check = 1U;
                }
            }        

            if(1U == check)     /* repeat same as row 1 */
            {
                check = 0U;
                digitalWrite(row_1, HIGH); digitalWrite(row_2, HIGH); digitalWrite(row_3, HIGH); digitalWrite(row_4, LOW);
                if(!digitalRead(col_1))
                {
                    new_col = 1U;
                    new_row = 4U;
                }
                else if(!digitalRead(col_2))
                {
                    new_col = 2U;
                    new_row = 4U;
                }
                else if(!digitalRead(col_3))
                {
                    new_col = 3U;
                    new_row = 4U;
                }
                else if(!digitalRead(col_4))
                {
                    new_col = 4U;
                    new_row = 4U;
                }
                else
                {
                    check = 1U;
                }
            }      

            if(0U == check)       /* a row low has been found */
            {
                if(new_col == old_col)   /* if new column & old colum has been equal */
                {
                    if((new_col >= 1U) && (new_col <= 4) && (new_row >= 1) && (new_row <= 4))  /* if new col & new row are within array boundaries */
                    {
                        if(0U == main_read)           /* if main is not reading the key state */
                        {
                            key1 = keys_val[new_row-1U][new_col-1U];      /* store the key value */
                        }
                        else
                        {
                            key2 = keys_val[new_row-1U][new_col-1U];    /* mainline got interrupted */
                            main_interrupted = 1U;
                        }
                        key_state = 2U;       /* key found successfully, now move to next state */
                    }
                    else
                    {
                        key_state = 0U;      /* if new col & new row are not within array boundaries, something wrong, move to default state */
                    }
                }
                else  /* if new col & old col are not same, something wrong, move to default state */
                {
                    key_state = 0U;
                }
            }
            else    /* if no row low has been found, something wrong,move to default state */
            {
                key_state = 0U;
            }     

        }
        else if(2U == key_state)   /* wait for all keys to open again, by grounding all rows, & wait for col to be high */
        {
            digitalWrite(row_1, LOW); digitalWrite(row_2, LOW); digitalWrite(row_3, LOW); digitalWrite(row_4, LOW);
            if(digitalRead(col_1) && digitalRead(col_2) && digitalRead(col_3) && digitalRead(col_4))
            {
                key_state = 0U;    /* all col found high, move to default state */
            }
        }
        else
        {
        }

    }

    /*new_time = micros();
    if(diff < (new_time-old_time))
    {
        diff =  new_time-old_time;
        Serial.println(diff);
    }*/

}

void loop()
{
    uint8_t temp;

    while(1)
    {
        temp = key_read();
        if(no_key != temp)
        {
            Serial.print("KEY: ");
            Serial.println((char)temp);
        }
    }
}

uint8_t key_read(void)
{
    uint8_t temp;

    main_read = 1U;  /* set var for main line read & read the key value */
    temp = key1;
    key1 = no_key;
    main_read = 0U;

    if(1U == main_interrupted)  /* if main line gets interupted, again read the key var */
    {
        temp = key2;
        key2 = no_key;
        main_interrupted = 0U;
    }

    return temp;

}

void clear_key_vars(void)
{
    key_main_access = 1U;    /* clear all previous key varaibles & start aagin  */ 

    key_state = 0U;
    old_col = 1U;
    new_col = 1U;
    new_row = 1U;
    main_read = 0U;
    main_interrupted = 0U;
    key1 = no_key;
    key2 = no_key;  

    key_main_access = 0U;

}

void init_all_vars__key_c(void)
{
    key_main_access = 0U;   /* init ll vars to default state */
    key_state = 0U;
    old_col = 1U;
    new_col = 1U;
    new_row = 1U;
    main_read = 0U;
    main_interrupted = 0U;
    key1 = no_key;
    key2 = no_key;
}

 

Last Edited: Sat. Jun 17, 2017 - 11:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unless you have diodes in your keypad, I'd suggest you set the unused rows to inputs - that way you don't have the potential for shorting active pins. You can make you code much faster - only scan one row at a time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1. Which diodes to place?

2. If diodes not used, then which unsused rows?

 

can u elaborate

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Each row is either and output and low or an input. This has been discussed many times before. Let Google be your guide.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I never cease to be gobsmacked by the sheer size and complexity of these "solutions".

 

Every CPU or MCU textbook has examples for scanning a keypad.  e.g. Z80 or 6502 from the 1980s.

If you think about it,  every PC keyboard has got a microcontroller to service a "large" matrix of keys.   Detect up/down shift etc.

 

I am a great believer in "search for a proven solution".   Use it.   Or perhaps study the method and create "your" own version.

 

Don't be proud.    See how other people do things.    Steal the best ideas.   Improve on their techniques ...

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1. Attached is updated code with minor improvements and also now one one row at a time is output low, remaining rows will be  input pullup

2. Max time for key scan in ISR is 172us for key at 4x4 location.

3. code also takes care of the problem if key is read in mainline, while at same time key getting updated.

 

#include "TimerOne.h"

const uint8_t no_key = 0U;

const uint8_t keys_val[4][4] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

volatile uint8_t key_main_access;
volatile uint8_t key_state;
volatile uint8_t old_col;
volatile uint8_t new_col;
volatile uint8_t new_row;
volatile uint8_t main_read;
volatile uint8_t main_interrupted;
volatile uint8_t key1;
volatile uint8_t key2;

const int row_1 = 33;
const int row_2 = 35;
const int row_3 = 37;
const int row_4 = 39;
const int col_1 = 41;
const int col_2 = 43;
const int col_3 = 45;
const int col_4 = 47;

volatile uint32_t old_time, new_time, diff = 0U;
 
void setup()
{
    Serial.begin(9600);

/* init all vars for keypad in default state */  
    init_all_vars__key_c();

/* 20ms timer interrupt */  
    Timer1.initialize(20000);         
    Timer1.attachInterrupt(isr_key_callback); 

/* all colums inout high */  
    pinMode(col_1, INPUT_PULLUP);
    pinMode(col_2, INPUT_PULLUP);
    pinMode(col_3, INPUT_PULLUP);
    pinMode(col_4, INPUT_PULLUP);    

/* all rows output HIGH */  
    pinMode(row_1, INPUT_PULLUP);
    pinMode(row_2, INPUT_PULLUP);
    pinMode(row_3, INPUT_PULLUP);
    pinMode(row_4, INPUT_PULLUP);   
            
}

void loop()
{
    uint8_t temp;

    clear_key_state_and_vars();
    
    while(1)
    {
        temp = key_read();
        if(no_key != temp)
        {
            Serial.print("KEY: "); 
            Serial.println((char)temp);
        }
    }
}


void isr_key_callback(void)
{
    old_time = micros();  
    keypad_scan(); 
    new_time = micros();
    
    if(diff < (new_time - old_time))
    {
        diff =  new_time - old_time;
        Serial.print("Time: ");  
        Serial.println(diff); 
    }     
}

 

void keypad_scan()
{  
    uint8_t check;

    if(0U == key_main_access)   /* if main is not accessing keypad variable, will happen if main wants to reset keypad varaibles */  
    {
        if(0U == key_state)    /* ground all rows & check for any col low */  
        {
            pinMode(row_1, OUTPUT); pinMode(row_2, OUTPUT); pinMode(row_3, OUTPUT); pinMode(row_4, OUTPUT);          
            digitalWrite(row_1, LOW); digitalWrite(row_2, LOW); digitalWrite(row_3, LOW); digitalWrite(row_4, LOW); 

            if(!digitalRead(col_1))  /* if found store the col & move to next state */ 
            {
                old_col = 1U;
                key_state = 1U;
            }
            else if(!digitalRead(col_2))
            {
                old_col = 2U;
                key_state = 1U;
            }
            else if(!digitalRead(col_3))
            {
                old_col = 3U;
                key_state = 1U;
            }
            else if(!digitalRead(col_4))
            {
                old_col = 4U;
                key_state = 1U;
            }
            else
            {
            }                        
        
        }
        else if(1U == key_state)  /* ground one row at a time & check for col low  */ 
        {
            check = 0U;   /* assume row 1 is found to be low */ 
            pinMode(row_1, OUTPUT); pinMode(row_2, INPUT_PULLUP); pinMode(row_3, INPUT_PULLUP); pinMode(row_4, INPUT_PULLUP);          
            digitalWrite(row_1, LOW); 
            if(!digitalRead(col_1))   /* if found store the col & row */ 
            {
                new_col = 1U;
                new_row = 1U;
            }
            else if(!digitalRead(col_2))
            {
                new_col = 2U;
                new_row = 1U;
            }
            else if(!digitalRead(col_3))
            {
                new_col = 3U;
                new_row = 1U;
            }
            else if(!digitalRead(col_4))
            {
                new_col = 4U;
                new_row = 1U;
            }
            else
            {
                check = 1U;  /* initial assumption that this row found to be false, so now check next row */ 
            } 


            if(1U == check)   /* repeat same as row 1 */ 
            {
                check = 0U;
                pinMode(row_1, INPUT_PULLUP); pinMode(row_2, OUTPUT); pinMode(row_3, INPUT_PULLUP); pinMode(row_4, INPUT_PULLUP);   
                digitalWrite(row_2, LOW);
                if(!digitalRead(col_1))
                {
                    new_col = 1U;
                    new_row = 2U;
                }
                else if(!digitalRead(col_2))
                {
                    new_col = 2U;
                    new_row = 2U;
                }
                else if(!digitalRead(col_3))
                {
                    new_col = 3U;
                    new_row = 2U;
                }
                else if(!digitalRead(col_4))
                {
                    new_col = 4U;
                    new_row = 2U;
                }
                else
                {
                    check = 1U;
                }           
            }


            if(1U == check)    /* repeat same as row 1 */ 
            {
                check = 0U;
                pinMode(row_1, INPUT_PULLUP); pinMode(row_2, INPUT_PULLUP); pinMode(row_3, OUTPUT); pinMode(row_4, INPUT_PULLUP);
                digitalWrite(row_3, LOW); 
                if(!digitalRead(col_1))
                {
                    new_col = 1U;
                    new_row = 3U;
                }
                else if(!digitalRead(col_2))
                {
                    new_col = 2U;
                    new_row = 3U;
                }
                else if(!digitalRead(col_3))
                {
                    new_col = 3U;
                    new_row = 3U;
                }
                else if(!digitalRead(col_4))
                {
                    new_col = 4U;
                    new_row = 3U;
                }
                else
                {
                    check = 1U;
                }           
            }        


            if(1U == check)     /* repeat same as row 1 */ 
            {
                check = 0U;
                pinMode(row_1, INPUT_PULLUP); pinMode(row_2, INPUT_PULLUP); pinMode(row_3, INPUT_PULLUP); pinMode(row_4, OUTPUT);
                digitalWrite(row_4, LOW);
                if(!digitalRead(col_1))
                {
                    new_col = 1U;
                    new_row = 4U;
                }
                else if(!digitalRead(col_2))
                {
                    new_col = 2U;
                    new_row = 4U;
                }
                else if(!digitalRead(col_3))
                {
                    new_col = 3U;
                    new_row = 4U;
                }
                else if(!digitalRead(col_4))
                {
                    new_col = 4U;
                    new_row = 4U;
                }
                else
                {
                    check = 1U;
                }           
            }      


            if(0U == check)       /* a row low has been found */ 
            {
                if(new_col == old_col)   /* if new column & old colum has been equal */ 
                {
                    if((new_col >= 1U) && (new_col <= 4) && (new_row >= 1) && (new_row <= 4))  /* if new col & new row are within array boundaries */ 
                    {
                        if(0U == main_read)           /* if main is not reading the key state */ 
                        {
                            key1 = keys_val[new_row-1U][new_col-1U];      /* store the key value */ 
                        }
                        else
                        {
                            key2 = keys_val[new_row-1U][new_col-1U];    /* mainline got interrupted */ 
                            main_interrupted = 1U;                 
                        }
                        key_state = 2U;       /* key found successfully, now move to next state */ 
                    }
                    else
                    {
                        key_state = 0U;      /* if new col & new row are not within array boundaries, something wrong, move to default state */ 
                    }
                }  
                else  /* if new col & old col are not same, something wrong, move to default state */ 
                {
                    key_state = 0U;
                }
            }       
            else    /* if no row low has been found, something wrong,move to default state */ 
            {
                key_state = 0U;
            }     
        
        }
        else if(2U == key_state)   /* wait for all keys to open again, by grounding all rows, & wait for col to be high */  
        {
            pinMode(row_1, OUTPUT); pinMode(row_2, OUTPUT); pinMode(row_3, OUTPUT); pinMode(row_4, OUTPUT); 
            digitalWrite(row_1, LOW); digitalWrite(row_2, LOW); digitalWrite(row_3, LOW); digitalWrite(row_4, LOW);   
            if(digitalRead(col_1) && digitalRead(col_2) && digitalRead(col_3) && digitalRead(col_4))
            {
                key_state = 3U;    /* all col found high, move to next state */ 
            }     
        }
        else if(3U == key_state)   /* wait for all keys to open again, by grounding all rows, & wait for col to be high */  
        {
            pinMode(row_1, OUTPUT); pinMode(row_2, OUTPUT); pinMode(row_3, OUTPUT); pinMode(row_4, OUTPUT); 
            digitalWrite(row_1, LOW); digitalWrite(row_2, LOW); digitalWrite(row_3, LOW); digitalWrite(row_4, LOW);   
            if(digitalRead(col_1) && digitalRead(col_2) && digitalRead(col_3) && digitalRead(col_4))
            {
                key_state = 0U;    /* all col found high, move to default state */ 
            }     
            else
            {
                key_state = 2U;                  
            }
        }
        else
        {
        }        

    }    
}

uint8_t key_read(void)
{
    uint8_t temp;

    main_read = 1U;  /* set var for main line read & read the key value */ 
    temp = key1;
    key1 = no_key;
    main_read = 0U;

    if(1U == main_interrupted)  /* if main line gets interupted, again read the key var */ 
    {
        temp = key2;
        key2 = no_key;
        main_interrupted = 0U;      
    }

    return temp;
  
}


void clear_key_vars(void)     
{
    key_main_access = 1U;    /* clear all previous key varaibles & start aagin  */ 
    
//    key_state = 0U;
    old_col = 1U;
    new_col = 1U;
    new_row = 1U;
    main_read = 0U;
    main_interrupted = 0U;
    key1 = no_key;
    key2 = no_key;  

    key_main_access = 0U;
    
}


void clear_key_state_and_vars(void)     
{
    key_main_access = 1U;    /* clear all previous key varaibles & start aagin  */ 
    
    key_state = 0U;
    old_col = 1U;
    new_col = 1U;
    new_row = 1U;
    main_read = 0U;
    main_interrupted = 0U;
    key1 = no_key;
    key2 = no_key;  

    key_main_access = 0U;
    
}


void init_all_vars__key_c(void)
{
    key_main_access = 0U;   /* init ll vars to default state */ 
    key_state = 0U;
    old_col = 1U;
    new_col = 1U;
    new_row = 1U;
    main_read = 0U;
    main_interrupted = 0U;
    key1 = no_key;
    key2 = no_key;  
}