1、基于STM32控制的智能键盘+程序基于STM32控制的智能键盘摘要:本设计选择STM32为核心控制元件,设计了用4个IO口实现4*4矩阵键盘,使用C语言进行编程。矩阵式键盘提高效率进行按键操作管理有效方法,它可以提高系统准确性,有利于资源的节约,降低对操作者本身素质的要求。关键词:STM32 矩阵键盘 ARM 显示电路1 引言 随着21世纪的到来,以前的单个端口连接的按键已经不能满足人们在大型或公共场合的需求。电子信息行业将是人类社会的高科技行业之一,4*4矩阵键盘设计师当今社会中使用的最广的技术之一。4*4矩阵式键盘采用STM32为核心,主要由矩阵式键盘电路、显示电路等组成,软件选用C语言编
2、程。STM32将检测到的按键信号转换成数字量,显示于数码管上。该系统灵活性强,易于操作,可靠性高,将会有更广阔的开发前景。2 总体设计方案 该智能键盘电路由ARM最小系统,矩阵键盘电路和显示电路组成,在常规的4*4矩阵键盘的基础上,通过改进实现了用4个IO口完成4*4矩阵键盘。2.1 总体设计框图本电路主要由3大部分电路组成:矩阵键盘电路、ARM最小系统电路、按键显示电路。其中ATM最小系统主要由复位电路和时钟电路组成。电路复位后数码管显示字符“” 表示没有按键,显示电路由STM32的PD0PD7来控制数码管显示是哪个按键按下。总体设计方框图,如图1所示。STM32 复位电路 矩阵键盘电路 时
3、钟电路 按键显示电路图1总体设计方框图3 智能键盘设计原理分析3.1 STM32复位和时钟电路设计 此电路主要是复位电路和时钟电路两部分,其中复位电路采用按键手动复位和上电自动复位组合,电路如图2(右)所示:其中14脚为STM32的复位端。时钟电路如图2(左)所示:晶振采用的是8MHz和32.786KHz,8MKz分别接STM32的12脚和13脚,32.786KHz分别接STM32的8脚和9脚。图STM复位和时钟电路设计3.2 矩阵键盘电路的设计 该电路的四个端子分别接STM32的PB12PB15,电路如图3所示。图3 矩阵键盘电路该矩阵键盘电路扫描方法如下:(1)PB15,PB14,PB13
4、,PB12设置为输入并内部上拉。程序读取这四个IO口的引脚电平,如果某个IO为低电平,则是该列中相应IO口对应行处的按键按下。(2)PB15输出低电平,PB14,PB13,PB12设置为输入并内部上拉。程序读取PB14,PB13,PB12这三个IO口的引脚电平。如果某个IO为低电平,则是第一列中相应IO口对应行处的按键按下。(3)PB14输出低电平,PB15,PB13,PB12设置为输入并内部上拉。程序读取PB15,PB13,PB12这三个IO口的引脚电平。如果某个IO为低电平,则是第二列中相应IO口对应行处的按键按下。(4)PB13输出低电平,PB15,PB14,PB12设置为输入并内部上拉
5、。程序读取PB15,PB14,PB12这三个IO口的引脚电平。如果某个IO为低电平,则是第三列中相应IO口对应行处的按键按下。(5)PB12输出低电平,PB15,PB14,PB13设置为输入并内部上拉。程序读取PB15,PB14,PB13这三个IO口的引脚电平。如果某个IO为低电平,则是第四列中相应IO口对应行处的按键按下。3.3按键去抖动每隔10ms扫描键盘一次,当扫描某个按键按下时,则开始计数,当连续4次 扫描(也就是40ms)都是这个按键按下时,说明按键有效。如果不到四次计数,就采集不到该按键按下,则说明该按键无效。3.4 按键显示电路本设计采用STM32的IO口PD0PD7来控制数码管
6、来实时显示按键状态。当按键有按下时,数码管将显示对应的按键编号“0F”,对应表示的按键是“SW1SW16”。按键显示电路,如图4。图4 按键显示电路4 程序流程图 程序流程图,如图4所示。 图5 程序流程图5 总体电路图 总体电路图,如图6所示。图6 总体电路图5 总结与体会通过这次矩阵键盘的设计,使我对ARM有了更深的理解。刚开始拿到选题,我先是查找相关资料,从图书馆和网上找到相关的课题,参考借鉴别人的设计,从而理清我们设计的思路。此次作业设计大致可以分为两部分,电路图部分和程序编程部分,其中最有难度的是程序的编写与调试。在编写程序的过程中,我遇到了各种各样的问题,没有总体的思路,对程序不知
7、该如何去编写。我知道知道这个是我的弱点。在接下来的时间,在ARM编程方面,我得需要加强。平时多用Keil uVision4在ARM开发板上进行程序调试,多看一些程序,慢慢的积累,提升自己。 参考文献:1 彭刚、秦志强等.基于ARM Cortex-M3的STM32系列嵌入式微控制器应用实践M.北京:电子工业出版社2 李宁.基于MDK的STM32处理器开发应用 M.北京航空航天大学出版社,2008. 3 4 附录:程序:/* 文件名: main.c* 版本: 1.0* 工作环境: RealView MDK-ARM 4.20* 作者: 河南科技学院* 生成日期: 2012-03-20* 功能: 模版
8、程序(用户可以在这里简单说明工程的功能)* 相关文件: 无* 修改日志: 2012-03-20 创建文档/* * 函数名称 main * 函数说明 主函数 * 输入参数 无 * 输出参数 无 * 返回参数 无 */void Delay_nus(unsigned long n) unsigned long j; while(n-) j=8; while(j-); void Delay_nms(unsigned long n) while(n-) Delay_nus(1100); void Led_GPIO_Config(void) /*定义一个GPIO_InitTypeDef类型的结构体*/ G
9、PIO_InitTypeDef GPIO_InitStructure; /*开启GPIOA的外设时钟*/ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); /*选择要控制的GPIOC引脚*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All ; /*设置引脚模式为通用推挽输出*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*设置引脚速率为50MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_5
10、0MHz; /*调用库函数,初始化GPIOC*/ GPIO_Init(GPIOD, &GPIO_InitStructure); /* 关闭所有led灯 */ GPIO_SetBits(GPIOD, GPIO_Pin_All); void Key_GPIO_Config(void) /*定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef GPIO_InitStructure; /*开启GPIOC的外设时钟*/ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); /*选择要控制的GPIOC引脚*/ G
11、PIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; /*设置引脚模式为通用推挽输出*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*设置引脚速率为50MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIOC*/ GPIO_Init(GPIOD, &GPIO_InitStructure); /* 关闭所有led灯 */ GPIO_SetBi
12、ts(GPIOB, GPIO_Pin_12|GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15); void key_scan(void ) / GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)& GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)& GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)& GPIO_ReadInputD
13、ataBit(GPIOB,GPIO_Pin_15)!=1 ) Delay_nms(5); if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_12)& GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)& GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_14)& GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_15)!=1 ) if( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_0
14、); if( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_1); if( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_2); if( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)=0) GPIO_ResetBits(GPIOB, GPIO_Pin_13); GPIO_ResetBits(GPIOB, GPIO_Pin_12); if(GPIO_Rea
15、dInputDataBit(GPIOB,GPIO_Pin_13) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)!=1) Delay_nms(5); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)!=1) if(GPIO_ReadInputDataBit(GPIOB,GP
16、IO_Pin_13)=0) GPIO_ResetBits(GPIOB, GPIO_Pin_14); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_5); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_6); GPIO_SetBits(GPIOD, GPIO_Pin_2); GPIO_ResetBits(GPIOB, GPIO_Pin_13); if(GPIO_ReadInput
17、DataBit(GPIOB,GPIO_Pin_12) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)!=1) Delay_nms(5); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)!=1) if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin
18、_12)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_7); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_8); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_9); GPIO_SetBits(GPIOD, GPIO_Pin_13); GPIO_ResetBits(GPIOD, GPIO_Pin_14); if(GPIO_ReadInputDataBit
19、(GPIOD,GPIO_Pin_12) &GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_13) &GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_15)!=1) Delay_nms(5); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)!=1) if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)=0)
20、 GPIO_ResetBits(GPIOD, GPIO_Pin_10); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_11); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_12); GPIO_SetBits(GPIOB, GPIO_Pin_14); GPIO_ResetBits(GPIOB, GPIO_Pin_15); if(GPIO_ReadInputDataBit(GP
21、IOB,GPIO_Pin_12) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)!=1) Delay_nms(5); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13) &GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)!=1) if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)=0) GP
22、IO_ResetBits(GPIOD, GPIO_Pin_13); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_14); if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)=0) GPIO_ResetBits(GPIOD, GPIO_Pin_15); GPIO_SetBits(GPIOB, GPIO_Pin_15) ;int main(void) Key_GPIO_Config(); Led_GPIO_Config(); IWDG_WriteAcc
23、essCmd(IWDG_WriteAccess_Enable); /* IWDG counter clock: 40KHz(LSI) / 32 = 1.25 KHz */ /设置IWDG时钟 IWDG_SetPrescaler(IWDG_Prescaler_256); /* Set counter reload value to 349 */ /设置定时器重载值 IWDG_SetReload(300); /* Reload IWDG counter */ /重载IWDG计数器 IWDG_ReloadCounter(); /* Enable IWDG (the LSI oscillator wi
24、ll be enabled by hardware) */ /使能IWDG IWDG_Enable(); while (1) key_scan(); IWDG_ReloadCounter(); #ifdef USE_FULL_ASSERT/* * 函数名称 assert_failed * 函数说明 报告在检查参数发生错误时的源文件名和错误行数 * 输入参数 file: 源文件名 line: 错误所在行数 * 输出参数 无 * 返回参数 无 */void assert_failed(uint8_t* file, uint32_t line) /* 用户可以增加自己的代码用于报告错误的文件名和所在行数, 例如:printf(错误参数值: 文件名 %s 在 %d行rn, file, line) */ /* 无限循环 */ while (1) #endif/*文件结束*/