嵌入式系统实验——【玄武F103开发板】按key1熄灭两个LED灯、松开恢复点亮
迪丽瓦拉
2024-06-02 03:42:39
0

这里写目录标题

  • 一、任务目标
    • (一)分析
  • 二、设计思路
    • (一)开启`KEY1`对应的`GPIOx`时钟
      • 1.找到`KEY1(PE3)`所在的`GPIOx`端口
      • 2.开启`GPIOE`端口时钟
    • 3.清空`PE3`的端口位
    • 4.设置`PE3`的端口位为输出模式的上拉模式
    • 5.一个易错点!
  • 三、完整代码

项目代码-修改前

一、任务目标

上述压缩包内的项目实现了按下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); 	//ARCC_APB2ENR |= (1<<3);	//BRCC_APB2ENR |= (1<<6);	//E// 清空控制PB5、PE5,PA0的端口位GPIOB_CRL &= ~( 0x0F<< (4*5));	//PB5GPIOE_CRL &= ~( 0x0F<< (4*5));	//PE5GPIOA_CRL &= ~( 0x0F<< (4*0));	//PA0// 配置PB5、PE5位通用推挽输出、速度为10MGPIOB_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); 	//ARCC_APB2ENR |= (1<<3);	//BRCC_APB2ENR |= (1<<6);	//EGPIOB_CRL &= ~( 0x0F<< (4*5));	//PB5GPIOE_CRL &= ~( 0x0F<< (4*5));	//PE5GPIOA_CRL &= ~( 0x0F<< (4*0));	//PA0GPIOE_CRL &= ~( 0x0F<< (4*3));	//PE3GPIOB_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)
{	
}

相关内容