原创 stm32 矩阵键盘

2012-3-18 14:45 5052 17 19 分类: MCU/ 嵌入式

//write by dragonbao 2011-9-16.

这是硬件上的键盘规划
// | 1 | 2 | 3 | 4 | ---line 1 PE6 //
// --------------------------- //
// | 5 | 6 | 7 | 8 | ---line 2 PE5 //
// --------------------------- //
// | 9 | 10| 11| 12| ---line 3 PE4 //
// --------------------------- //
// | 13| 14| 15| 16| ---line 4 PE3 //
// --------------------------- //
// | 17| 18| 19| 20| ---line 5 PE2 //
// --------------------------- //
// | | | | //
// col1 col2 col3 col4 //
// PE0 PB5 PB8 PB9 //
//_________________________________________________//

参考了下基于avr的矩阵键盘程序,耐着性子移植到符合上面硬件规划的stm32板子上。

volatile uint8_t key_flag = 0;

void key_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;
//key output
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB,&GPIO_InitStructure);

//key input
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
GPIO_Init(GPIOE,&GPIO_InitStructure);
}


//判断是否有键按下函数,对键盘进行一次扫描
//返回键盘接口状态,有键按下时返回键值;没有键按下返回无效标志位
uint8_t Is_Key_PressOn(void)
{
volatile uint8_t i,ScanCode;
for(i=0;i<4;i++)
{
switch(i) //扫描信号产生
{
case 0:
GPIOE->BSRR = 0x00010000;//PE0 = 0;
GPIOB->BSRR = 0x00000320;//PB5 = 1; PB8 = 1; PB9 = 1;
key_flag = 1;
break;
case 1:
GPIOE->BSRR = 0x00000001;//PE0 = 1;
GPIOB->BSRR = 0x00200300;//PB5 = 0; PB8 = 1; PB9 = 1;
key_flag = 2;
break;
case 2:
GPIOE->BSRR = 0x00000001;//PE0 = 1;
GPIOB->BSRR = 0x01000220;//PB5 = 1; PB8 = 0; PB9 = 1;
key_flag = 3;
break;
case 3:
GPIOE->BSRR = 0x00000001;//PE0 = 1;
GPIOB->BSRR = 0x02000120;//PB5 = 1; PB8 = 1; PB9 = 0;
key_flag = 4;
break;
default: key_flag = 0; break;
}
if((((uint8_t)GPIOE->IDR)|0x83)!=0xff)
return ((uint8_t)GPIOE->IDR | 0x83);
}
return(PRESS_INVALID);
}

//找到闭合键,判断延时前后两次键值是否相同,如果相同则返回键值
uint8_t Find_Key_PressOn(uint8_t KeyCode_before,uint8_t KeyCode_after)
{
if(KeyCode_before==KeyCode_after) return(KeyCode_after);
else return(PRESS_INVALID);
}

//计算键值,根据返回的键值计算相应的返回值
uint8_t Calc_Key_PressOn(uint8_t KeyCode)
{
uint8_t TempNum;
switch(KeyCode)
{
case 0xBF:
if(1==key_flag)
{
TempNum = 1;break;
}
else if(2==key_flag)
{
TempNum = 2;break;
}
else if(3==key_flag)
{
TempNum = 3;break;
}
else if(4==key_flag)
{
TempNum = 4;break;
}
else break;
case 0xDF:
if(1==key_flag)
{
TempNum = 5;break;
}
else if(2==key_flag)
{
TempNum = 6;break;
}
else if(3==key_flag)
{
TempNum = 7;break;
}
else if(4==key_flag)
{
TempNum = 8;break;
}
else break;
case 0xEF:
if(1==key_flag)
{
TempNum = 9;break;
}
else if(2==key_flag)
{
TempNum = 10;break;
}
else if(3==key_flag)
{
TempNum = 11;break;
}
else if(4==key_flag)
{
TempNum = 12;break;
}
else break;
case 0xF7:
if(1==key_flag)
{
TempNum = 13;break;
}
else if(2==key_flag)
{
TempNum = 14;break;
}
else if(3==key_flag)
{
TempNum = 15;break;
}
else if(4==key_flag)
{
TempNum = 16;break;
}
else break;
case 0xFB:
if(1==key_flag)
{
TempNum = 17;break;
}
else if(2==key_flag)
{
TempNum = 18;break;
}
else if(3==key_flag)
{
TempNum = 19;break;
}
else if(4==key_flag)
{
TempNum = 20;break;
}
else break;
default : TempNum=0;break; //发生错误时返回,无效标志
}
return(TempNum); //正常返回值为1~16
}

