STM32第二课:库函数编程和按键消抖


功能实现

1.设备上电后灯全灭
2.按下按键KEY1,LED1灯亮,再次按下该灯灭。
要求:按键按下时要高效实现,快速触发时也不能失效。


一、库函数编程流程

1.概念了解:

STM32的三种开发模式及各自特点:
1.寄存器:开发周期长,难度大,代码执行效率高。
2.库函数:开发方便,可读性好。
3.Hal库:开发非常快捷方便,代码冗余度高,不利于学习。

2.具体步骤

2.1导入对应的相关库

想要使用库函数编程,首先需要添加对应的标准库。标准库的获取一般由开发商处获取,若没有就要考虑另外两种开发模式。

标准库内一般分为inc文件和src文件

在这里插入图片描述
inc:内涵标准库的各个头文件
src:内涵标准库的源码.c文件

那么究竟该如何导入到工程中呢?
首先对于src文件我们只需在项目中新建一个文件夹(下图中的stdlib即为新建的文件夹),将src中的.c文件添加进去即可。
在这里插入图片描述

对于inc里的头文件,我们需要点击魔法棒,在C/C++中添加该文件路径
在这里插入图片描述
此时,进行Rebuild会发现有错误。
想要解决就需要在C/C++的Define中添加:STM32F10X_HD,USE_STDPERIPH_DRIVER
添加完毕即可使用标准库了。

2.2库函数的查看及使用

库函数:库函数是官方写好的一些API,开发人员可以使用这些接口来快速开发程序。
库函数的本质:封装好的一些具有某种功能的函数,内部其实还是寄存器编写。

首先,我们需要打开固件库使用手册,在目录中找到GPIO库函数的位置
在这里插入图片描述
在图中我们可以看到各个函数名以及作用。
不知道如何使用的话,只需在keil中写出并鼠标右键goto即可。

二、按键消抖

1.消抖前

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "beep.h"
#include "delay.h"

int main()
{
    Led_Init();
    key_Init();
    Beep_Init();
    
    while(1)
    {
			if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
			{	
				Led_Toggle(4);
			}
	}
}

#include "stm32f10x.h"

void Led_Init()
{
	//配置好模式,然后全灭
	//开APB2时钟
	RCC->APB2ENR |= 0X01 << 6;
  //配置PE2--PE5为通用推挽输出
	GPIOE->CRL &=~(0X0F << 20);//PE5
	GPIOE->CRL |= 0X03 << 20;
	GPIOE->CRL &=~(0X0F << 16);//PE4
	GPIOE->CRL |= 0X03 << 16;
  GPIOE->CRL &=~(0X0F << 12);//PE3
	GPIOE->CRL |= 0X03 << 12;
	GPIOE->CRL &=~(0X0F << 8);//PE2
	GPIOE->CRL |= 0X03 << 8;
	//4个引脚均输出高电平
	GPIOE->ODR |= (0x0F << 2);
	
}
//开关灯
void Led1_Ctrl(int flag)
{
  if(!!flag)
	 {
		GPIOE->ODR &= ~(0x0F << 2);
	 }
	else
	 {
		GPIOE->ODR |= (0x0F << 2);
	 }
	 
}

void Led_Toggle(int flag)
{
	GPIOE->ODR ^= 0x01<<(flag+1);
}

此时虽然程序逻辑上没有问题,但手指过快按下按键会导致按键失灵,主要原因是由于按键检测过于敏感,太快了。

2.消抖后

按键消抖就是为了防止这种现象的出现。
加入按键消抖后的主函数代码:

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "beep.h"
#include "delay.h"

int main()
{
    Led_Init();
    key_Init();
    Beep_Init();
	
    while(1)
    {
			
			if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
			{
				Delay_nms(10);
			    if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
				{
				    while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
					{}
					Led_Toggle(4);
				}
			}
    }
}

逻辑解析:当按键按下时按键会先检测KEY1是否发出了一个高电平信号,若发出则等待10毫秒再次检测,以防止误触或错误检测。之后再通过while检测是否为高电平。若不是高电平,则代表按键已经抬起。此时就能确定以及肯定按键被用户按下了。执行LED灯反转操作。

