STM32F103五分钟入门系列按键实验(库函数+寄存器)

Posted 自信且爱笑‘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F103五分钟入门系列按键实验(库函数+寄存器)相关的知识,希望对你有一定的参考价值。

学习板:STM32F103ZET6

强推系列:
STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结

STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置

STM32F103五分钟入门系列(三)GPIO的常用库函数使用方法总结+一个网络上的误区

前言

本博总结一下按键实验,设计一个实验,该实验为:
①按下key_up后LED0、LED1交替闪烁,每0.5s闪烁一次,取消按下后,两个灯全灭。

②按下key0后,LED0常亮、蜂鸣器每隔0.5s间断发声。

③按下key2后,LED1常亮,蜂鸣器每隔0.5s间断发声。

④按下key1后,LED0、LED1同时亮,同时灭,且同时灭的时候蜂鸣器发声,同时亮的时候蜂鸣器不发声;间隔1s。

一、原理图分析

本实验用到LED0、LED1、蜂鸣器、key_up、key0、key1、key2:

在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
得到以下信息:

①LED0接PB5,且PB5输出低电平时LED0被点亮,PB5只需输出标准高低电平即可,所有采用通用推挽输出。

②LED1接PE5,且PE5输出低电平时LED1被点亮,PE5只需输出标准高低电平即可,所有采用通用推挽输出。

③蜂鸣器接PB8,高电平发声,PB8只需输出标准高低电平即可,所有采用通用推挽输出。

④key_up接PA0,按下后PA0检测到一个高电平输入,未按下时为悬空状态,而悬空状态IO输入是未知的,所以为了防止程序跑飞,采用下拉输入,在悬空状态下,使IO输入下拉到低电平。这样,在悬空状态下,IO检测到的是低电平,不会去执行key_up按下后的程序。

⑤key0接PE4、key1接PE3、key2接PE2;key0~2按下后,对应引脚检测到低电平输入,未按下时为悬空状态,而悬空状态IO输入是未知的,所以为了防止程序跑飞,采用上拉输入,在悬空状态下,使IO输入上拉到高电平。这样,在悬空状态下,IO检测到的是高电平,不会去执行KEY0 ~2按下后的程序。

二、按键实验(库函数版)

1、LED

led.h代码:

1	//led.h
2	#ifndef LED_H
3	#define LED_H
4	void LED_Init(void);
5
6	#endif
7

led.c代码:

1 	//led.c
2 	#include "sys.h"
3 	#include "stm32f10x.h"
4 	#include "led.h"
5 	void LED_Init(void)
6 	{
7 		GPIO_InitTypeDef GPIO_InitStruct_B;
8 		GPIO_InitTypeDef GPIO_InitStruct_E;
9 		RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE ,ENABLE);
10		
11		GPIO_InitStruct_B.GPIO_Mode=GPIO_Mode_Out_PP;
12		GPIO_InitStruct_B.GPIO_Pin=GPIO_Pin_5;
13		GPIO_InitStruct_B.GPIO_Speed=GPIO_Speed_50MHz;
14		GPIO_Init(GPIOB,&GPIO_InitStruct_B);
15		
16		GPIO_InitStruct_E.GPIO_Mode=GPIO_Mode_Out_PP;
17		GPIO_InitStruct_E.GPIO_Pin=GPIO_Pin_5;
18		GPIO_InitStruct_E.GPIO_Speed=GPIO_Speed_50MHz;
19		GPIO_Init(GPIOE,&GPIO_InitStruct_E);
20		
21		GPIO_SetBits(GPIOB, GPIO_Pin_5);//PB5置高电平
22		//GPIO_WriteBit(GPIOB, GPIO_Pin_5,1);
23		//GPIO_Write(GPIOB,0x0020);              //慎用
24		//PBout(5)=1;
25		GPIO_SetBits(GPIOE, GPIO_Pin_5);//PE5置高电平
26		//GPIO_WriteBit(GPIOE, GPIO_Pin_5,1);
27		//GPIO_Write(GPIOE,0x0020);              //慎用
28		//PEout(5)=1;
29 }

