【3-4】按键控制

使用硬件电路

从此开始,需要开始使用模块化的编程方式(即是建立.c与.h文件)

一、新建组

1.新建组Hardware用于存放硬件驱动代码

2.新建LED.c与LED.h,并且在

(1)LED.c中加入

#include "stm32f10x.h"                  // Device header

(2)在LED.h中加入防止头文件重复包含的代码:

#ifndef _LED_H
#define _LED_H
XXXXXXXXXXXXXXXXXXXX
#endif

用于声明的函数放在"XXXXX"处,而且需要再打完#endif代码后回车,在其后面空上一行(由于该模式无法空行,特此提示)

二、在LED.c中写入LED初始化文件代码

1.GPIOA端口1/2的初始化该代码,与点亮LED中的代码基本相同,只不过是作为函数表示出来,使用和删除更加方便

void LED_Init ()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init (GPIOA,&GPIO_InitStructure);
	
	GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2);
}

2.在.h文件中

加入以下代码:防止头文件重复包含

#ifndef _LED_H
#define _LED_H

#endif


另外#endif需要在后面加上一行空行,减少警告

3.本处共使用两个LED灯,分别接在GPIOA的1、2号位上。使用两个按键,分别接在GPIOB的1、11号位上。

分别利用GPIO_ResetBits(设低电平)与GPIO_SetBits(设高电平)两个函数。其实直接调用两个函数也没有关系,但是为了更为简洁,阅读时的方便,就这样设置了。同样,也作为自己设置函数的联系,类似于C语言学习时期利用函数输出Holle World一样.

void LED1_NO(void)
{
	GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}
void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA,GPIO_Pin_1);
}

之后,同理设置GPIOA的2号位的LED灯的开关函数.

4.如图所示在头文件中进行声明

#ifndef _LED_H
#define _LED_H
void LED_Init (void);  
void LED1_NO(void);
void LED1_OFF(void);
void LED2_NO(void);
void LED2_OFF(void);
#endif

5.在主函数中调用这几个函数,并加入Delay.h用于延时,实现类似于流水灯的效果

int main()
{	
	LED_Init();
	while (1)
	{
		LED1_NO();
		LED2_OFF();
		Delay_ms(500);
		LED1_OFF();
		LED2_NO();
		Delay_ms(500);
		
	}
}

三、建立Key.h 文件,用于接受按键相关函数

1.由图可知,两个按键分别连在PB1与PB11上,即需要初始化这两个端口,并且为了能够获取这两个端口输入的值,所以需要配置为上拉输入模式。初始化方式与前面初始化A1A2端口类似但是此处是作为上拉输入模式初始化端口,其他差别不大

void Key_Init (void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}

2.建立函数,用于存储按键按下带来的信息

①在建立函数之前,先深入了解一下输入函数。

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

a.uint8_t GPIO_ReadInputDataBit(),读取输入数据寄存器的某一位引脚的数据,符合该题仅有两个引脚安有按键的条件,是我们之后会用到的函数

b.uint16_t GPIO_ReadInputData(),读取输入数据寄存器的整个外设,如一整个GPIOB的输入信号。

c.uint8_t GPIO_ReadOutputDataBit(),读取输出数据寄存器的某一位引脚数据,用于探测程序此时在该引脚处输出的电平高低,用于下一步的操作

d.uint16_t GPIO_ReadOutputData(),读取输出寄存器的整个外设

②在这里,我们使用GPIO_ReadInputDataBit函数。

a.定义函数,返回类型为uint8_t,在主函数总使用KeyNum来接受这个值。

uint8_t Key_GetNum(void);

b.我们要区别两个按键按下是的效果,那么可以定义,PB1按键为1号按键,PB11按键为2号按键。对应的,在没有任何按键被按下的情况下,返回值KeyNum为0,保持静默状态。当点击后1号按键后赋值为一,2号按键赋值为2,以此来区分。

c.但是我们使用的按键一般是机械按键,也就是说会有震荡导致按下以及松手的一瞬间都会有一定的震荡,干扰单片机对信息的识别。故而需要加入延时函数,延时20ms即可。而我们在生活中一般都是松手后灯才会亮灭,所以需要加入一个循环函数来检查是否已经松手。按键1与按键2的检测逻辑相同

uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	
	if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0);
		Delay_ms(20);
		KeyNum = 1;
	}
	if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11 ) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0);
		Delay_ms(20);
		KeyNum = 2;
	}
	return KeyNum;
}

③定义一个全局变量来接受Key_GetNum的值,在主函数中引用两个函数,按下按键1保持1号灯亮,按下2号按键使其熄灭

uint8_t KeyNum;

int main()
{	
	Key_Init();
	LED_Init();
	while (1)
	{
		KeyNum = Key_GetNum();
		if (KeyNum == 1)
		{
			LED1_ON();
		}
		if (KeyNum == 2)
		{
			LED1_OFF();
		}
	}
}

④但是如果是让两个按键全部都只服务于LED1又会显得LED2没用,我们接下来会让按键1控制LED1的亮灭,按键2控制LED2的亮灭。

a.这样我们需要一个取反函数,在知道当前LED的状态的前提下,对它的状态进行取反:我们需要先前提及的函数GPIO_ReadOutputDataBit()读取输出数据寄存器的某一位引脚数据

void LED1_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1) == 0)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_1);
	}
	else
  {
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	}
}

b.函数Key_GetNum输出的值都只是有即时效应,按下松手后KeyNum就会恢复默认值0,直到按键1/2再次被按下。此时,我们根据再次按下获得的返回值确定对哪个LED进行取反。

uint8_t KeyNum;

int main()
{	
	Key_Init();
	LED_Init();
	while (1)
	{
		KeyNum = Key_GetNum();
		if (KeyNum == 1)
		{
			LED1_Turn();
		}
		if (KeyNum == 2)
		{
			LED2_Turn();
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值