This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Keypad for Msp430g2553

Other Parts Discussed in Thread: MSP430G2553

Hi Everybody,

I have msp430g2553 launchpad and i integrated it with an extern 4x4 keypad.

My development tool is ccs6

for "rows" i use port1 pin 4-7

for "columns" i use port2 pin 0-3

when i press a button, i'm getting some reposnse but not the correct one, and even more then one reponse(due to the for loop)

Is there an example for keypad 4x4? or someone can help me and tell what is wrong with my code?

Thank you.

Here's my code:

#include <msp430g2553.h>


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

	const char rowPins[MATRIX_ROW] = {BIT4, BIT5, BIT6, BIT7};
    const char colPins[MATRIX_ROW] = {BIT0, BIT1, BIT2, BIT3};


    void main(void)
    {
    	//Stop WDT
        WDTCTL = WDTPW + WDTHOLD;

        P1IE |= BIT4 + BIT5 + BIT6 + BIT7;
        P1IES |= BIT4 + BIT5 + BIT6 + BIT7;
        P1IFG &= 0x00;

        P2IE |= BIT0 + BIT1 + BIT2 + BIT3;
        P2IES |= BIT0 + BIT1 + BIT2 + BIT3;
        P2IFG &= 0x00;


        __bis_SR_register(GIE);
    }

    // Port 1 interrupt service routine
    #pragma vector=PORT1_VECTOR
	#pragma vector=PORT2_VECTOR
    __interrupt void PORT_1 (void)
    {
    	int i;
    	int j;
    	for(i=0; i<MATRIX_ROW;i++)
    	{
    		if(P1IFG & rowPins[i])
    		{
    			for(j=0;j<MATRIX_ROW;j++)
    			{
    				if(P2IFG & colPins[j])
    					break; //for breakpoint to see i and j
    			}
    		}
    	}

    	P2IFG &= 0x00;
    	P1IFG &= 0x00;
    }

 

  • Hello,
    I will move your post to the MSP forums, where the experts there can help you best.

    Thanks
    ki
  • Look at this BoosterPack and its source code IR_Learning_Mode, - it contains the handling of 4x4 keypad.

  • Thank you for the reply
    Do i need to buy this keypad or can i use one of my own?
  • Ok Thank you
    About my code above, I'm new at programming into mcu, can you help me to know what is wrong with my code?
    thank you
  • Try to start from programming a single button. 'Push the button' looks very simple but it involves jittering. To eliminate it, you should implement some kind of debouncer using a time delay, Schmitt-Trigger or another type of filter. To read the data from the pin you should configure IO direction to "input-state", which also involves input noise, so it also should be filtered in hardware. The solution of such filer can cause power consumption penalties. And, by the way, keypad can be even encoded.
    So, as I said, I recommend to study "push-the-button" matter from just one button first.

  • PS: then try to study handling of two buttons. Try to make handling of pushing multiple buttons completely independent. (You will discover race-conditioning collision problems and solutions to them). So as I said, this task is not so simple not only to newcomer but to anyone.
  • Link to your keypad is recommended.

    Most of the time a 4x4 matrix involves scanning (providing power) to the column. while reading the rows.

    Double key press will confuse it.

  • Your code has a very common mistake. Your line #30 is followed immediately by the end of main(). This means you give up the CPU to something else that you have no control of. The CPU has no chance to do anything or wait for interrupts under the control of your code after that.

    Your line #34 and #35 may have a problem too. Did CCS give you any warning?

    There are many ways to read the 4x4 keypad. But the way you used will not work. You set up all 4-row and all 4-column pins as input pins. When you press one of the keys on the keypad, one of the row input pins is shorted to one of the column input pins, but nothing (except possibly noise) appears at any of these input pins whether you pressed or not.

    Try, for example, set up the row pins as input with built-in pull-up resisters, and set up the column pins as output pins with 0V level out. This way, when any column pin is shorted with any row pin, that row pin will make a 3V to 0V transition. Thus your code may immediately detect which row is touched. Subsequently, you can change the settings of the column pins so that only one of them is outputting 0V while the other three are floating or pulled up by built-in resister. This way your code can determine which column is touched.

    Show your modified code and I will help you.
  • Hi old_cow

    Thank you for replying.

    After returning to basics and learning again th digital i/o and with your direction.

    I did the code beneath i succeded to get the correct value from the input side but not from the output size (i'm scanning the output size)

    #include <msp430.h> 
    
    /*
     * main.c
     */
    #define P1_3 BIT3
    #define P1_4 BIT4
    #define P1_5 BIT5
    #define P1_7 BIT7
    
    #define P2_0 BIT0
    #define P2_1 BIT1
    #define P2_2 BIT2
    #define P2_3 BIT3
    #define LEN 4
    char matrix[LEN][LEN] ={'1','2','3','4',
    					   '5','6','7','8',
    					   '9','0','a','b',
    					   'c','d','e','f'};
    char ScanKey();
    void main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    
        P2DIR |= (BIT0 + BIT1 + BIT2 + BIT3); // Output Direction p2.0,p2.1,p2.2,p2.3
        P2OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3); // Put output to low
    
        P1DIR &= ~(BIT3 + BIT4 + BIT5 + BIT7); //Input Direction p1.3,p1.4,p1.5,p1.7
        P1REN |= (BIT3 + BIT4 + BIT5 + BIT7);//enable resistor p1.3,p1.4,p1.5,p1.7
        P1OUT |= (BIT3 + BIT4 + BIT5 + BIT7);// set resistor pull up
        P1IES |= (BIT3 + BIT4 + BIT5 + BIT7);//high to low
        P1IE |= (BIT3 + BIT4 + BIT5 + BIT7); //enable interupt
    
        P1IFG = 0;									//Clear Port1 IFG
        P2IFG = 0;									//Clear Port2 IFG
        _EINT();
    }
    
    char ScanKey()
    {
    	unsigned char row_sel=0;
    	unsigned char keyrow=0;
    	unsigned char i=0;
    	unsigned char j=0;
    
    
    	for (i = 0 ; i < LEN ; i ++)// each output
    	{
    		switch(i)
    		{
    		case 0:
    			P2OUT |= BIT0; // output p2.0 is high
    			break;
    		case 1:
    			P2OUT |= BIT1;// output p2.1 is high
    			break;
    		case 2:
    			P2OUT |= BIT2;// output p2.2 is high
    			break;
    		case 3:
    			P2OUT |= BIT3;// output p2.3 is high
    			break;
    		}
    
    		__delay_cycles(100);
    
    		if((P1IN & BIT7))			// find the pressed button row
    			row_sel|=0x08;
    		if((P1IN & BIT5))
    			row_sel|=0x04;
    		if((P1IN & BIT4))
    			row_sel|=0x02;
    		if((P1IN & BIT3))
    			row_sel|=0x01;
    		keyrow = BIT3;
    
    		for (j = 0 ; j< LEN ; j++)
    		{
    			if ((row_sel & keyrow) == 0)
    			{
    				P2DIR |= (BIT0 + BIT1 + BIT2 + BIT3); // Output Direction p2.0,p2.1,p2.2,p2.3
    				P2OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3); // Put output to low
    				return matrix[i][j];
    			}
    
    			keyrow = keyrow >> 1;
    		}
    		row_sel=0;
    
    		switch(i)
    				{
    				case 0:
    					P2OUT &= ~BIT0;// output p2.0 is low
    					break;
    				case 1:
    					P2OUT &= ~BIT1;// output p2.1 is low
    					break;
    				case 2:
    					P2OUT &= ~BIT2;// output p2.2 is low
    					break;
    				case 3:
    					P2OUT &= ~BIT3;// output p2.3 is low
    					break;
    				}
    
    	}
    
    
    	 P2DIR |= (BIT0 + BIT1 + BIT2 + BIT3); // Output Direction p2.0,p2.1,p2.2,p2.3
    	 P2OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3); // Put output to low
    	 return '-';
    }
    
    #pragma vector=PORT1_VECTOR
    __interrupt void port_1(void)
    {
    
        ScanKey();
        P1IFG = 0;									//Clear Port1 IFG
        P2IFG = 0;									//Clear Port2 IFG
    }
    
    

  • You made good progress. Your code is well organized, easy to follow and understand.

    I have to apologize for (a) I did not warn you that you may damage the Port pins under certain conditions and (b) I did not explain the suggested scheme well.

    (a) If you drive one of the four P2 pins high and another one of them low, and if you press two keys on the same P1 pin that connects to those two P2 pins simultaneously, you created a short between high and low. This may destroy those P2 pins. Your line #52, 55, 58, and 61 are dangerous. I hope nothing bad happened yet. Again, my sincere apologies.

    (b) The scheme is using "active low" logic and you did not realize that. The four P1 input pins are normally in the high state due to the internal pull-up resister. When any one of them is connected to a low, that P1 pin will make a high to low transition and generate an interrupt. You normally drive all four P2 output pins low so that any of the 16 key will generate an interrupt when pressed. (You did this correctly.)

    But in order to tell which one of the 16 keys is doing it, you have to do 4 steps to read 4 key per step. (You did that correctly too.). In each step, you have to drive only one of the four P2 pins to low. (You drove one of them high instead. This is incorrect and dangerous too.) At the same time, you have to let the other three P2 pins either as input pins (so that they have high impedance) or as input with internal pull-up. Driving those other three P2 pins high will work, but doing this is dangerous due to (a).

    Also, in reading the four P1IN pins, you incorrectly assumed that they were active high.

    If you have any doubts, please ask. Be careful not to blowup your Port pins.
  • Hi,

    Thank you so much for your time and explenations

    In the scankey method i set all p2 pins to be input (as you said) and each iteration i set one of them to be output, and then read p1IN  and if i found a match i'm sending the matrix value and put p2 pins to be output again.

    And it worked!!! (yes, yes thanks to you)

    But i don't want to blow nothing so it would be great if you can look and give me your opinion

    again thank you so much, you are awsome

    #include <msp430.h> 
    
    /*
     * main.c
     */
    #define P1_3 BIT3
    #define P1_4 BIT4
    #define P1_5 BIT5
    #define P1_7 BIT7
    
    #define P2_0 BIT0
    #define P2_1 BIT1
    #define P2_2 BIT2
    #define P2_3 BIT3
    #define LEN 4
    char matrix[LEN][LEN] ={'1','2','3','4',
    					   '5','6','7','8',
    					   '9','0','a','b',
    					   'c','d','e','f'};
    char ScanKey();
    void main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    
        P2DIR |= (BIT0 + BIT1 + BIT2 + BIT3); // Output Direction p2.0,p2.1,p2.2,p2.3
        P2OUT &=  ~(BIT0 + BIT1 + BIT2 + BIT3); // Put output to low
    
        P1DIR &= ~(BIT3 + BIT4 + BIT5 + BIT7); //Input Direction p1.3,p1.4,p1.5,p1.7
        P1REN |= (BIT3 + BIT4 + BIT5 + BIT7);//enable resistor p1.3,p1.4,p1.5,p1.7
        P1OUT |= (BIT3 + BIT4 + BIT5 + BIT7);// set resistor pull up
        P1IES |= (BIT3 + BIT4 + BIT5 + BIT7);//high to low
        P1IE |= (BIT3 + BIT4 + BIT5 + BIT7); //enable interupt
    
        P1IFG = 0;									//Clear Port1 IFG
        P2IFG = 0;									//Clear Port2 IFG
        _EINT();
    }
    
    char ScanKey()
    {
    	unsigned char row_sel=0;
    	unsigned char keyrow=0;
    	unsigned char i=0;
    	unsigned char j=0;
    
    	P2DIR &= ~(BIT0 + BIT1 + BIT2 + BIT3); //set all p2 pins to be input
    	for (i = 0 ; i < LEN ; i ++)// each output
    	{
    		switch(i)
    		{
    		case 0:
    			P2DIR |= BIT0; // direction p2.0 is output
    			break;
    		case 1:
    			P2DIR |= BIT1;// direction p2.1 is output
    			break;
    		case 2:
    			P2DIR |= BIT2;// direction p2.2 is output
    			break;
    		case 3:
    			P2DIR |= BIT3;// direction p2.3 is output
    			break;
    		}
    
    		__delay_cycles(100);
    
    		if((P1IN & BIT7))			// find the pressed button row
    			row_sel|=0x08;
    		if((P1IN & BIT5))
    			row_sel|=0x04;
    		if((P1IN & BIT4))
    			row_sel|=0x02;
    		if((P1IN & BIT3))
    			row_sel|=0x01;
    		keyrow = BIT3;
    
    		for (j = 0 ; j< LEN ; j++)
    		{
    			if ((row_sel & keyrow) == 0)
    			{
    				P2DIR |= (BIT0 + BIT1 + BIT2 + BIT3); // Output Direction p2.0,p2.1,p2.2,p2.3
    				P2OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3); // Put output to low
    				return matrix[i][j];
    			}
    
    			keyrow = keyrow >> 1;
    		}
    		switch(i)
    		{
    			case 0:
    				P2DIR &= ~BIT0; // direction p2.0 is input
    				break;
    			case 1:
    				P2DIR &= ~BIT1;// direction p2.1 is input
    				break;
    			case 2:
    				P2DIR &= ~BIT2;// direction p2.2 is input
    				break;
    			case 3:
    				P2DIR &= ~BIT3;// direction p2.3 is input
    				break;
    		}
    		row_sel=0;
    
    	}
    
    
    	 P2DIR |= (BIT0 + BIT1 + BIT2 + BIT3); // Output Direction p2.0,p2.1,p2.2,p2.3
    	 P2OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3); // Put output to low
    	 return '-';
    }
    
    #pragma vector=PORT1_VECTOR
    __interrupt void port_1(void)
    {
        P1IFG = 0;									//Clear Port1 IFG
        P2IFG = 0;									//Clear Port2 IFG
    }
    
    

  • In your current code, you are not setting P2 pins in a way that could cause contention. The code is okay in that respect.

    But I think the way you read the P1 input is incorrect. for example, your have:

    if ((P1IN & BIT7)) row row_sel|=0x08;

    This line should have been:

    if ((P1IN & BIT7)==0) row row_sel|=0x08;

**Attention** This is a public forum