上面代码中,第7、8行分别定义GPIO_Init()的第二个参数,为了方便理解,直接定义了俩个,其实只需要一个就行了。第21、22、23、24行代码都可以给PB5置高电平,让初始状态下LED0灭。同理25、26、27、28行给PE5置高电平。

再讲一下第23、27行代码的0x0020怎么来的,GPIO_Write()在函数里面用到ODR寄存器,第二个参数就是对ODR寄存器配置的16位数。如下图所示。因为这个函数里面对ODR寄存器的配置:“GPIOx->ODR = PortVal”用的是赋值语句,而不是位或语句,所以这个函数要慎用,之前博客也强调过。比如本实验使用到了PB5、PB8,设置PB5时用GPIO_Write()函数,此时PB5输出高电平、PB8输出低电平;在设置PB8时,再用该函数,使PB8输出低电平,但同时又会设置PB5输出低电平,因为在两个不同的.c文件中不好同时设置,所以会对设置造成紊乱。
在这里插入图片描述

2、蜂鸣器

蜂鸣器代码上一博客(四)蜂鸣器总结过了,直接附代码:

头文件:beep.h
代码:

//beep.h
#ifndef BEEP_H
#define  BEEP_H

void BEEP_Init();
#endif

beep.c代码:

1 	//beep.c
2 	#include "beep.h"
3 	#include "stm32f10x.h"
4 	#include "sys.h"
5 
6 	void BEEP_Init(void)
7 	{
8 		GPIO_InitTypeDef GPIO_InitStruct;
9 		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能GPIOB时钟
10		
11		GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
12		GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
13		GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//PB8 IO配置
14		GPIO_Init(GPIOB,&GPIO_InitStruct);
15		
16		GPIO_ResetBits(GPIOB,GPIO_Pin_8);     //初始状态置低电平,关闭蜂鸣器
17		//GPIO_WriteBit(GPIOB,GPIO_Pin_8, 0);//初始状态置低电平,关闭蜂鸣器
18		//GPIO_Write(GPIOB,0);          //初始状态置低电平,关闭蜂鸣器 
19		//PBout(8)=0;                         //初始状态置低电平,关闭蜂鸣器
20	}

3、按键

头文件key.h:

#ifndef KEY_H
#define KEY_H

void KEY_Init(void);

#endif

key.c文件

//key.c
#include "stm32f10x.h"
#include "sys.h"
#include "key.h"
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct_A;
	GPIO_InitTypeDef GPIO_InitStruct_E;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE , ENABLE);//使能GPIOA和GPIOE(PA0 PE2、3、4)
	
	GPIO_InitStruct_A.GPIO_Mode=GPIO_Mode_IPD;
	GPIO_InitStruct_A.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct_A.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct_A);//PA0 key_up  下拉输入
	
	GPIO_InitStruct_E.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct_E.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
	GPIO_InitStruct_E.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOE, &GPIO_InitStruct_E);//PE2、3、4 key0、key1、key2 上拉输入
}

接下来就是主函数了,主函数中实现全部功能:

①按下key_up后LED0、LED1交替闪烁,每0.5s闪烁一次,取消按下后,两个灯全灭。
②按下key0后,LED0常亮、蜂鸣器每隔0.5s间断发声。
③按下key2后,LED1常亮,蜂鸣器每隔0.5s间断发声。
④按下key1后,LED0、LED1同时亮,同时灭,且同时灭的时候蜂鸣器发声,同时亮的时候蜂鸣器不发声;间隔1s。

4、主函数

