stm32 按键控制灯(使用固件库)

引言

主要是自己最近在学习stm32固件库的使用(对于一定要求不使用固件库的,实际上没有特别必要,因为这是统一官方版的库,就和stdio.h之类的差不多,不过最好也学会自己写,过一段时间,我也会写不使用固件库的)
(后面写了一个中断实现的https://blog.csdn.net/qq_44885018/article/details/103070394

任务要求

1.按键点灯,键按下灯发亮,按键松开,灯熄灭
2.当两个键同时按下的时候,蜂鸣器鸣叫

电路

作为学习单片机或者arm,首先第一件事情是就电路图进行分析
先让我们看看LED的电路图
在这里插入图片描述
先分析一下二极管,二极管负极结的芯片,正极接3.3v的电压,想要二极管发光,就需要芯片输出一个低电平,而且可以从图中看出灯D1-D3对应引脚是PH10-PH12(也就是GPIO口H组的第10-12号引脚)

然后分析一下按键电路
在这里插入图片描述
首先可以从图中看出如果按键没有按下,芯片引脚电平是高电平,而且外部电路提供上拉电阻,内部引脚设置可以是悬空,当按键按下,芯片引脚与地相连,为低电平。实现就是通过读取芯片引脚电平的状态来判断是否按键的(这里的stm32单片机与c51不一样,他的引脚需要设置模式才可以输入读取,而c52只需要直接读或者写就可以)
也可以看到K2用的是GPIO口的A组,0号引脚
K3用的是GPIO口的C组,13号引脚

下面分析一下蜂鸣器的电路图
在这里插入图片描述
在不是硬件设计过程中,我们基本上可以将二级管的状态看成只有两个状态(忽略放大)一个反向截止,一个饱和导通,导通的条件的话就是发射结和集电结均正偏,截止就是均反偏,以后看见这种电路,直接看发射结就可以判断需要什么电平。实现这个三极管很明显是NPN型,所有需要基极高电平,才可以蜂鸣器鸣叫。
而且可以看出基极接的GPIO口为B组5号引脚。

代码

个人建议直接复制,然后用source_insight软件(一款适合写项目代码的软件,不过好像不可以写makefile,shell脚本)
下面代码基本上按照工程规范去书写的,所有可能用了很多宏定义
(注意工程中能用宏,就尽量少用常量)
1.LED的代码和头文件

#ifndef __LED_H__
#define __LED_H__
#define GEC_LED_ON	0
#define GEC_LED_OFF	1
#define GEC_F429_D3 3
#define GEC_F429_D4 4
#define GEC_F429_D5 5
//GEC_led_init:初始化led所使用的端口,默认初始化为高电平
void GEC_led_init(void);

/*GEC_led_ctl:对灯进行控制
 @led_n:表示灯的编号
 例如:GEC_F429_D3:表示LED灯3
 	   GEC_F429_D4:表示LED灯4
 	   GEC_F429_D5:表示LED灯5
 @on_off:表示灯的状态
 例如:
 	GEC_LED_OFF:表示灯灭
 	GEC_LED_ON:	 表示灯亮
*/
void GEC_led_ctl(int led_n,int on_off);


#endif

LEDcode

#include<stdio.h>
#include"led.h"
#include"stm32f4xx.h"
#include"stm32f4xx_gpio.h"
//GEC_led_init:初始化led所使用的端口,默认初始化为高电平
void GEC_led_init(void)
{
	//使能GPIOH端口时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, ENABLE);
	GPIO_InitTypeDef  GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//设置模式为输出模式
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//输出类型为推挽
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//输出速率为50MHz
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;//初始化的引脚为10、11、12
	GPIO_Init(GPIOH,&GPIO_InitStruct);//进行初始化
	//对端口设置默认电平----高电平
	GPIO_WriteBit(GPIOH, GPIO_Pin_10,Bit_SET);
	GPIO_WriteBit(GPIOH, GPIO_Pin_11,Bit_SET);
	GPIO_WriteBit(GPIOH, GPIO_Pin_12,Bit_SET);
	
}
/*GEC_led_ctl:对灯进行控制
 @led_n:表示灯的编号
 例如:GEC_F429_D3:表示LED灯3
 	   GEC_F429_D4:表示LED灯4
 	   GEC_F429_D5:表示LED灯5
 @on_off:表示灯的状态
 例如:
 	GEC_LED_OFF:表示灯灭
 	GEC_LED_ON:	 表示灯亮
*/
void GEC_led_ctl(int led_n,int on_off)
{
	switch (led_n)
	{
		case GEC_F429_D3:
		{
			if(GEC_LED_OFF==on_off)
			{
				GPIO_WriteBit(GPIOH, GPIO_Pin_10,Bit_SET);
			}
			else if(GEC_LED_ON==on_off)
			{
				GPIO_WriteBit(GPIOH, GPIO_Pin_10,Bit_RESET);
			}
			
		}break;
		case GEC_F429_D4:
		{
			if(GEC_LED_OFF==on_off)
			{
				GPIO_WriteBit(GPIOH, GPIO_Pin_11,Bit_SET);
			}
			else if(GEC_LED_ON==on_off)
			{
				GPIO_WriteBit(GPIOH, GPIO_Pin_11,Bit_RESET);
			}
		}break;
		case GEC_F429_D5:
		{
			if(GEC_LED_OFF==on_off)
			{
				GPIO_WriteBit(GPIOH, GPIO_Pin_12,Bit_SET);
			}
			else if(GEC_LED_ON==on_off)
			{
				GPIO_WriteBit(GPIOH, GPIO_Pin_12,Bit_RESET);
			}
		}break;
		default:;
	}
}

2.KEY的代码和头文件

#ifndef __KEY_H__
#define __KEY_H__
#define GEC_F429_K2	2
#define GEC_F429_K3	3
#define GEC_F429_K2_K3 4
#define GEC_KEY_UP	1
#define GEC_KEY_DOWN 0
#define KEY_ALL_DOWN 0
#define KEY_K2_DOWN  1
#define KEY_K3_DOWN  2
#define KEY_ALL_UP 	 3


//GEC_key_init:初始化key所使用的端口
void GEC_key_init(void);

/*
	GEC_key_ctl:实现对按键的状态的监控
	@key_n:用于保存键返回状态的主源
	例如:
		GEC_F429_K2_K3:表示主源为两个键
		GEC_F429_K2:表示主源是键K2
		GEC_F429_K3:表示主源是键k3
	返回值:返回主源键的状态
	例如:
		GEC_KEY_DOWN:表示主源键按下
		GEC_KEY_UP:表示主源键松开
		(注意当主源键为GEC_F429_K2_K3表示两个键按下或者松开,当主源键为一个时表示另一个为松开状态)
*/
int  GEC_key_ctl(int *key_n);
void time_sleep(int x);



#endif

KEY的头文件

#include"key.h"
#include<stdio.h>
#include"stm32f4xx.h"
#include"stm32f4xx_gpio.h"

//GEC_key_init:初始化key所使用的端口
void GEC_key_init(void)
{
	//使能GPIOA、GPIOC端口时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
	//设置模式
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;//设置为输入模式
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;//设置相应端口
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;//输入模式为悬空
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//速率为50MHz
	GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化端口
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;//切换引脚
	GPIO_Init(GPIOC,&GPIO_InitStruct);//切换组号,并且初始化
}
/*
	GEC_key_ctl:实现对按键的状态的监控
	@key_n:用于保存键返回状态的主源
	例如:
		GEC_F429_K2_K3:表示主源为两个键
		GEC_F429_K2:表示主源是键K2
		GEC_F429_K3:表示主源是键k3
	返回值:返回主源键的状态
	例如:
		GEC_KEY_DOWN:表示主源键按下
		GEC_KEY_UP:表示主源键松开
		(注意当主源键为GEC_F429_K2_K3表示两个键按下或者松开,当主源键为一个时表示另一个为松开状态)
*/
int  GEC_key_ctl(int *key_n)
{
	//读取键的电平状态
	uint8_t status_a=GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);//获取键k2的电平
	uint8_t status_c=GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13);//获取键k3的电平
	//将键k2的电平左移1位和键k3的电平组合去满足宏的范围
	/*
		KEY_ALL_DOWN:表示键k2、k3按下
		KEY_K2_DOWN:表示键k2按下,k3松开
		KEY_K3_DOWN:表示键k3按下,k2松开
		KEY_ALL_UP:表示键k2、k3松开
	*/
	status_c+=status_a<<1;
	switch (status_c)
	{
		case KEY_ALL_DOWN:
		{
			*key_n=GEC_F429_K2_K3;
			return GEC_KEY_DOWN;
		}
		case KEY_K2_DOWN:
		{
			*key_n=GEC_F429_K2;
			return GEC_KEY_DOWN;
		}
		case KEY_K3_DOWN:
		{
			*key_n=GEC_F429_K3;
			return GEC_KEY_DOWN;
		}
		case KEY_ALL_UP:
		{
			*key_n=GEC_F429_K2_K3;
			return GEC_KEY_UP;
		}
		default:;
	}
	return GEC_KEY_UP;
}


