【STM32嵌入式系统设计与开发】——6矩阵按键应用(4×4)

这里写目录标题

  • 一、任务描述
  • 二、任务实施
  • 1、SingleKey工程文件夹创建
  • 2、函数编辑
  • (1)主函数编辑
  • (2)LED IO初始化函数(LED_Init())
  • (3)开发板矩阵键盘IO初始化(ExpKeyBordInit())
  • (3)开发板矩阵按键LED控制(ExpKeyBordInit())
  • (4)键盘IO(PE12-PE15)设置为输入模式函数(KeyBordSetIn())
  • (5)键盘IO(PE8-PE11)设置为输出模式函数(KeyBordSetOut())
  • (6)矩阵键盘行列读写操作函数(GPIO_KEY_RW())
  • (7)矩阵键盘键值扫描函数(KeyBoardScan())
  • 3、宏定义
  • (1)源文件添加头文件
  • (2)按键头文件编辑
  • 4、知识链接
  • (1)GPIO_SetBits()
  • (2)GPIO_ResetBits()
  • (3)GPIO_ReadOutputData()
  • (4)GPIO_ReadInputData()
  • 5、工程测试

  • STM32资料包:
    百度网盘下载链接:链接:https://pan.baidu.com/s/1mWx9Asaipk-2z9HY17wYXQ?pwd=8888
    提取码:8888


    一、任务描述

    二、任务实施

    观察电路图,DK1-DK16按键有按下PE8 – PE11端口下拉输入,PE12-PE15输出,按键按下从而组合成16种控制led灯。
    请添加图片描述
    参考排列组合,如同KE1按下时,PE8为与PE12导通。
    请添加图片描述

    1、SingleKey工程文件夹创建

    步骤1:复制工程模板“1_Template”重命名为“4_KeyBoard”

    步骤2:修改项目工程名,先删除projects文件夹内除了Template.uvprojx文件外的所有内容并修改为“KeyBoard.uvprojx”。并删除output/obj和output/lst中的所有文件。

    步骤3:运行“KeyBoard.uvprojx”打开目标选项“Options for Target”中的“Output”输出文件,并修改可执行文件名称为“KeyBoard”点击“OK”保存设置。最后点击“Rebuild”编译该工程生成KeyBoard文件。

    步骤4:复制“2_LEDTest”中的"1_LED"文件复制到hardware中。
    请添加图片描述
    步骤5:新建“2_KeyBoard”文件,并在该文件夹下新建“KeyBoard.c”和“KeyBoard.h”两个文件。
    请添加图片描述
    步骤6:工程组文件中添加“led.c”和“KeyBoard.c”文件。

    步骤7:目标选项添加添加头文件路径

    2、函数编辑

    (1)主函数编辑


    步骤1:端口初始化准备

    	//函数初始化,端口准备
    	delay_init();     //启动滴答定时器,延时函数
    	LED_Init();       //板载LED初始化
        ExpKeyBordInit(); //开发板按键初始化
    

    步骤2:循环工作代码编辑,读取按键并判断按键模式,按下则点亮led灯,否则LED灯熄灭

    	while(1)
    	{
    		KeyValue = ExpKeyScan(0);
    		switch(KeyValue)
    		{
    			case 1:LED_MODE1(KeyValue);
    				break;
    			case 2:LED_MODE1(KeyValue);
    				break;
    			case 3:LED_MODE1(KeyValue);
    				break;
    			case 4:LED_MODE1(KeyValue);
    				break;
    			case 5:LED_MODE1(KeyValue);
    				break;
    			case 6:LED_MODE1(KeyValue);
    				break;
    			case 7:LED_MODE1(KeyValue);
    				break;
    			case 8:LED_MODE1(KeyValue);
    				break;
    			case 9:LED_MODE1(KeyValue);
    				break;
    			case 10:LED_MODE1(KeyValue);
    				break;
    			case 11:LED_MODE1(KeyValue);
    				break;
    			case 12:LED_MODE1(KeyValue);
    				break;
    			case 13:LED_MODE1(KeyValue);
    				break;
    			case 14:LED_MODE1(KeyValue);
    				break;
    			case 15:LED_MODE1(KeyValue);
    				break;
    			case 16:LED_MODE1(KeyValue);
    				break;
    		}
    		
    	}
    

    请添加图片描述

    (2)LED IO初始化函数(LED_Init())

    /*********************************************************************
     @Function  : 开发板LED IO初始化
     @Parameter : N/A 
     @Return    : N/A
    **********************************************************************/
    void ExpLEDInit(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure; // 定义 GPIO 初始化结构体变量
        
        /* 时钟使能 */	
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 GPIOA 时钟
        
        /* 引脚配置 */	
        GPIO_InitStructure.GPIO_Pin = LED_ALL; // D1-D8->PA0-PA7 
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚为推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚的输出速度为 50MHz
        GPIO_Init(GPIOA, &GPIO_InitStructure); // 应用以上配置到 GPIOA 上
        
        GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    }
    

    (3)开发板矩阵键盘IO初始化(ExpKeyBordInit())

    初始化PE8 – PE15端口,并为推挽输出。

    /*********************************************************************
     @Function  : 矩阵键盘IO初始化
     @Parameter : None 
     @Return    : None
    **********************************************************************/
    void ExpKeyBordInit(void)
    {
     	GPIO_InitTypeDef  GPIO_InitStructure;
    	
    	/*时钟使能*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
    	
    	/*引脚配置*/
        GPIO_InitStructure.GPIO_Pin = KEY_ALL;           // 将开发板四个按键连接到PE8~PE15
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置 GPIO 输出速度为 50MHz
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出		 
        GPIO_Init(GPIOE, &GPIO_InitStructure);	
    	
    	/*引脚初始电平设置*/
    	GPIO_SetBits(GPIOE,KEY_ALL);
    }
    

    (3)开发板矩阵按键LED控制(ExpKeyBordInit())

    初始化PE8 – PE15端口,并为推挽输出。

    /*********************************************************************
     @Function  : 开发板矩阵按键LED控制
     @Parameter : KeyValue:矩阵按键状态 
                    每一位表示一个矩阵按键的状态,每位按键对于相应led模式
     @Return    : N/A
    **********************************************************************/
    void LED_MODE1(uint32_t KeyValue)
    {
    	switch(KeyValue)
    	{
    		case 1:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED1 = 0;delay_ms(1000);
    			break;
    		case 2:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED2 = 0;delay_ms(1000);
    		  break;
    		case 3:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED3 = 0;delay_ms(1000);
    			break;
    		case 4:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED4 = 0;delay_ms(1000);
    		  break;
    		case 5:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED5 = 0;delay_ms(1000);
    			break;
    		case 6:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED6 = 0;delay_ms(1000);
    		  break;
    		case 7:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED7 = 0;delay_ms(1000);
    			break;
    		case 8:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED8 = 0;delay_ms(1000);
    		  break;
    		case 9:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED1 = 0;
    		  LED2 = 0;delay_ms(1000);
    			break;
    		case 10:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED3 = 0;
    		  LED4 = 0;delay_ms(1000);
    		  break;
    		case 11:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED5 = 0;
    		  LED6 = 0;delay_ms(1000);
    		  break;
    		case 12:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  LED7 = 0;
    		  LED8 = 0;delay_ms(1000);
    			break;
    		case 13:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  delay_ms(1000);
    		  break;
    		case 14:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    		  for(int i = 0;i < 8;i++)
    			{
    			    PAout(i) = 0;
    				  delay_ms(500);
    			}
    			for(int i = 0;i < 8;i++)
    			{
    			    PAout(i) = 1;
    					delay_ms(500);
    			}
    		  break;
    		case 15:
    			GPIO_SetBits(GPIOA, LED_ALL); // 将 GPIOA 的引脚 PA0-PA7 设置为高电平,使得开发板 LED 灭
    			break;
    	}
    	
    }
    
    
    

    (4)键盘IO(PE12-PE15)设置为输入模式函数(KeyBordSetIn())

    将指定的 GPIO 引脚设置为输入模式,并启用下拉输入。

    /*********************************************************************
     @Function  : 键盘IO设置为输入模式
     @Parameter : KEYIO :要设置的IO
     @Return    : N/A
    **********************************************************************/
    void KeyBordSetIn(uint16_t KEYIO)
    {
     	GPIO_InitTypeDef  GPIO_InitStructure;
    	/*时钟使能*/
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
    	/*引脚配置*/
      GPIO_InitStructure.GPIO_Pin = KEYIO;	           
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;     //下拉输入
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOE, &GPIO_InitStructure);	
    }
    

    (5)键盘IO(PE8-PE11)设置为输出模式函数(KeyBordSetOut())

    将指定的 GPIO 引脚设置为输入模式,并启用下拉输入

    /*********************************************************************
     @Function  : 键盘IO设置为输出模式
     @Parameter : KEYIO :要设置为输出模式的GPIO引脚
     @Return    : N/A
    **********************************************************************/
    void KeyBordSetOut(uint16_t KEYIO)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        /* 使能GPIOE时钟 */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
    
        /* 配置引脚为输出模式 */
        GPIO_InitStructure.GPIO_Pin = KEYIO;    
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOE, &GPIO_InitStructure);
    }
    

    (6)矩阵键盘行列读写操作函数(GPIO_KEY_RW())

    从矩阵键盘中读取按键状态,通过设置特定的 GPIO 引脚为输入或输出模式,并根据参数设置写入行或列,并且根据读取的输入和输出数据返回一个表示按键状态的字节值

    /*********************************************************************
     @Function  : 矩阵键盘行列读写操作
     @Parameter : ReadIo  :读输入的IO
    							WirteIo :写输出的IO
     @Return    : 行列IO输出状态
    **********************************************************************/
    uint8_t GPIO_KEY_RW(uint16_t ReadIo,uint16_t WirteIo)
    {
    	uint16_t Wdata=0,Rdata=0;	
    	//写
    	KeyBordSetOut(KEY_ALL);             //设置IO
    	if(WirteIo==0x0f00)
    		GPIO_SetBits(GPIOE,KEY_LINE);   //写行		 
    	else 
    		GPIO_ResetBits(GPIOE,KEY_LIST); //写列		
    	Wdata = GPIO_ReadOutputData(GPIOE); //读输出	
    	Wdata &= WirteIo;                   //取有效区域
    	
    	//读
    	KeyBordSetIn(ReadIo);               //设置IO 
    	Rdata = GPIO_ReadInputData(GPIOE);  //读输入
    	Rdata &= ReadIo;                    //取有效区域
    	
    	//状态返回	
    	Rdata |= Wdata;                     //合并两次读取的数据
    	return (uint8_t)(Rdata>>8);         //移位返回
    }
    

    (7)矩阵键盘键值扫描函数(KeyBoardScan())

    扫描矩阵键盘的按键状态,通过检测行列按键的组合来确定按下的具体按键,并在按键按下后进行一定的延时消抖处理,最终返回表示按键值的一个字节。

    /*********************************************************************
     @Function  : 矩阵键盘键值扫描
     @Parameter : N/A
     @Return    : 键值
    **********************************************************************/
    uint8_t KeyBoardScan(void)
    {
    	uint8_t KeyValue=0,Key=0;
    	uint8_t a = 0;
    
    	if(GPIO_KEY_RW(KEY_LIST,KEY_LINE)!=0x0f)    //读取按键是否按下
    	{
    		delay_ms(10);//延时10ms进行消抖
    		if(GPIO_KEY_RW(KEY_LIST,KEY_LINE)!=0x0f)//再次检测键盘是否按下
    		{
    			//测试列
    			Key = GPIO_KEY_RW(KEY_LIST,KEY_LINE);
    			switch(Key)
    			{
    				case(0x1F):	KeyValue=1;break;//1列
    				case(0x2F):	KeyValue=2;break;//2列
    				case(0x4F): KeyValue=3;break;//3列
    				case(0x8F):	KeyValue=4;break;//4列
    			}
    			//测试行
    			Key = GPIO_KEY_RW(KEY_LINE,KEY_LIST);
    			switch(Key)
    			{
    				case(0x0E):	KeyValue=KeyValue;break;   //1行
    				case(0x0D):	KeyValue=KeyValue+4;break; //2行
    				case(0x0B): KeyValue=KeyValue+8;break; //3行
    				case(0x07):	KeyValue=KeyValue+12;break;//4行
    			}
    			 //松手检测		
    			while((a<50)&&(Key!=0x00))	
    			{
    				delay_ms(5);
    				Key = GPIO_KEY_RW(KEY_LINE,KEY_LIST);
    			  a+=1;
    			}				
    		}
    	}
    	return KeyValue;
    }
    
    

    3、宏定义

    (1)源文件添加头文件

    步骤1:按键功能文件中添加相关头文件,源文件报错消失部分

    #include "stm32f10x_gpio.h"
    #include "stm32f10x_rcc.h"
    #include ".\delay\delay.h"
    #include "SingleKey.h"
    

    步骤2:主函数添加所需的led和KeyBoard头文件,主源文件部分报错消失

    /***********Hardweare***************/
    #include "led.h"
    #include "KeyBoard.h"
    

    (2)按键头文件编辑

    点击编译显示报错

    步骤1:创建一个宏定义保护

    #ifndef _SINGLEKEY_H
    #define _SINGLEKEY_H
    
    
    
    
    
    #endif
    

    步骤2:添加宏定义

    /******************矩阵键盘IO预定义********************/
    #define  KEY_LINE 	GPIO_Pin_8  | GPIO_Pin_9  | GPIO_Pin_10  | GPIO_Pin_11  	//行
    
    #define  KEY_LIST 	GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14  | GPIO_Pin_15 	//列
    
    #define  KEY_ALL  	GPIO_Pin_8  | GPIO_Pin_9  | GPIO_Pin_10  | GPIO_Pin_11 | \
    										GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14  | GPIO_Pin_15		//行和列
    //行列操作定义
    #define RLine_WList  0 //读行写列
    #define RList_WLine  1 //读列写行
    

    步骤3:添加函数声明

    void    ExpKeyBordInit(void);    //矩阵键盘IO初始化
    uint8_t KeyBoardScan(void);      // 矩阵键盘键值扫描
    


    步骤4:添加数据类型和宏的头文件

    #include <stdint.h>
    //键值枚举
    enum KeyBoard
    {
    	KEY_NO=0,
        KEY_K1,
    	KEY_K2,
    	KEY_K3,
    	KEY_K4,
    	KEY_K5,
    	KEY_K6,
    	KEY_K7,
    	KEY_K8,
    	KEY_K9,
    	KEY_K10,
    	KEY_K11,
    	KEY_K12,
    	KEY_K13,
    	KEY_K14,
    	KEY_K15,
    	KEY_K16
    };
    

    4、知识链接

    (1)GPIO_SetBits()

    将指定的 GPIO 引脚设置为高电平(或逻辑“1”)状态

    void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
    

    (2)GPIO_ResetBits()

    将指定的 GPIO 引脚设置为低电平(或逻辑“0”)状态

    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
    

    (3)GPIO_ReadOutputData()

    这个函数用于读取配置为输出的 GPIO(通用输入/输出)引脚的当前状态。换句话说,它读取当前从配置为输出的 GPIO 引脚驱动出去的数据。

    uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
    

    GPIOx:指定要读取输出数据的 GPIO 端口,如 GPIOA、GPIOB 等

    (4)GPIO_ReadInputData()

    相反,这个函数用于读取配置为输入的 GPIO 引脚的当前状态。它读取当前在配置为输入的 GPIO 引脚上检测到的数据。

    uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
    

    GPIOx:指定要读取输出数据的 GPIO 端口,如 GPIOA、GPIOB 等

    5、工程测试

    作者:iot鑫鹏

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32嵌入式系统设计与开发】——6矩阵按键应用(4×4)

    发表回复