stm32的GPIO口PA0按键没按下就是低电平的分析

芯片:stm32f407ZET6X
功能:实现两按键分别控制四个灯和一个蜂鸣器
思路:将寄存器设置封装成函数,体会固件库的实现原理

踩坑记录:下载程序后发现与PA0连接的按键,还没按下按键,就出现了灯闪,蜂鸣器响,正常逻辑应该是按下按键,PA0口接地,此时才灯亮。

原因分析:因为初始化PA0口时没有使能A组的时钟(RCC_AHB1ENR |= (0x01); 漏写或还未写),所以,上拉设置对A组IO口无效,我发现GPIO口在未使能的状态下,是低电平,猜想默认是下拉吗???。对于输入口,不要尝试置位或复位,因为输入模式下,GPIOx->GPIOx_IDR(端口输入寄存器)是只读的。

//#include "reg_stm32.h"


/**/
#define PRI_BASEADDR 0x40000000

/*AHB1总线时钟使能相关*/
#define AHB1_BASEADDR (PRI_BASEADDR + 0x20000)


#define RCC_BASEADDR  (AHB1_BASEADDR+0x3800)
#define RCC_AHB1ENR  *((unsigned int *)(RCC_BASEADDR+0x30))//使能时钟寄存器

#define GPIOA_BASEADDR (AHB1_BASEADDR+0x0000)// IO口基地址
#define GPIOE_BASEADDR (AHB1_BASEADDR+0x1000)
#define GPIOF_BASEADDR (AHB1_BASEADDR+0x1400)


//构造一个结构体
typedef struct {
	unsigned int GPIOx_MODER;  //0x00
	unsigned int GPIOx_OTYPER; //0x04
	unsigned int GPIOx_OSPEEDR;//0x08
	unsigned int GPIOx_PUPDR;  //0x0c
	unsigned int GPIOx_IDR;    //0x10,只读
	unsigned int GPIOx_ODR;    //0x14
	//...
}GPIOx_TypeDef;

#define GPIOA ((GPIOx_TypeDef *)GPIOA_BASEADDR)//宏名代表结构体地址
#define GPIOE ((GPIOx_TypeDef *)GPIOE_BASEADDR)
#define GPIOF ((GPIOx_TypeDef *)GPIOF_BASEADDR)

/*针对输出口的初始化,BEEP和LED*/
void GPIO_Out_Init(GPIOx_TypeDef * GPIOx, unsigned char PIN)
{
	//使能RCC时钟,**重点**
	RCC_AHB1ENR |= (0x01<<4);//使能E组GPIO口
	RCC_AHB1ENR |= (0x01<<5);//使能F组GPIO口
	
	//端口模式,输出--01
	GPIOx->GPIOx_MODER &= ~(0x03<<PIN*2);//多位,先清零,后置位
	GPIOx->GPIOx_MODER |=  (0x01<<PIN*2);//后置位
	
	//如果是输出模式,则输出类型---推挽--x=0
	GPIOx->GPIOx_OTYPER &= ~(0x01<<PIN);//与0得0
	
	//输出速度
		GPIOx->GPIOx_OSPEEDR &= ~(unsigned int)(0x03<<PIN*2);
	    GPIOx->GPIOx_OSPEEDR |=  (unsigned int)(0x01<<PIN*2);	
	
	//5.配置 PF8 引脚为上拉 ,这个影响不大可以忽略
	GPIOx->GPIOx_PUPDR &= ~(unsigned int)(0x03<<PIN*2);
	GPIOx->GPIOx_PUPDR |=  (unsigned int)(0x01<<PIN*2);

}


/*针对输入口的初始化,KEY0~KEY4*/

