基于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-16 21:44

STM32F407——多功能跑马灯
1、完成多功能跑马灯项目。。 2、预习中断。。 #正点视频第2讲开发板入门,第3讲stm32学习方法,第4讲NVIC中断优先级管理,第28讲外部中断实验-EXTI。。 ##多功能跑马灯 #include sys.h #include delay.h #include usart.h #include led.h #include beep.h #include key.h //ALIENTEK 探索者STM32F407开发板 实验3 //按键输入实验-库函数版本 //技术支持:www.openedv.com //淘宝店铺:http://eboard.taobao.com //广州市星翼电子科技有限公
[单片机]
stm32f407串口通信使用流程
初始化 1.定义初始化变量 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; 2.使能时钟 GPIO开启AHB1时钟 USART1开启APB2时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟 3.配置GPIO端口为引脚复用USA
[单片机]
基于stm32F407 10KHZPWM方波以及PWM周期计算
#include sys.h #include timer.h void TIM4_PWM_Init(u16 arr,u16 psc) { RCC- APB1ENR|=1 2;//使能TIM4 RCC- AHB1ENR|=1 3;//使能GPIOD GPIO_Set(GPIOD,PIN12,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU); GPIO_AF_Set(GPIOD,12,2); TIM4- ARR=arr; TIM4- PSC=psc; TIM4- CCMR1|=6 4;//PWM1 mode
[单片机]
STM32F407 串口接收中断的使用
1 首先,在HAL_UART_MspInit函数当中初始化串口的外设时钟,串口接收中断使能配置,串口IO配置。该函数会由HAL库自行调用。 2 然后,写一个中断入口函数,该函数需要调用HAL库当中的HAL_UART_IRQHandler接口,HAL_UART_IRQHandler中会对中断的标志位进行处理,然后会调用中断回调函数HAL_UART_RxCpltCallback。 3 重写中断回调函数,在该函数当中处理串口缓冲区当中的内容。 4 HAL库的中断使用顺序都大致类似,其它类型的中断处理对坐入号替换就好。
[单片机]
<font color='red'>STM32F407</font> 串口接收中断的使用
STM32F407-获取GPIO电平状态
判断STM32 GPIO输入口的输入状态(高电平或低电平) 以PE2和PE4为例: ① 判断单个端口是否为高电平: if(GPIOE- IDR& GPIO_IDR_IDR2) { 函数体; } 当PE2端口为高电平时,if条件为真;当PE2口为低电平时,if条件为假; ② 判断单个端口是否为低电平: if((~GPIOE- IDR)& GPIO_IDR_IDR2) { 函数体; } 分析:首先通过 &GPIO_IDR_IDR屏蔽掉PE2之外的其他PE口。当PE2为高电平时,GPIO-〉IDR的bit2为‘1’,取反后为‘0’,因此条件为假;当PE2为低电平时,GPIO-〉IDR的
[单片机]
STM32的时钟系统学习笔记(基于STM32F407
RCC(Reset clock Control 复位时钟控制器) 时钟源(时钟生成) 常规:外部晶振、芯片内部振荡器、锁相环(PLL) PS:(Phase Locked Loop): 为锁相回路或锁相环 其他:以太网、USB OTG FS、或其他外设的时钟源 STM32F407时钟树关系图(重点理解经常用到) 时钟总线 RCC通过多个预分频器配置时钟总线 PS:预分频器 (Prescaler-PSC)用来将定时器时钟源进行分频输出 总线类型:AHB、低速APB1、高速APB2 PS: AHB(Advanced High Performance Bus),高级高性能总线 APB(Advanc
[单片机]
STM32的时钟系统学习笔记(基于<font color='red'>STM32F407</font>)
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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