IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> stm32的GPIO口PA0按键没按下就是低电平的分析 -> 正文阅读

[嵌入式]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;
	
}

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

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-07 21:19:16  更:2021-07-07 21:19:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 16:22:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码