void GPIO_In_Init(GPIOx_TypeDef * GPIOx, unsigned char PIN)
{
	//使能RCC时钟,**重点**
	RCC_AHB1ENR |= (0x01<<4);//使能E组GPIO口
	RCC_AHB1ENR |= (0x01<<5);//使能F组GPIO口
	RCC_AHB1ENR |= (0x01);   //使能A组GPIO口,输入模式就是只读,不可再ResetBits或SetBits设置IO口**重点**
	
	//配置IO口为输入模式
	GPIOx->GPIOx_MODER &= ~(0x03<<PIN*2);

	//设置为上拉
	GPIOx->GPIOx_PUPDR &= ~(unsigned int)(0x03<<PIN*2);
	GPIOx->GPIOx_PUPDR |=  (unsigned int)(0x01<<PIN*2);
	
}

//输出1
void GPIO_SetBits(GPIOx_TypeDef *GPIOx ,unsigned char Pin)
{
	GPIOx->GPIOx_ODR |= (0x01<<Pin);
}

//输出0
void GPIO_ResetBits(GPIOx_TypeDef *GPIOx ,unsigned char Pin)
{
	GPIOx->GPIOx_ODR &= ~(0x01<<Pin);
}

//读取按键所连接端口的电平
unsigned int GPIO_ReadInputDataBit(GPIOx_TypeDef *GPIOx ,unsigned char Pin)
{
    //判断某一组的 某一个 GPIO 口的电平
	if( GPIOx->GPIOx_IDR & (0x1<<Pin) )
	{
		return 1;
	}else{
		return 0;
	}
}

void BEEP_Init(void)
{
	
    GPIO_Out_Init(GPIOF, 8);//蜂鸣器
	//初始不响,**重点**
	GPIO_ResetBits(GPIOF ,8);
}


void LED_Init(void)
{
	GPIO_Out_Init(GPIOF, 9);//led0
	GPIO_Out_Init(GPIOF, 10);//led1
    GPIO_Out_Init(GPIOE, 13);//led2
	GPIO_Out_Init(GPIOE, 14);//led3
	
	
    //初始不亮,**重点**
	GPIO_SetBits(GPIOF ,9);
	GPIO_SetBits(GPIOF ,10);
	GPIO_SetBits(GPIOE ,13);
	GPIO_SetBits(GPIOE ,14);
}


void KEY_Init(void)
{
	GPIO_In_Init(GPIOA ,0);//key0
	GPIO_In_Init(GPIOE ,2);
	GPIO_In_Init(GPIOE ,3);
	GPIO_In_Init(GPIOE ,4);//key3

	
	//初始端口值,给其一个确定的状态,**重点**
	GPIO_SetBits(GPIOA ,0);
	GPIO_SetBits(GPIOE ,2);
	GPIO_SetBits(GPIOE ,3);
	GPIO_SetBits(GPIOE ,4);
	
}

int main(void)
{
	//初始化准备
    BEEP_Init();
	LED_Init();
    KEY_Init();
	
	//实现功能
	while(1)	
	{	
		if(GPIO_ReadInputDataBit(GPIOA ,0) == 0)
		{
			GPIO_ResetBits(GPIOF ,9);
			GPIO_ResetBits(GPIOF ,10);
			GPIO_ResetBits(GPIOE ,13);
			GPIO_ResetBits(GPIOE ,14);
			
			GPIO_SetBits(GPIOF ,8);			
		}
		
		if( GPIO_ReadInputDataBit(GPIOE ,2) == 0 )
		{
		GPIO_SetBits(GPIOF ,9);
		GPIO_SetBits(GPIOF ,10);
		GPIO_SetBits(GPIOE ,13);
		GPIO_SetBits(GPIOE ,14);
		
		GPIO_ResetBits(GPIOF ,8);
		
		}
	}

	
	
	return 0;
	
}

总结:寄存器是基于触发器的,触发器的赋值是一定需要时钟的,而寄存器的时钟是由总线时钟提供的,就是说没有总线时钟的话,你给寄存器值它是不会读入的。使能时钟这根弦时刻要绷紧,就像心脏时刻需要跳动一样

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值