0

I have not used arduino until now. I thought of interfacing my 4x4 keypad. But when I press keys 1, 4, 7 and *, key values A, B, C and D are sent out to serial terminal respectively. All other keys are working fine. My HW is fine and tested keypad with Atmel Studio. Here is the arduino code. Also attached the schematic. I am using custom shield with arduino nano board on it and pins are marked in the schematic. Shorting links are placed on JP3 and JP2. What could be the reason?

#include <Keypad.h>
#include <util/delay.h>
#include <Wire.h>


const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'D', '#', '0', '*'},
  {'C', '9', '8', '7'},
  {'B', '6', '5', '4'},
  {'A', '3', '2', '1'}
};
byte rowPins[ROWS] = {A0, A1, A2, A3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {12, 3, 2, 13}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {

  char key = keypad.getKey();

  if (key != NO_KEY) {
    Serial.println(key);
  }
}

Edit: Below is the working code I wrote using avrgcc compiler. Note that pinMode is custom macro, works similar to arduino pinMode, but with small difference.

#include "CL_keypad.h"
#include <util/delay.h>


#ifndef IOPORTB
#define IOPORTB 0
#endif
#ifndef IOPORTC
#define IOPORTC 1
#endif
#ifndef IOPORTD
#define IOPORTD 2
#endif

#define IOPB0  0
#define IOPB1  1
#define IOPB2  2
#define IOPB3  3
#define IOPB4  4
#define IOPB5  5
#define IOPB6  6
#define IOPB7  7
#define IOPC0  8
#define IOPC1  9
#define IOPC2  10
#define IOPC3  11
#define IOPC4  12
#define IOPC5  13
#define IOPC6  14
#define IOPC7  15
#define IOPD0  16
#define IOPD1  17
#define IOPD2  18
#define IOPD3  19
#define IOPD4  20
#define IOPD5  21
#define IOPD6  22
#define IOPD7  23

#define IOBitSet(ioport, bit) (((ioport)==IOPORTD)?(PORTD|=1<<(bit)):((ioport)==IOPORTB)?(PORTB|=1<<(bit)):((ioport)==IOPORTC)?(PORTC|=1<<(bit)):0)
#define IOBitClear(ioport, bit) (((ioport)==IOPORTD)?(PORTD&=~(1<<(bit))):((ioport)==IOPORTB)?(PORTB&=~(1<<(bit))):((ioport)==IOPORTC)?(PORTC&=~(1<<(bit))):0)
#define IOBitDirOut(ioport, bit) (((ioport)==IOPORTD)?(DDRD|=1<<(bit)):((ioport)==IOPORTB)?(DDRB|=1<<(bit)):((ioport)==IOPORTC)?(DDRC|=1<<(bit)):0)
#define IOBitDirIn(ioport, bit) (((ioport)==IOPORTD)?(DDRD&=~(1<<(bit))):((ioport)==IOPORTB)?(DDRB&=~(1<<(bit))):((ioport)==IOPORTC)?(DDRC&=~(1<<(bit))):0)
#define IOBitInvert(ioport, bit) (((ioport)==IOPORTD)?(PORTD^=1<<(bit)):((ioport)==IOPORTB)?(PORTB^=1<<(bit)):((ioport)==IOPORTC)?(PORTC^=1<<(bit)):0)

// Read the entire port and return the value read. Individual bits are not tested
#define portRead(ioport) (((ioport)==IOPORTD)?(PIND):((ioport)==IOPORTB)?(PINB):((ioport)==IOPORTC)?(PINC):0)


#define pinMode(pin,mode) (((mode)==OUTPUT)?IOBitDirOut(((pin)/8),((pin%8))):IOBitDirIn(((pin)/8),((pin)%8)))
#define digitalWrite(pin,value) (((value)==LOW)?IOBitClear(((pin)/8),((pin)%8)):IOBitSet(((pin)/8),((pin)%8)))
#define digitalRead(pin) ((portRead((pin)/8))&(1<<((pin)%8))?HIGH:LOW)
#define digitalInvert(pin) (IOBitInvert(((pin)/8),((pin)%8)))

#define NUM_ROWS 4          // Number of rows in the keypad
#define NUM_COLS 4          // number of columns in the keypad
#define NO_KEY_DETECTED '\0'   // When no key is detected, return '\0'
#define SWITCHING_DELAY 1      // 2 msec delay between row switching. 



unsigned char readSwitch(unsigned char columnNum)
{
    //check if key is pressed.
    if(!digitalRead(columnNum))
    {
        //Key De-bounce crude method. To be changed later
        _delay_ms(KEY_DEBOUNCE_TIME);
        if(!digitalRead(columnNum))
        {
            return(1);
        }
    }
    return(0);
}


// Assign port pin numbers  based on the hardware connectivity
uint8_t rowBitNumbers[NUM_ROWS] = {IOPB4,IOPD3,IOPD2,IOPB5};
uint8_t columnBitNumbers[NUM_COLS] = {IOPC0,IOPC1,IOPC2,IOPC3};

        unsigned char keyAssignments[4][4] = {
        {'D', 'C', 'B', 'A'},
        {'.', '9', '6', '3'},
        {'0', '8', '5', '2'},
        {'*', '7', '4', '1'},
    };


    // Initialize keypad need not be called if port pins are not shared
// In case same pins are used as output in some cases, it could be re-initialized.
void initializeKeyPad(void)
{
    unsigned char loopCnt;


    for(loopCnt=0;loopCnt<NUM_ROWS;loopCnt++)
    {
        pinMode(rowBitNumbers[loopCnt],INPUT);
    }


    for(loopCnt=0; loopCnt<NUM_COLS; loopCnt++)
    {
        pinMode(columnBitNumbers[loopCnt],INPUT);
        // In case  of external Pull ups are used, no need to configure row Port pins.
        // Otherwise enable pull ups.

        // Enable pull up resistors if required
        digitalWrite(columnBitNumbers[loopCnt],HIGH);

    }
}

// Function to read the key that is being pressed.
// Returns the value of the key pressed.
// First one row will be set low and then all the columns are read.
// Process is repeated for all the rows.



//////////////////////////////// IMPORTANT   ///////////////////////////////////
// Some delay needs to be given between row switching to avoid capacitance effect

unsigned char getKeyStatus(void)
{
    unsigned char rowLoopCount;
    unsigned char columnLoopCount;
    unsigned char retValue=NO_KEY_DETECTED;
    //Loop for maximum rows configured
    for(rowLoopCount=0;rowLoopCount<NUM_ROWS;rowLoopCount++)
    {
        // Make the Row as output port. So row will be low (No need to set low because default is low)
        pinMode(rowBitNumbers[rowLoopCount],OUTPUT);
        // Give small delay for settling
        _delay_ms(SWITCHING_DELAY);
        //  Read each column.
        for(columnLoopCount=0;columnLoopCount<NUM_COLS;columnLoopCount++)
        {
            //Read  the status of the switch
            if(readSwitch(columnBitNumbers[columnLoopCount]))
            {
                pinMode(rowBitNumbers[rowLoopCount],INPUT);
                return(keyAssignments[rowLoopCount][columnLoopCount]);
            }
            _delay_ms(SWITCHING_DELAY);
        }
        // At the end, change the direction as input so that port goes to high impedance
        pinMode(rowBitNumbers[rowLoopCount],INPUT);
        //CL_delay_mS(SWITCHING_DELAY);
    }
    return(retValue);
}

Here is the Schematic Schematic

  • So you seem to print out the values from the wrong column (leftmost instead of rightmost)? Did you double check the column wiring? – Maximilian Gerhardt Mar 25 '18 at 16:35
  • possible bad keyboard .... connect only one column at a time and test ...... also, get rid of the external pullup resistors and enable the internal pullups – jsotola Mar 25 '18 at 22:17
  • Code written using AVR GCC works fine with same hardware. Updated first post with same code. – Rajesh Mar 25 '18 at 22:32
  • @jsotola Internal pull ups on PC0 to PC3 not enough. I had faced spurious input problems many times without external pull ups. – Rajesh Mar 25 '18 at 22:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.