//main.c
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "beep.h"
 int main(void)
 {
	 LED_Init();
	 BEEP_Init();
	 KEY_Init();
	 delay_init();
	 
	 while(1)
	 {
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))//检测key_up按下
		{
			delay_ms(10);                                 //消抖
			if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))//检测key_up按下
			{
				PBout(5)=0;//点亮LED0
				PEout(5)=1;//熄灭LED1
				delay_ms(500);
				PBout(5)=1; //熄灭LED0
				PEout(5)=0;//点亮LED1
				delay_ms(500);
			}
			if(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))//取消按下key_up后俩个灯都灭
			{
				PBout(5)=1;//熄灭LED0
				PEout(5)=1;//熄灭LED1
			}
		}
		
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0)//key0按下
		{
			delay_ms(10);  
			if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0)//key0按下
			{
				PBout(5)=0;//点亮LED0
				PEout(5)=1;//熄灭LED1
				PBout(8)=1;//蜂鸣器发声
				delay_ms(500);
				PBout(8)=0;//蜂鸣器不发声
				
				delay_ms(500);
			}
			if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)!=0)//取消按下key0后都关闭
			{
				PBout(5)=1;//熄灭LED0
				PEout(5)=1;//熄灭LED1
				PBout(8)=0;//蜂鸣器不发声
			}
		}
		else if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)==0)//key2按下
		{
			delay_ms(10);  
			if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)==0)//key2按下
			{
				PBout(5)=1; //熄灭LED0
				PEout(5)=0;//点亮LED1
				PBout(8)=1;//蜂鸣器发声
				delay_ms(500);
				PBout(8)=0;//蜂鸣器不发声
				delay_ms(500);
			}
			if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)!=0)//取消按下key2后都熄灭
			{
				PBout(5)=1;//熄灭LED0
				PEout(5)=1;//熄灭LED1
				PBout(8)=0;//蜂鸣器不发声
			}
		}
		
		else if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==0)//key1按下
		{
			delay_ms(10);
			if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==0)//key1按下
			{
				PBout(5)=0;//点亮LED0
				PEout(5)=0;//点亮LLED1
				PBout(8)=0; //蜂鸣器不发声
				delay_ms(1000);
				PBout(5)=1;//熄灭LED0
				PEout(5)=1;//熄灭LLED1
				PBout(8)=1; //蜂鸣器发声
				delay_ms(1000);
			}
			if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)!=0)//取消按下key1后都熄灭
			{
				PBout(5)=1;//熄灭LED0
				PEout(5)=1;//熄灭LED1
				PBout(8)=0;//蜂鸣器不发声
			}
		}
	 } 
 }
 

代码中有注释就不再解释了,有点多…

三、按键实验(寄存器版)

1、LED

头文件led.h,与库函数版一样,代码:

//led.h
#ifndef LED_H
#define LED_H
void LED_Init(void);

#endif

led.c编写:

时钟使能,分别为PB5与PE5

	RCC->APB2ENR|=1<<3;
	RCC->APB2ENR|=1<<6;
	//RCC->APB2ENR|=0x0048;

在这里插入图片描述

可以用代码中注释部分一步使能时钟。

led.c完整代码:

//led.c
#include "sys.h"
#include "stm32f10x.h"
#include "led.h"
void LED_Init(void)
{
	RCC->APB2ENR|=1<<3;
	RCC->APB2ENR|=1<<6;
	//RCC->APB2ENR|=0x0048;
	
	GPIOB->CRL&=0xff0fffff;//配置PB5、PE5
	GPIOB->CRL|=0x00300000;
	GPIOE->CRL&=0xff0fffff; //注意一定要清零
	GPIOE->CRL|=0x00300000;
	
	//初始熄灭俩个灯
	GPIOB->ODR|=0x0020;				//ODR寄存器
	GPIOE->ODR|=0x0020;				//ODR寄存器
	
	//GPIOB->ODR|=1<<5;				//ODR寄存器
	//GPIOE->ODR|=1<<5;				//ODR寄存器
	
	//GPIOB->BSRR=0x00000020;			//BSRR寄存器
	//GPIOE->BSRR=0x00000020;			//BSRR寄存器
	
	//GPIOB->BSRR=1<<5;				//BSRR寄存器
	//GPIOE->BSRR=1<<5;				//BSRR寄存器
	
}

其中配置PB5、PE5的十六进制数0x00300000由来如下图:

在这里插入图片描述

使用BSRR寄存器时0x00000020的由来:

在这里插入图片描述

2、蜂鸣器

蜂鸣器代码上一博客(四)蜂鸣器总结过了,直接附代码:

beep.h代码:

1	//beep.h
2	#ifndef BEEP_H
3	#define BEEP_H
4	void BEEP_Init(void);
5	#endif

beep.c代码:

