基于STM32F407最小系统板三种矩阵键盘实现方法

发布者:Asawen最新更新时间:2019-08-16 来源: eefocus关键字:STM32F407  最小系统  矩阵键盘 手机看文章 扫描二维码
随时随地手机看文章

这里采用的八个端口为PA0-PA7。


此处先给出矩阵键盘的原理图:


一、八个端口采用开漏输出,配置上拉电阻,实现同51一样的双向IO口功能。


//按键初始化函数

void KEY_Init(void){

  GPIO_InitTypeDef  GPIO_InitStructure;

 

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA

 

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;

  GPIO_InitStructure.GPIO_Pin|=  GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;

  //这里这么写是因为复制代码块里,太长了,所以分成两部分。

  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;//普通输出模式

  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//开漏输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;//上拉

  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

  

以上初始化配置完成之后,精华部分如下:


/*mode =1代表连按,mode = 0代表单按*/

u8 matrixkey(int mode){

u8 row = 0;

u8 column =0;

static u8 key = 1;

GPIO_Write(GPIOA,0x0F);

if(key&&(GPIO_ReadInputData(GPIOA)&0XFF)!=0X0F){

delay_ms(10);//按下消抖 

column = GPIO_ReadInputData(GPIOA)&0X0F;

GPIO_Write(GPIOA,0xF0);

delay_ms(1);//这个语句超级重要!!!

row = GPIO_ReadInputData(GPIOA)&0XF0;

LCD_ShowNum(100,20,row+column,4,12);

key = 0;

}

if(mode)    key = 1;

if( (GPIO_ReadInputData(GPIOA)&0XFF) == 0X0F){

delay_ms(10); //松手消抖

key = 1;

}

        return row+column;

}

因为配置成端口开漏,上拉电阻模式,


判断第几行的时候,矩阵键盘的1-4行输出逻辑1与5-8行输出的逻辑0,线与为0;


判断第几列的时候,矩阵键盘的5-8行输出逻辑1与1-4行输出的逻辑0,线与为0;


最后得到的行与列相加返回。


区别同51的代码,这里判断按键按下后,有个delay_ms(1)的语句极为重要,不一定需要1ms可以更小,让CPU有一定的反应时间后,再次读取端口电平状态。(也只是推测,具体的原因,以后要深究。)

在主函数里即


int main(void){ 

u8 count =1;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2

delay_init(168);      //初始化延时函数

uart_init(115200); //初始化串口波特率为115200

  LCD_Init();           //初始化LCD FSMC接口

KEY_Init();

LCD_Clear(BLUE);

  while(1) {  

        switch(matrixkey(0)){

                 /*第一行*/

case 0xee:count=count+1; break; case 0xde:count=count+2;break;

case 0xbe:count=count+3; break; case 0x7e:count=count+4;break; 

 

/*第二行*/

case 0xed:count=count+5; break; case 0xdd:count=count+6;break;

case 0xbd:count=count+7; break; case 0x7d:count=count+8;break;  

 

/*第三行*/

case 0xeb:count=count+9; break; case 0xdb:count=count+10;break;

case 0xbb:count=count+11;break; case 0x7b:count=count+12;break;  

                /*第四行*/

case 0xe7:count=count+13;break; case 0xd7:count=count+14;break;

case 0xb7:count=count+15;break; case 0x77:count=count+16;break;  

       }

LCD_ShowNum(100,100,count,4,12);

}

二、动态配置成4行输出,4行输入。


/*四行输出,四列输入*/

void R_Out_C_Input(void){ 

    GPIO_InitTypeDef  GPIO_InitStructure;

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//开漏输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

}

 

/*四列输出,四行输入*/

void C_Out_R_Input(void){  

GPIO_InitTypeDef  GPIO_InitStructure;

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//开漏输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

}

动态配置输入输出的矩阵键盘实现代码如下:


u8 matrixkey(int mode){

u8 row = 0;

u8 column = 0;

static u8 key =1;

GPIO_Write(GPIOA,0); //这里主函数里初始化后,PA0-3输出,PA4-7输入,让PA0-3输出0

if(key&&((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0)){

  delay_ms(10);

  column =  GPIO_ReadInputData(GPIOA)&0XF0; //获取列值

  C_Out_R_Input();//PA0-3输入,PA4-7输出

  delay_ms(1);

  GPIO_Write(GPIOA,0);

  row = GPIO_ReadInputData(GPIOA)&0X0F;//获取行值

  LCD_ShowNum(100,20,row+column,4,12);

  key = 0;

  R_Out_C_Input();//重新配置成低四位输出,高四位输入。

}

if(mode)key = 1;

if( (GPIO_ReadInputData(GPIOA)&0XF0) == 0XF0){

delay_ms(10);//松手消抖

key = 1;

}

        return row+column;

 

}

主函数同上,只不过将KEY_Init();这条语句改为R_Out_C_Input();


三、低四位输出,高四位输入模式固定,逐行扫描,获取1-16按钮。


 主函数同二、,端口初始化配置即void R_Out_C_Input(void);函数


矩阵键盘扫描实现略长,看起来复杂,不过是依葫芦画瓢。


但最重要的是逐行扫描,必须每一行扫描,如果有按键按下,要进行松手检测,否则实现不了。


具体的心得体会,以后回来再改。


while((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0); //松手检测


紧接着delay_ms(10); 松手消除抖动。


u8 matrixkey(int mode){

static u8 key =1;

         GPIO_Write(GPIOA,0x0e); //第一行输出到第五-八行

if(key&&((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0)){

delay_ms(10);

key = 0;

switch(GPIO_ReadInputData(GPIOA)&0xF0){

case 0xe0:return 0xee;

case 0xd0:return 0xde;

case 0xb0:return 0xbe;

case 0x70:return 0x7e;

}

}

while((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0); //松手检测

delay_ms(10);

 

GPIO_Write(GPIOA,0x0d);//第二行输出到第五-八行

if(key&&((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0)){

delay_ms(10);

key = 0;

switch(GPIO_ReadInputData(GPIOA)&0xF0){

case 0xe0:return 0xed;

case 0xd0:return 0xdd;

case 0xb0:return 0xbd;

case 0x70:return 0x7d;

}

}

while((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0);

delay_ms(10);

 

GPIO_Write(GPIOA,0x0b);//第三行输出到第四-八行

if(key&&((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0)){

delay_ms(10);

key = 0;

switch(GPIO_ReadInputData(GPIOA)&0xF0){

case 0xe0:return 0xeb;

case 0xd0:return 0xdb;

case 0xb0:return 0xbb;

case 0x70:return 0x7b;

}

}

while((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0);

delay_ms(10);

 

GPIO_Write(GPIOA,0x07);//第四行输出到第五-八行

if(key&&((GPIO_ReadInputData(GPIOA)&0xF0)!=0xF0)){

delay_ms(10);

key = 0;

switch(GPIO_ReadInputData(GPIOA)&0xF0){

case 0xe0:return 0xe7;

case 0xd0:return 0xd7;

case 0xb0:return 0xb7;

case 0x70:return 0x77;

}

}

if(mode) key =1;

if((GPIO_ReadInputData(GPIOA)&0xF0)==0xF0)

key =1;

return 0;

}

比较:


三种方案其实,第二种方案比较通用,第一种比较简单易懂,前两种都比较好,因为按键按下不松开,并不会影响CPU一直停留在while()循环里啥都不干。


最后的实验效果:


之前用的板子是STM32F107,数据手册中的GPIO口一些输出输入方式的配置与STM32F407有较大不同,这里以STM32F407的为基准。32的单片机跟51不同,51的端口不需要配置成这个端口做输出还是做输入用,双向IO意味着我端口输出XXH(八位),照样可以直接读取到,而32以及PIC系列的单片机,要想读取端口的状态,需要配置成输入模式。


但是32系列的单片机有点好处,即只要设置成开漏输出模式下,再加上拉电阻,采用GPIO_ReadInputData();


即能实现双向IO功能。


针对F407而言,内部的上拉电阻开关,无论是输入还是输出模式都可以打开,所以用第一种方案好。我看了看手册,这里配置成输出模式,并没指明开漏模式下才能端口读取电平状态,应该是两者都可以(通用或者推挽模式)。


而F103系列的,上拉电阻开关只针对输入模式下,(输出模式下,内部上、下拉电阻功能被禁止)如果要实现第一种方案,还需要额外加上拉电阻,麻烦许多,所以用二、三方案比较好。同时读取电平必须要开漏输出。


在此附上F407的输出GPIO手册截图吧:


关键字:STM32F407  最小系统  矩阵键盘 引用地址:基于STM32F407最小系统板三种矩阵键盘实现方法

上一篇:STM32笔记(二)(寄存器)——矩阵键盘
下一篇:基于 STM32F407 使用 4*4 矩阵键盘

推荐阅读最新更新时间:2024-11-04 16:45

PIC单片机最小系统(实物)
1、使用芯片PIC18F25KXX; 2、实物图如下: 3、使用PICKIT3下载器下载程序;使用20pf的贴片电容及4.096无源晶振;外围电路可自行添加 4、亲测可以正常使用; 不过在之前的程序里需要添加配置字,关于配置字有专门的文章
[单片机]
PIC单片机<font color='red'>最小系统</font>(实物)
AVR单片机最小系统 基本硬件线路与分析
基本的AVR硬件线路,包括以下几部分: 1。复位线路 2。晶振线路 3。AD转换滤波线路 4。ISP下载接口 5。JTAG仿真接口 6。电源 7。串口电路 下面以本网站推荐的AVR入门芯片 ATmega16L-8AI 分析上述基本线路。(-8AI表示8M频率的TQFP贴片封装,工业级,更详细的型号含义资料,请参考: AVR芯片入门知识 ) 复位线路的设计(下图上面一部分) Mega16已经内置了上电复位设计。并且在熔丝位里,可以控制复位时的额外时间,故AVR外部的复位线路在上电时,可以设计得很简单:直接拉一只10K的电阻到VCC即可(R6)。 为了可靠,再加上一只0.1uF的电容(C13)以消除干扰、
[单片机]
AVR单片机<font color='red'>最小系统</font> 基本硬件线路与分析
凌阳16位单片机SPCE06lA的最小系统及开发
1 SPCE061A的主要特点 SPCE061A是继μ'nSPTM(Microcontroller and Signal Processor)系列产品SPCE500A等之后,凌阳科技公司推出的又一个16位结构的微控制器芯片。与SPCE500A不同的是,SPCE061A仅内置32k闪存FLASH,其较高的处理速度使1'nSP"能够非常容易地、快速地处理复杂的数字信号,因而特别适用于数字语音识别等应用领域。SPCE061A在2.6V-3.6V工作电压范围内的工作速度范围为0.32-49.152MHz,且具备8通道10位模-数转换输入功能,以及内置自动增益控制功能的麦克风输入方式;同时具有双通道10位DAC方式的音频输出功能。
[单片机]
凌阳16位单片机SPCE06lA的<font color='red'>最小系统</font>及开发
基于stc89c52的4*4矩阵键盘输入数码管
/////////////////////////////////////////////////////////////////////////// 实现功能: 完成独立按键的测试,当key5-key20这二十个按键中,有一个按下时, 则在开发板的第一个数码管上会显示具体的数值,显示的数值是这样 定义的,key5按下时,显示0,key6按下时显示2,然后依次这样类推, 达到按下去相应的值显示相应数值的功能 实验板型号:BS-XYD-C52 实验名称: 静态数码管 编写人: TabLee 编写日期: 2014-3-21 /////////////////////////////////////////
[单片机]
基于stc89c52的4*4<font color='red'>矩阵键盘</font>输入数码管
7. Stm32f407 key外部中断
硬件平台: stm32f407ve 软件平台: win10 (OS Name: Microsoft Windows 10 Enterprise OS Version: 10.0.18363 N/A Build 18363) Keil5 5.26.2 HAL库版本: 2.14.0(目前下载的最新的) 中断这个部分需要参考中文手册和权威指南。 这里我还是提一下NVIC这个东西,全称是Nested vectored interrupt controller,即嵌套向量中断控制器。这个器件是用来管理stm32所有中断的(在现实
[单片机]
7. <font color='red'>Stm32f407</font> key外部中断
AVR 矩阵键盘程序源代码V3.5(有连续按键功能,有组合键功能)
程序特点: 1.有连续按键功能 2.有组合键功能 3.连续按键起始时间和间隔时间自定义 4.可根据需要扩展组合键 使用方法: 将文件 Keypad.h 和 Keypad.c 放入您的工程,将按键需要执行的函数赋值给对应的函数指针 注:需要执行的函数必须为无参数,无返回值 例:您按下A时需要执行以下函数: void fun(void) { printf( 我按下了A ); } 只需执行下列语句 p_Key_A = MenuExit; 并在主循环中调用 KeypadPoll(); 以下是两个文件源码 Keypad.h /******** AVR 4*4矩阵键盘扫描程序 ******** * 版
[单片机]
自制STM8L15x最小系统
STM8L 主打低功耗,对于15x系列产品1.8v就可以驱动芯片正常工作了,Halt模式下面更加可以低至1.65v。最高工作电压3.6v。 一般的自制51的最小系统都要有晶振、复位电路、下载口引出,但是STM8L有内置的16M(HSE)和38k(LSE)的内置RC电路用作发生时钟信号,因此外置晶振都省下了。 此外,15x系列的MCU内部集成了上电复位(POR)、掉电复位(PDR)以及可编程的停机复位(BOR)功能,基本无需外置的复位电路。但是为了稳妥起见,加个自锁开关吧。 所以自制STM8L的最小系统只需要一块贴片元件转接板(0.5mm脚距)、排针、洞洞板、一个自锁开关即可。
[单片机]
stm32f407如何配置外部中断
这几天又重新学了stm32f4,遇到了一个外部配置的实验,实验内容仅作简单的外部中断,读者只要搞懂其中的原理,稍微复杂的中断就能很好解决。 实验内容:按键KEY0按下,触发外部中断,中断函数点亮LED0 现将实验笔记做一个分享。 外部中断需要如下几步(此处我们以正点原子探索者开发板为例) 1)初始化LED灯,按键的GPIO 2)配置NVIC 3)将按键 GPIO 连接到 EXTI 源输入 4)配置按键 EXTI 中断/事件线 5) 编写 EXTI 中断服务函数 正点原子KEY0对应IO口为PE4,LED0对应IO口为PF9. 1)初始化LED灯,按键的GPIO RCC_AHB1PeriphClockCmd(RCC_AHB1
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved