论坛» 嵌入式开发» MCU

分享一个基于状态机的矩阵按键程序(源码)

工程师
2019-07-12 23:05 1楼


支持抬起识别。可以修改支持短按按下识别,短按抬起识别,长按按下识别,长按抬起识别。

支持任何微处理器(MCU、ARM等)


先看电路图:


以下是源码:

void MatrixKeyScan(unsigned char ucKeyValue[4][4])

{

static unsigned char ucKeyState[4][4] = {KEY_STATE_0, KEY_STATE_0, KEY_STATE_0, KEY_STATE_0};

static unsigned char ucKeyTime[4][4] = {0, 0, 0, 0};

unsigned char ucKeyPress[4], i = 0, j = 0;

for(j = 0; j < 4; j++)

{

LineOutCtrl(j, SET);

for(i = 0; i < 4; i++)

{

ColumnScan(i, ucKeyPress);

//printf("\r\n %d %d %d", j, i, ucKeyPress[i]);

switch (ucKeyState[j][i])

{

case KEY_STATE_0:

if (!ucKeyPress[i])

{

ucKeyState[j][i] = KEY_STATE_1;

}

break;


case KEY_STATE_1:

if (!ucKeyPress[i])

{

ucKeyTime[j][i] = 0;

ucKeyState[j][i] = KEY_STATE_2;

}

else

{

ucKeyState[j][i] = KEY_STATE_0;

}

break;


case KEY_STATE_2:

if(ucKeyPress[i])

{

ucKeyState[j][i] = KEY_STATE_0;

}

else

{

ucKeyTime[j][i]++;

if(ucKeyTime[j][i] == 1)

{

ucKeyState[j][i] = KEY_STATE_3;

}

}

break;

case KEY_STATE_3:

if (ucKeyPress[i])

{

ucKeyValue[j][i] = (i + j * 4 + 1);

ucKeyState[j][i] = KEY_STATE_0;

}

else

{

}

break;

default:

break;

}

}

LineOutCtrl(j, RESET);

}

}



void ColumnScan(U8 Index, U8 *KeyPress)

{

switch(Index)

{

case 0:

if(GPIO_ReadInputDataBit(KEYIN1_PORT, KEYIN1_PIN) == RESET)

KeyPress[Index] = 0;//按下

else

KeyPress[Index] = 1;//抬起

break;

case 1:

if(GPIO_ReadInputDataBit(KEYIN2_PORT, KEYIN2_PIN) == RESET)

KeyPress[Index] = 0;

else

KeyPress[Index] = 1;

break;

case 2:

if(GPIO_ReadInputDataBit(KEYIN3_PORT, KEYIN3_PIN) == RESET)

KeyPress[Index] = 0;

else

KeyPress[Index] = 1;

break;

case 3:

if(GPIO_ReadInputDataBit(KEYIN4_PORT, KEYIN4_PIN) == RESET)

KeyPress[Index] = 0;

else

KeyPress[Index] = 1;

break;

default:

break;

}

//printf("\r\n %d %d", Index, KeyPress[Index]);

}


void LineOutCtrl(U8 Index, U8 en)

{

switch(Index)

{

case 0:

if(!en)

GPIO_SetBits(KEYOUT1_PORT, KEYOUT1_PIN);

else

GPIO_ResetBits(KEYOUT1_PORT, KEYOUT1_PIN);

break;

case 1:

if(!en)

GPIO_SetBits(KEYOUT2_PORT, KEYOUT2_PIN);

else

GPIO_ResetBits(KEYOUT2_PORT, KEYOUT2_PIN);

break;

case 2:

if(!en)

GPIO_SetBits(KEYOUT3_PORT, KEYOUT3_PIN);

else

GPIO_ResetBits(KEYOUT3_PORT, KEYOUT3_PIN);

break;

case 3:

if(!en)

GPIO_SetBits(KEYOUT4_PORT, KEYOUT4_PIN);

else

GPIO_ResetBits(KEYOUT4_PORT, KEYOUT4_PIN);

break;

default:

break;

}

}


#define KEYOUT1_PORT GPIOA

#define KEYOUT1_PIN GPIO_Pin_0

#define KEYOUT2_PORT GPIOA

#define KEYOUT2_PIN GPIO_Pin_1

#define KEYOUT3_PORT GPIOA

#define KEYOUT3_PIN GPIO_Pin_2

#define KEYOUT4_PORT GPIOA

#define KEYOUT4_PIN GPIO_Pin_3


#define KEYIN1_PORT GPIOA

#define KEYIN1_PIN GPIO_Pin_4

#define KEYIN2_PORT GPIOA

#define KEYIN2_PIN GPIO_Pin_5

#define KEYIN3_PORT GPIOA

#define KEYIN3_PIN GPIO_Pin_6

#define KEYIN4_PORT GPIOA

#define KEYIN4_PIN GPIO_Pin_7


#define KEY_STATE_0 0

#define KEY_STATE_1 1

#define KEY_STATE_2 2

#define KEY_STATE_3 3

#define KEY_STATE_4 4


#define N_KEY 0xFE


void Task_10ms(void)

{

static U8 ucCount = 0;

U8 ucKeyValue[4][4] = {

{N_KEY, N_KEY, N_KEY, N_KEY},

{N_KEY, N_KEY, N_KEY, N_KEY},

{N_KEY, N_KEY, N_KEY, N_KEY},

{N_KEY, N_KEY, N_KEY, N_KEY}

}, i = 0, j = 0;


MatrixKeyScan(ucKeyValue);

for(j = 0; j < 4; j++)

{

for(i = 0; i < 4; i++)

{

if(ucKeyValue[j][i] != N_KEY)

{

printf("\r\n ucKeyValue 测试计数:%d %d",ucCount++, ucKeyValue[j][i]);

}

}

}

}


工程师
2019-07-12 23:26 2楼

程序通俗易懂,还是不错哦!

助工
2019-07-12 23:28 3楼

谢谢楼主的源码

工程师
2019-07-12 23:30 4楼

太用心啦

菜鸟
2019-07-12 23:34 5楼

学习一下

工程师
2019-07-12 23:36 6楼

对比了楼主的程序,才发现我之前写的程序太LOW了,膜拜一下!

我还要多学习才行!

工程师
2019-07-12 23:54 7楼

之前看到到安福莱的类似程序,单个按键驱动改一下按键的的扫描函数,可支持短按,长按,连发,弹起。

共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]