矩阵键盘的详解之梳理F4总结系列准备篇(一)

目录

一、矩阵键盘的原理图、PCB图

二、矩阵键盘的初始化

三、扫描函数详解


一、矩阵键盘的原理图、PCB图

二、矩阵键盘的初始化

  • PF0到PF3固定为推挽输出,PF12到PF15固定为下拉输入。
  • 即,无键按下时,对应PF12到PF15为0,有键按下时,PF12到PF15中,对应的引脚为高。
/**
  ******************************************************************************
  * @file    main.c
  * @author  Sumjess
  * @version V1.0
  * @date    2019-05-xx
  * @brief   按键应用bsp(扫描模式)
  ******************************************************************************
  * @attention
  *
  * 实验平台   :STM32 F429 
  * CSDN Blog  :https://blog.csdn.net/qq_38351824
  * 微信公众号 :Tech云
  *
  ******************************************************************************
  */ 

/**
  * @brief  配置矩阵按键用到的I/O口
  * @param  无
  * @retval 无     
	* @explain PF0到PF3固定为推挽输出,PF12到PF15固定为下拉输入。即,无键按下时,对应PF12到PF15为0,有键按下时,PF12到PF15中,对应的引脚为高。
  */
void Key4X4_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/*开启按键GPIO口的时钟*/
	RCC_AHB1PeriphClockCmd(KEY_OUT_GPIO_CLK|KEY_IN_GPIO_CLK,ENABLE);
	
/*---------定义PF0到PF3为推挽输出---------*/
	GPIO_InitStructure.GPIO_Pin = KEY_OUT_PIN;         /*选择按键的引脚*/  
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;      /*设置引脚为输出模式*/    
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;	   /*设置引脚的输出类型为推挽输出*/
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   /*设置引脚不上拉也不下拉*/	  
	GPIO_Init(KEY_OUT_GPIO_PORT, &GPIO_InitStructure); /*使用上面的结构体初始化按键*/   
  
/*---------定义PF4到PF7为下拉输入---------*/   
	GPIO_InitStructure.GPIO_Pin = KEY_IN_PIN;           /*选择按键的引脚*/  
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;        /*设置引脚为输入模式*/    
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;      /*设置引脚下拉*/ 
	GPIO_Init(KEY_IN_GPIO_PORT, &GPIO_InitStructure);   /*使用上面的结构体初始化按键*/
}

三、扫描函数详解

解释说明在下面。

/**
  * @brief  矩阵键盘循环扫描
  * @param  无
  * @retval 返回键值     
	* @explain 
  */