status_c+=status_a<<1;
语句解释:利用status_c低两个bit为记录按键的所有情况,
例如:status_a表示KEY2的情况,实际上是只有一个bit有用,我们通过左移移位将其加到status_c的第二个bit(1-8bit算),就用两个bit实现所有情况,当然你也可以改,将status_c或者status_a省掉用一个status_c变量就可以实现。
3.蜂鸣器的代码和头文件

#ifndef __BEEP_H__
#define __BEEP_H__
#define GEC_BEEP_ON		1
#define GEC_BEEP_OFF	0
//初始化蜂鸣器端口
void GEC_beep_init(void);

/*
	GEC_beep_ctl:实现对蜂鸣器的控制
	@on_off:表示蜂鸣器的鸣叫或者不鸣
	例如:
		GEC_BEEP_ON:表示蜂鸣器鸣叫
		GEC_BEEP_OFF:表示蜂鸣器不鸣
*/
void GEC_beep_ctl(int on_off);



#endif

蜂鸣器的code

#include<stdio.h>
#include"stm32f4xx.h"
#include"stm32f4xx_gpio.h"
#include"beep.h"
//初始化蜂鸣器端口
void GEC_beep_init(void)
{
	//使能蜂鸣器端口时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//设置蜂鸣器端口为输出模式
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;//将输出模式设置为推挽
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//设置蜂鸣器的端口为pin_5
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//设置输出速率为50MHz
	GPIO_Init(GPIOB,&GPIO_InitStruct);//初始化蜂鸣器端口模式
	GPIO_WriteBit(GPIOB, GPIO_Pin_5,Bit_RESET);//设置默认为蜂鸣器不鸣
}
/*
	GEC_beep_ctl:实现对蜂鸣器的控制
	@on_off:表示蜂鸣器的鸣叫或者不鸣
	例如:
		GEC_BEEP_ON:表示蜂鸣器鸣叫
		GEC_BEEP_OFF:表示蜂鸣器不鸣
*/
void GEC_beep_ctl(int on_off)
{
	if(GEC_BEEP_ON==on_off)
	{
		GPIO_WriteBit(GPIOB, GPIO_Pin_5, Bit_SET);
	}
	else
	{
		GPIO_WriteBit(GPIOB, GPIO_Pin_5,Bit_RESET);
	}
}

