Re:从零开始的stm32(2、键盘按键识别)

3 篇文章 0 订阅
2 篇文章 0 订阅

高产似那啥
哦,细心的同学们可能会发现又没目录了。我承认我懒,用模板都觉得麻烦在这里插入图片描述
这不还是为了跟上更新进度吗?虽然更新了也没人看啊哈哈哈
我们言归正传,为了实现PWM输出,我们总得用点啥来调占空比,频率啥的吧?总不可能改一次就重新刷程序上去吧。可以

所以我们先教大家在32中按键该如何使用当然不是因为我pwm还没调好

在这里插入图片描述
按键一般就这两种接线方式,所以我们先介绍上拉和下拉。

一般的,当一个按键按下的时候,对应的引脚输入数据是0或1是不确定的,还要看外部电路的组成是上拉还是下拉,当外部电路时上拉的时候,即外部接正的时候,读入的数据是1;当外部电路是下拉的时候,读入的数据是0.

所以上图中可以理解为当键盘按下后key1和key0是下拉,key_up是上拉。

上拉例子:无键按下的时候是1 ,有键按下时是0
下拉例子:无键按下的时候是0 , 有键按下时是1

所以,为了让键盘按下后,我们的MCU能有所反应,我们就应该设置key0和key1上拉输入,这样当没按键摁下时,引脚读数为1,有按键摁下是,就被GND给带成0了。key_up同理。

我这边用的引脚是GPIOE4,3和GPIOA.0
那么我们按照第一章讲的样子,初始化一下IO口吧:

void KEY_Init(void) //IO初始化
{ 
 	GPIO_InitTypeDef GPIO_InitStructure;
 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE时钟

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4|GPIO_Pin_3;//KEY0-KEY1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE4,3

	//初始化 WK_UP-->GPIOA.0	  下拉输入
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉	  
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

}

我估么着这句话你们没看懂

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);

为什么能直接或上它俩呢?
我们右键到它的定义去看看:

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)
  {
    RCC->APB2ENR |= RCC_APB2Periph;
  }
  else
  {
    RCC->APB2ENR &= ~RCC_APB2Periph;
  }
}

嗯,好像看不出啥,那我们看看RCC_APB2Periph_GPIOA是怎么定义的吧
在这里插入图片描述
可以看到这一串数转化成二进制后所占的位是互不干扰的,也就是说A占了低一位,那么剩下的BCDEF等等都不会占用A的低一位了,不信你们可以算算。

而每次调用RCC_APB2PeriphClockCmd这个函数都会执行上图中最下面一行的#define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00))
这是个宏定义,也可以看成一个函数。我把它写成函数形式就是

void IS_RCC_APB2_PERIPH(PERIPH)
{
	(((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00)
}

所以呀,每次调用都会与上0xFFC00002,而每次调用的数值又互不干扰,那为什么就不能直接或上再调用呢?

10011001&11001100 = 10001000
01100110&11001100 = 01000100
10001000|01000100 = 11001100

10011001|01100110 = 11111111
11111111&11001100 = 11001100
10001000|01000100 = 11001100

是不是更明白了?
初始化键盘IO口后,我们就可以写扫描函数了

u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志,并不是按键KEY_UP  
	if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(KEY0==0)return 1;
		else if(KEY1==0)return 2;
		else if(WK_UP==1)return 3;
	}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; 	    
 	return 0;// 无按键按下
}

还是很好理解的
(key_up&&(KEY0==0||KEY1==0||WK_UP==1))这句话是一个简写,写得通俗易懂就是

(key_up&&KEY0==0)|(key_up&&KEY1==0)|(key_up&&KEY_UP==1);

然后就可以直接在主函数调用了

 int main(void)
 {
 	unsigned char key=0;	
	delay_init();	    	 //延时函数初始化	  
	LED_Init();		  		//初始化与LED连接的硬件接口
	BEEP_Init();         	//初始化蜂鸣器端口
	KEY_Init();         	//初始化与按键连接的硬件接口
	LED0=0;					//先点亮红灯
	while(1)
	{
 		key=KEY_Scan(0);	//得到键值
	   	if(key)
		{						   
			switch(key)
			{				 
				case 1:	//控制LED0翻转
					LED0=!LED0;
					break; 
				case 2:	//控制LED1翻转	 
					LED1=!LED1;
					break;
				case 3:	//同时控制LED0,LED1翻转 
					LED0=!LED0;
					LED1=!LED1;
					break;
			}
		}else delay_ms(10); 
	}	 
}

好了,赶快把代码写好去试一试吧!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以利用 STM32 的定时器和外部中断实现按键扫描。具体步骤如下: 1. 定义定时器和外部中断的初始化参数。 ``` TIM_HandleTypeDef htim2; TIM_OC_InitTypeDef sConfigOC; GPIO_InitTypeDef GPIO_InitStruct; EXTI_HandleTypeDef hexti; ``` 2. 初始化定时器和外部中断。 ``` void MX_TIM2_Init(void) { htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 1000; //设定定时器计数周期为1ms htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } } void MX_GPIO_Init(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; //下降沿触发 GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_0) { //按键被按下 } } ``` 3. 启动定时器和外部中断。 ``` HAL_TIM_Base_Start_IT(&htim2); //启动定时器 HAL_NVIC_EnableIRQ(EXTI0_IRQn); //启动外部中断 ``` 4. 在定时器的中断回调函数中进行按键扫描。 ``` void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &htim2) { static uint16_t key_state = 0; //按键状态,0为未按下,1为按下 if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) //按键被按下 { if (key_state == 0) //如果之前未按下 { key_state = 1; HAL_GPIO_EXTI_Callback(GPIO_PIN_0); //调用外部中断回调函数 } } else //按键未被按下 { key_state = 0; } } } ``` 这样就可以实现按键扫描了。需要注意的是,如果有多个按键,可以在中断回调函数中根据不同的 GPIO_Pin 进行区分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值