项目代码-修改前
上述压缩包内的项目实现了按下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
时钟KEY1(PE3)
所在的GPIOx
端口
由图可以看出KEY
在GPIOE
端口
GPIOE
端口时钟源文件已经打开,不需要再进行操作
PE3
的端口位
清空的代码如下图,下图代码的逻辑即为把上图中的[15:12]
位置为0
,这四位即为PE3
的对应的寄存器的位(上图中的x
即为E
,y
即为PE3
中的3
)
其他可以实现此功能的代码均可以
PE3
的端口位为输出模式的上拉模式设置为输入模式的上拉/下拉模式需要将MODE3[1:0]
设置为00
,CNF3[1:0]
设置为10
,由于每4
位对应一个端口,PE3
的处于从低往高位数第4
个4
位(从0
开始的),原理同上,因此可以使用如下代码:
但是GPIOE_CRL |= (0x08<<4*3);
只是设置了输入模式的上拉/下拉模式,若想设置为上拉模式,还需要设置PE3
对应的ODR
寄存器,设置ODR
位1
则上拉,为0
则下拉(老师说的,还没来得及思考为什么)。
设置寄存器值时,应避免改变寄存器的其他位的值,常采用端口位清除寄存器(BSRR
)、端口位设置/清除寄存器(BRR
)
所以采用代码:GPIOE_BSRR |= (1<<3);
(3
是因为PE3
中的3
),来使得输入模式的上拉/下拉模式变为上拉模式
下图代码中如果不加入划线两条语句,另外四条语句由于没有使用BSRR
和BRR
寄存器,而是对ODR
寄存器直接进行操作,如果在这个过程中,改变了PE3
对应的ODR
的值,则会导致程序逻辑出错,按钮对灯的亮灭不产生影响。(但是划线两条语句不一定都是必要的,本实验过程中偷懒没有做细致研究,以后可能会再深入看一下),除下图写法外,还可采用使用对BSRR
和BRR
寄存器从而改变PE5
、AE5
的ODR
寄存器的特定位,而不改变其他位的方法,达成实验目的,后续可能会对此部分做补充
(if( (GPIOE_IDR & (0x0001<<3)) == 0)
是判断PE3(KEY1)
对应的输入数据寄存器(IDR
)的第3
位是否为1
,3
是因为PE3
中的3
,IDR
寄存器见下下张图片)
(可能有多余的内容,非最优方法)
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)
{
}