//键盘扫描主程序
uint8_t Keyboard(void)
{
uint8_t key_temp; //暂存键值的变量
key_temp=Is_Key_PressOn(); //判断是否有键闭合

// PORTC=key_temp; 调试过程中使用,正常运行时没用可以删除
if (key_temp==PRESS_INVALID) //判断该次扫描中是否有键按下
return(PRESS_INVALID); //没有闭合则建立无效标志
else
delay_nus(100); //闭合则延时

key_temp=Find_Key_PressOn(key_temp,((uint8_t)GPIOE->IDR | 0x83)); //找到闭合键
if (key_temp==PRESS_INVALID)
return(key_temp); //若延时前后键值不相等则返回无效标志
else
key_temp=Calc_Key_PressOn(key_temp); //有效则计算键值

while((((uint8_t)GPIOE->IDR)|0x83)!=0xff)//等待键放。。。看实际情况使用
{
delay_nus(10);
}
return(key_temp); //返回键值
}

。。。。。。。

有更好建议或意见的请不吝指出。。。。 

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户377235 2013-9-20 23:36

#include"4x4_key.h" #include"delay.h" u8 Key_Scan(void) { u8 i,j; u16 Buffer[4]={0xfe00,0xfd00,0xfb00,0xf700}; u16 temp; for(j=0;j<4;j++) { GPIOB->ODR&=0x00ff; GPIOB->ODR|=Buffer[j]; temp=0x1000; for(i=0;i<4;i++) { if(!(GPIOB->IDR & temp)) { while(!(GPIOB->IDR & temp)); return(i+j*4); } temp<<=1; } } return(16); } void Key_Init() { GPIOB->CRH=0x88883333; GPIOB->ODR|=0xf000; }

用户1630203 2012-12-14 09:31

楼主很认真,但是方法太繁琐了吧。有简单些方式的。

用户1614644 2012-4-18 15:59

要是有人教我就好了,我就没有这个运气。
相关推荐阅读
用户312232 2012-03-20 19:37
【博客大赛】【原创】 嵌入式开发工具-VS2010 EXPRESS
当提到VS2010作为嵌入式开发工具,替代IAR, Keil等工具时,也许你会感到惊讶,但确实可以,而且更有力,更方便.大家知道用IAR,keil等工具,如果要调试程序的话,还必须具有昂贵的仿真器...
用户312232 2012-03-19 16:25
.net micro framework小小测试
现在的技术真是日新月异,.net能够在普通的微处理器上跑了,感觉挺神气的呢. 下面从基本测试环境搭起. 1. 下载VS2010并安装 2.下载Microsoft NETMF SDK 1...
用户312232 2012-03-18 14:32
IAR printf重定向到usart设置
General Options->Library Configuration的Library要选择Full 不要忘了加上stdio.h头文件 #define PUTCHAR_PROT...
用户312232 2012-03-18 14:25
示波器使用事项1
使用探头的“X1”档时,示波器探头大约相当于一个100pF的电容,这在频率较高时,影响很大,会使信号幅度衰减很多,甚至导致振荡电路停振。 使用“X10”档则会改善很多,因为输入阻抗会增大很多。...
用户312232 2012-03-18 14:07
双系统 删除ubuntu
下载一个MbrFix文件,从下面链接或附件中下载。 在CMD窗口输入 MbrFix /drive 0 fixmbr 按提示选 Y 重启后用分区工具恢复Linux分区。 http:/...
EE直播间
更多
我要评论
2
17
关闭 站长推荐上一条 /3 下一条