三、完整代码

main.c

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "beep.h"
#include "delay.h"

int main()
{
    Led_Init();
    key_Init();
    Beep_Init();
	
    while(1)
    {
			
			if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
			{
				Delay_nms(10);
				if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
				{
					while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
					{}
					Led_Toggle(4);
				}
			}
    }
}

led.c

#include "stm32f10x.h"

void Led_Init()
{
	//配置好模式,然后全灭
	//开APB2时钟
	RCC->APB2ENR |= 0X01 << 6;
  //配置PE2--PE5为通用推挽输出
	GPIOE->CRL &=~(0X0F << 20);//PE5
	GPIOE->CRL |= 0X03 << 20;
	GPIOE->CRL &=~(0X0F << 16);//PE4
	GPIOE->CRL |= 0X03 << 16;
  GPIOE->CRL &=~(0X0F << 12);//PE3
	GPIOE->CRL |= 0X03 << 12;
	GPIOE->CRL &=~(0X0F << 8);//PE2
	GPIOE->CRL |= 0X03 << 8;
	//4个引脚均输出高电平
	GPIOE->ODR |= (0x0F << 2);
	
}
//开关灯
void Led1_Ctrl(int flag)
{
  if(!!flag)
	 {
		GPIOE->ODR &= ~(0x0F << 2);
	 }
	else
	 {
		GPIOE->ODR |= (0x0F << 2);
	 }
	 
}

void Led_Toggle(int flag)
{
	GPIOE->ODR ^= 0x01<<(flag+1);
}

led.h

#ifndef _LED_H_
#define _LED_H_

void Led_Init();
void Led1_Ctrl(int flag);
void Led_Toggle(int flag);

#endif

key.c

#include "stm32f10x.h"

void key_Init()
{
	//开时钟
	RCC->APB2ENR |= 0x01<<4;//PC
	RCC->APB2ENR |= 0x01<<2;//PA
	//配置模式
	GPIOC->CRL &=~(0X0F << 24);//PC6   key4
	GPIOC->CRL |= 0X04 << 24;
  GPIOC->CRL &=~(0X0F << 20);//PC5   key3
	GPIOC->CRL |= 0X04 << 20;
	GPIOC->CRL &=~(0X0F << 16);//PC4   key2
	GPIOC->CRL |= 0X04 << 16;
	GPIOA->CRL &=~0X0F;//PA0   key1
	GPIOA->CRL |= 0X04;
	
}

int Get_Key_Val(void)
{
	int key_val = 0;
	if(!!(GPIOA->IDR &(0X01 << 0))==1)
		key_val = 1;
	if(!!(GPIOC->IDR &(0X01 << 4))==0)
		key_val = 2;
	if(!!(GPIOC->IDR &(0X01 << 5))==0)
		key_val = 3;
	if(!!(GPIOC->IDR &(0X01 << 6))==0)
		key_val = 4;
	
	return key_val;
}

key.h

#ifndef _KEY_H_
#define _KEY_H_

void key_Init();
int Get_Key_Val(void);

#endif

delay.c

#include "stm32f10x.h"
#include "delay.h"

void Delay_nus(uint32_t time)
{
    uint32_t i=0;
    for(i=0;i<time;i++){
        delay1us();
    }    
}

void Delay_nms(uint32_t time)
{
    uint32_t i=0;
    for(i=0;i<time;i++){
         Delay_nus(1000);//延时1ms
    }    
}

delay.h

#ifndef _DELAY_H_
#define _DELAY_H_
#include "stm32f10x.h"

#define delay1us() {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}

void Delay_nus(uint32_t time);
void Delay_nms(uint32_t time);
#endif
		

四、总结

1.了解了STM32各个开发模式的区别以及特点。
2.学会了如何对STM32进行库函数开发。
3.学会了如何对按键操作进行按键消抖。
4.学会了如何通过异或操作进行器件反转。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值