4.主函数的代码

#include<stdio.h>
#include"led.h"
#include"key.h"
#include"stm32f4xx.h"
#include"stm32f4xx_gpio.h"
#include"beep.h"
int main()
{
	GEC_led_init();//初始化LED灯
	GEC_key_init();//初始化按键灯
	GEC_beep_init();//初始化蜂鸣器
	int i,key_n;
	while(1)
	{
		i=GEC_key_ctl(&key_n);//判断键的状态
		if(GEC_KEY_DOWN==i)
		{
			switch (key_n)
			{
				case GEC_F429_K2:
				{
					GEC_led_ctl(GEC_F429_D3,GEC_LED_ON);
					GEC_led_ctl(GEC_F429_D4,GEC_LED_OFF);
					GEC_beep_ctl(GEC_BEEP_OFF);
				}break;
				case GEC_F429_K3:
				{
					GEC_led_ctl(GEC_F429_D4,GEC_LED_ON);
					GEC_led_ctl(GEC_F429_D3,GEC_LED_OFF);
					GEC_beep_ctl(GEC_BEEP_OFF);
				}break;
				case GEC_F429_K2_K3:
				{
					GEC_led_ctl(GEC_F429_D4,GEC_LED_ON);
					GEC_led_ctl(GEC_F429_D3,GEC_LED_ON);
					GEC_beep_ctl(GEC_BEEP_ON);
				}break;
				default:;
			}
		}
		else
		{
			GEC_led_ctl(GEC_F429_D4,GEC_LED_OFF);
			GEC_led_ctl(GEC_F429_D3,GEC_LED_OFF);
			GEC_beep_ctl(GEC_BEEP_OFF);
		}
	}
}

结语

也许你会感觉有点疑惑为什么要写的这样麻烦,主要是为了每个代码函数的高内聚低耦合,例如按键,不管怎么样,这个函数只返回按键的情况,至于做什么操作,这是交给主函数去操作。
如果有什么疑问可以留言,看到了,我会尽量解答,如果有什么需要讨论的,也可以留言,欢迎一起讨论

猜你喜欢

转载自blog.csdn.net/qq_44885018/article/details/103050388