嵌入式系统实验——【玄武F103开发板】按key1熄灭两个LED灯、松开恢复点亮

项目代码-修改前

一、任务目标

上述压缩包内的项目实现了按下KEY UP按键,LED灯熄灭,松开恢复点亮,要修改原文件夹中的main.c文件,使得按下KEY1开关,LED灯熄灭,松开恢复点亮。

(一)分析

在这里插入图片描述
在这里插入图片描述
首先按钮信号为输入信号,向ODR寄存器写入值,应该设置KEY按钮的端口配置地寄存器(GPIOx_CRL)为输入模式,下面分析KEY1(PE3)采用哪种输入模式:

下面的main.c代码的GPIOA_CRL |= (0x08<<4*0); GPIOA_BRR |= 1;,使得KEY UP设置为输入模式的下拉模式,当松开开关时,KEY UP为低电平,端口输入数据寄存器(IDR)对应的位变为1,执行if语句中的GPIOB_ODR &= (0<<5);GPIOE_ODR &= (0<<5);代码,使小灯点亮,当按下时,WK UP所处电路与VCC3.3导通,此时WK为高电平,端口输入数据寄存器(IDR)对应的位变为0,执行else语句,小灯熄灭。

但是KEY1按钮所处电路与上述WK UP所处电路有不同,其右侧接地,如果设置KEY1(PE3)为输入模式的下拉模式,KEY1为低电平,按下KEY1,按下前后,IDR均为0,无法通过按下按键与否判断小灯的闪灭,因此设置KEY1位输入模式的上拉模式

设置其为上拉模式一般步骤是:
①知道其位于哪个GPIO端口
②开启端口时钟
③清空端口配置低寄存器
④设置端口配置低寄存器。

#include "stm32f10x.h" 
typedef unsigned int u32; 
void delay(u32 i)
{while(i--);}
int main(void)
{	
	delay(0xfffff);
	// 开启GPIOx端口时钟
	RCC_APB2ENR |= (1<<2); 	//A
	RCC_APB2ENR |= (1<<3);	//B
	RCC_APB2ENR |= (1<<6);	//E
	
	// 清空控制PB5、PE5,PA0的端口位
	GPIOB_CRL &= ~( 0x0F<< (4*5));	//PB5
	GPIOE_CRL &= ~( 0x0F<< (4*5));	//PE5
	GPIOA_CRL &= ~( 0x0F<< (4*0));	//PA0
	
	// 配置PB5、PE5位通用推挽输出、速度为10M
	GPIOB_CRL |= (1<<4*5);
	GPIOE_CRL |= (1<<4*5);
	GPIOA_CRL |= (0x08<<4*0);  //PA0为“上拉下拉”输入
	GPIOA_BRR |= 1; // 通过设置ODR为1为上拉,为0则下拉,设置0,下拉
	
	while(1)
	{
		if( (GPIOA_IDR & 0x0001) == 0)
		{
			//输出低,亮灯
			GPIOB_ODR &= (0<<5);
			GPIOE_ODR &= (0<<5);		
		}
		else
		{
			//输出高,灭灯
			GPIOB_ODR |= (1<<5);  
			GPIOE_ODR |= (1<<5);	
		}
	}
}
void SystemInit(void)
{	
}

二、设计思路

(一)开启KEY1对应的GPIOx时钟

1.找到KEY1(PE3)所在的GPIOx端口

在这里插入图片描述
由图可以看出KEYGPIOE端口

2.开启GPIOE端口时钟

源文件已经打开,不需要再进行操作
在这里插入图片描述

3.清空PE3的端口位

在这里插入图片描述
清空的代码如下图,下图代码的逻辑即为把上图中的[15:12]位置为0,这四位即为PE3的对应的寄存器的位(上图中的x即为Ey即为PE3中的3
其他可以实现此功能的代码均可以
在这里插入图片描述

4.设置PE3的端口位为输出模式的上拉模式

设置为输入模式的上拉/下拉模式需要将MODE3[1:0]设置为00CNF3[1:0]设置为10,由于每4位对应一个端口,PE3的处于从低往高位数第44位(从0开始的),原理同上,因此可以使用如下代码:
在这里插入图片描述

但是GPIOE_CRL |= (0x08<<4*3);只是设置了输入模式的上拉/下拉模式,若想设置为上拉模式,还需要设置PE3对应的ODR寄存器,设置ODR1则上拉,为0则下拉(老师说的,还没来得及思考为什么)。
设置寄存器值时,应避免改变寄存器的其他位的值,常采用端口位清除寄存器(BSRR)、端口位设置/清除寄存器(BRR
在这里插入图片描述
在这里插入图片描述

所以采用代码:GPIOE_BSRR |= (1<<3);3是因为PE3中的3),来使得输入模式的上拉/下拉模式变为上拉模式

5.一个易错点!

下图代码中如果不加入划线两条语句,另外四条语句由于没有使用BSRRBRR寄存器,而是对ODR寄存器直接进行操作,如果在这个过程中,改变了PE3对应的ODR的值,则会导致程序逻辑出错,按钮对灯的亮灭不产生影响。(但是划线两条语句不一定都是必要的,本实验过程中偷懒没有做细致研究,以后可能会再深入看一下),除下图写法外,还可采用使用对BSRRBRR寄存器从而改变PE5AE5ODR寄存器的特定位,而不改变其他位的方法,达成实验目的,后续可能会对此部分做补充
if( (GPIOE_IDR & (0x0001<<3)) == 0)是判断PE3(KEY1)对应的输入数据寄存器(IDR)的第3位是否为13是因为PE3中的3IDR寄存器见下下张图片)
在这里插入图片描述
在这里插入图片描述

三、完整代码

(可能有多余的内容,非最优方法)
main.c

#include "stm32f10x.h" 
typedef unsigned int u32; 
lay(u32 i)
{
	while(i--);
}

int main(void)
{	
	delay(0xfffff);
	RCC_APB2ENR |= (1<<2); 	//A
	RCC_APB2ENR |= (1<<3);	//B
	RCC_APB2ENR |= (1<<6);	//E
	
	GPIOB_CRL &= ~( 0x0F<< (4*5));	//PB5
	GPIOE_CRL &= ~( 0x0F<< (4*5));	//PE5
	GPIOA_CRL &= ~( 0x0F<< (4*0));	//PA0
	GPIOE_CRL &= ~( 0x0F<< (4*3));	//PE3

	GPIOB_CRL |= (1<<4*5);
	GPIOE_CRL |= (1<<4*5);
	
	GPIOE_CRL |= (0x08<<4*3);
	GPIOE_BSRR |= (1<<3);
	while(1)
	{
		if( (GPIOE_IDR & (0x0001<<3)) == 0)
		{
			GPIOB_ODR &= (0<<5);
			GPIOE_ODR &= (0<<5);	
			GPIOE_BSRR |= (1<<3);			
		}
		else
		{
			GPIOB_ODR |= (1<<5);  
			GPIOE_ODR |= (1<<5);	
			GPIOE_BSRR |= (1<<3);
	
		}
	}
}
void SystemInit(void)
{	
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值