1 	//beep.c
2 	#include "beep.h"
3 	#include "sys.h"
4 	#include "stm32f10x.h"
5 	void BEEP_Init(void)
6 	{
7 		RCC->APB2ENR|=0x0008;      //使能GPIOB时钟
8 		//RCC->APB2ENR|=1<<3;	  //使能GPIOB时钟
9 		//RCC->APB2ENR=1<<3;      //使能GPIOB时钟
10		
11		GPIOB->CRH&=0XFFFFFFF0;
12		GPIOB->CRH|=0x00000003; //配置PB8
13		//GPIOB->CRH=0x00000003; //配置PB8 (不推荐直接赋值)
14
15		GPIOB->ODR&=0xfeff;         //ODR寄存器
16		//GPIOB->ODR&=0xfffe<<8;	//ODR寄存器
17		//GPIOB->BRR|=0x0100;       //BRR寄存器
18		//GPIOB->BRR=0x0100;        //BRR寄存器
19		//GPIOB->BRR|=1<<8;			//BRR寄存器
20		//GPIOB->BRR=1<<8;			//BRR寄存器
21	}
22

3、按键

头文件key.h:

//key.h
#ifndef  KEY_H
#define	 KEY_H
void KEY_Init(void);
#endif

key.c代码:

//key.c
#include "beep.h"
#include "sys.h"
#include "stm32f10x.h"
#include "key.h"

void KEY_Init(void)
{
	RCC->APB2ENR|=0x0044;//FPIOA和GPIOE
	
	GPIOA->CRL&=0xfffffff0;
	GPIOA->CRL|=0x00000008;  //PA0 下拉输入
	GPIOE->CRL&=0XFFF000FF;
	GPIOE->CRL|=0x00088800;  //PE2、PE3、PE4上拉输入
}

时钟配置的16位数由来:

在这里插入图片描述

配置PA0时32位数的由来:

在这里插入图片描述

配置PE2…4的32位数的由来:

在这里插入图片描述

4、主函数

//main.c
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "beep.h"
int main(void)
 {	
	 LED_Init();
	 KEY_Init();
	 BEEP_Init();
	 delay_init();
	 while(1)
	 {
		if((GPIOA->IDR&0x0001)!=0)//检测PA0,key_up  第0位有高电平时!0
		{
			delay_ms(10);
			if((GPIOA->IDR&0x0001)!=0)
			{
				GPIOB->BRR=1<<5;//点亮LED0
				GPIOE->BSRR=1<<5;//熄灭LED1
				delay_ms(500);
				GPIOB->BSRR=1<<5;//熄灭LED0
				GPIOE->BRR=1<<5;//点亮LED1
				delay_ms(500);
			}
			if((GPIOA->IDR&0x0001)==0)
			{
				GPIOB->BSRR=1<<5;//熄灭LED0
				GPIOE->BSRR=1<<5;//熄灭LED1
			}
		}
		 
		if((GPIOE->IDR&0x0010)==0)//检测PE4  key0,若按下,第4位为0.与运算后为0
		{
			delay_ms(10);
			if((GPIOE->IDR&0x0010)==0)
			{
				GPIOB->BRR=1<<5;//点亮LED0
				GPIOE->BSRR=1<<5;//熄灭LED1
				GPIOB->BSRR&=0;//清零  防止操作PB8时影响上面的LED0点亮操作  当然这里是=1<<  而不是|=1<<  所以可以不清零
				GPIOB->BSRR=1<<8;//蜂鸣器发声
				delay_ms(500);
				GPIOB->BRR=1<<8;//蜂鸣器不发声
				delay_ms(500);
			}
			
			if((GPIOE->IDR&am

以上是关于STM32F103五分钟入门系列按键实验(库函数+寄存器)的主要内容,如果未能解决你的问题,请参考以下文章

STM32F103五分钟入门系列蜂鸣器实验(库函数+寄存器)

STM32F103五分钟入门系列(十五)输入捕获(精雕细琢-.-)

STM32F103五分钟入门系列(十六)输入捕获(精雕细琢-.-)

精通《IIC通信》

精通《IIC通信》

STM32F103(二十)DAC(贼详细)