//实现矩阵键盘。返回值为,各按键的键值,此键值由用户自己定义。.
int KEY_Scan(void) //实现矩阵键盘。返回值为,各按键的键值,此键值由用户自己定义。
{
	u8 KeyVal;	 //keyVal为最后返回的键值。
	
	GPIO_Write(KEY_OUT_GPIO_PORT,((KEY_OUT_GPIO_PORT->ODR & 0xfff0) | 0x000f)); //先让PF0到PF3全部输出高。
	
	if((KEY_IN_GPIO_PORT->IDR & 0xf000)==0x0000)  //如果PF12到PF15全为0,则没有键按下。此时返回值为-1.
		return -1;
	else
	{	
	    Delay_ms(5);    //延时消抖。
	    if((KEY_IN_GPIO_PORT->IDR & 0xf000)==0x0000)//如果延时5ms后,PF12到PF15又全为0,刚才引脚的电位变化是抖动产生的.
	    return -1;
	}
//////////////////////////////注意:如果程序能运行到下面,证明已经保证有按键按下了////////////////////////////////
	
	GPIO_Write(KEY_OUT_GPIO_PORT,((KEY_OUT_GPIO_PORT->ODR & 0xfff0) | 0x0001));	//让PF3到PF0输出二进制的0001. ===> PF0为高电平,其余为低电平
		switch(KEY_IN_GPIO_PORT->IDR & 0xf000)		        //对PF12到PF15的值进行判断,以输出不同的键值。
		{
			case 0x1000: KeyVal=15; break;
			case 0x2000: KeyVal=11;	break;
			case 0x4000: KeyVal=7;	break;
			case 0x8000: KeyVal=3;	break;
		}
	   
	GPIO_Write(KEY_OUT_GPIO_PORT,((KEY_OUT_GPIO_PORT->ODR & 0xfff0) | 0x0002));	//让PF3到PF0输出二进制的0010. ===> PF1为高电平,其余为低电平
		switch(KEY_IN_GPIO_PORT->IDR & 0xf000)		        //对PF12到PF15的值进行判断,以输出不同的键值。
		{
			case 0x1000: KeyVal=14;	break;
			case 0x2000: KeyVal=10;	break;
			case 0x4000: KeyVal=6;	break;
			case 0x8000: KeyVal=2;	break;
		}

	GPIO_Write(KEY_OUT_GPIO_PORT,((KEY_OUT_GPIO_PORT->ODR & 0xfff0) | 0x0004));	//让PF3到PF0输出二进制的0100. ===> PF2为高电平,其余为低电平
		switch(KEY_IN_GPIO_PORT->IDR & 0xf000)		        //对PF12到PF15的值进行判断,以输出不同的键值。
		{
			case 0x1000: KeyVal=13;	break;
			case 0x2000: KeyVal=9;	break;
			case 0x4000: KeyVal=5;	break;
			case 0x8000: KeyVal=1;	break;
		}
 
	 GPIO_Write(KEY_OUT_GPIO_PORT,((KEY_OUT_GPIO_PORT->ODR & 0xfff0) | 0x0008));	//让PF3到PF0输出二进制的1000. ===> PF3为高电平,其余为低电平
		switch(KEY_IN_GPIO_PORT->IDR & 0xf000)		        //对PF12到PF15的值进行判断,以输出不同的键值。
		{
			case 0x1000: KeyVal=12;	break;
			case 0x2000: KeyVal=8;	break;
			case 0x4000: KeyVal=4;	break;
			case 0x8000: KeyVal=0;	break;
		}									  
	return KeyVal;		
}

GPIO_Write(KEY_OUT_GPIO_PORT,((KEY_OUT_GPIO_PORT->ODR & 0xfff0) | 0x000f)); //先让PF0到PF3全部输出高。

只解释这一句,一通百通。
    1、说明
     运算顺序:->  &  | 
     0xfff0 后面的括号可以不加,但是由于总显示警告,还是加上了。
     0xfff0 =  1111111111110000
     0x000f =  0000000000001111
     ODR:GPIO端口输出数据寄存器
     & :两个数都为1,结果才是1
     | :有一个1,结果就是1
    --------------------------------------------------
    2、作用
     GPIOF->ODR :  GPIOF端口输出数据寄存器
     &  0xfff0  :  保证除了第0位~第3位以外的其他位,不会因下一步操作而受改变    
     |   0x000f  :  使得第0位~第3位变为高电平
    --------------------------------------------------
    3、举例
     例如  引脚F的各个引脚状态依次为1000 1001 0101 1100 ,我现在想使第0位~第3位变成1111,同时让其他位不受影响。
             ① 1000100101011100 = 0x895c
             ② 0x895c & 0xfff0 | 0x000f  这就是答案
             ③ 验证:
              (1)  0x895c & 0xfff0  ===>  1000100101011100 & 1111111111110000 计算答案为 1000100101010000
              (2) 不难发现,将第0位~第3位,变为0了
              (3) 1000100101010000 | 0x000f  ===> 1000100101010000 |  0000000000001111  计算答案为  1000100101011111
             ④ 1000100101011111 与之前的 1000100101011100
 

发布了350 篇原创文章 · 获赞 684 · 访问量 38万+

猜你喜欢

转载自blog.csdn.net/qq_38351824/article/details/103956091
F4