芯片:stm32f407ZET6X 功能:实现两按键分别控制四个灯和一个蜂鸣器 思路:将寄存器设置封装成函数,体会固件库的实现原理
踩坑记录:下载程序后发现与PA0连接的按键,为按下,就出现了灯闪,蜂鸣器响,正常逻辑应该是按下按键,PA0口接地,此时才灯亮。
原因分析:因为初始化PA0口时没有使能A组的时钟(RCC_AHB1ENR |= (0x01); 漏写),所以,上拉拉设置对A组IO口无效,我发现GPIO口在未使能的状态下,是低电平,猜想默认是下拉吗???。对于输入口,不要尝试置位或复位,因为输入模式下,GPIOx->GPIOx_IDR(端口输入寄存器)是只读的。
#define PRI_BASEADDR 0x40000000
#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)
#define GPIOE_BASEADDR (AHB1_BASEADDR+0x1000)
#define GPIOF_BASEADDR (AHB1_BASEADDR+0x1400)
typedef struct {
unsigned int GPIOx_MODER;
unsigned int GPIOx_OTYPER;
unsigned int GPIOx_OSPEEDR;
unsigned int GPIOx_PUPDR;
unsigned int GPIOx_IDR;
unsigned int GPIOx_ODR;
}GPIOx_TypeDef;
#define GPIOA ((GPIOx_TypeDef *)GPIOA_BASEADDR)
#define GPIOE ((GPIOx_TypeDef *)GPIOE_BASEADDR)
#define GPIOF ((GPIOx_TypeDef *)GPIOF_BASEADDR)
void GPIO_Out_Init(GPIOx_TypeDef * GPIOx, unsigned char PIN)
{
RCC_AHB1ENR |= (0x01<<4);
RCC_AHB1ENR |= (0x01<<5);
GPIOx->GPIOx_MODER &= ~(0x03<<PIN*2);
GPIOx->GPIOx_MODER |= (0x01<<PIN*2);
GPIOx->GPIOx_OTYPER &= ~(0x01<<PIN);
GPIOx->GPIOx_OSPEEDR &= ~(unsigned int)(0x03<<PIN*2);
GPIOx->GPIOx_OSPEEDR |= (unsigned int)(0x01<<PIN*2);
GPIOx->GPIOx_PUPDR &= ~(unsigned int)(0x03<<PIN*2);
GPIOx->GPIOx_PUPDR |= (unsigned int)(0x01<<PIN*2);
}
void GPIO_In_Init(GPIOx_TypeDef * GPIOx, unsigned char PIN)
{
RCC_AHB1ENR |= (0x01<<4);
RCC_AHB1ENR |= (0x01<<5);
RCC_AHB1ENR |= (0x01);
GPIOx->GPIOx_MODER &= ~(0x03<<PIN*2);
GPIOx->GPIOx_PUPDR &= ~(unsigned int)(0x03<<PIN*2);
GPIOx->GPIOx_PUPDR |= (unsigned int)(0x01<<PIN*2);
}
void GPIO_SetBits(GPIOx_TypeDef *GPIOx ,unsigned char Pin)
{
GPIOx->GPIOx_ODR |= (0x01<<Pin);
}
void GPIO_ResetBits(GPIOx_TypeDef *GPIOx ,unsigned char Pin)
{
GPIOx->GPIOx_ODR &= ~(0x01<<Pin);
}
unsigned int GPIO_ReadInputDataBit(GPIOx_TypeDef *GPIOx ,unsigned char Pin)
{
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);
GPIO_Out_Init(GPIOF, 10);
GPIO_Out_Init(GPIOE, 13);
GPIO_Out_Init(GPIOE, 14);
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);
GPIO_In_Init(GPIOE ,2);
GPIO_In_Init(GPIOE ,3);
GPIO_In_Init(GPIOE ,4);
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;
}
总结:寄存器是基于触发器的,触发器的赋值是一定需要时钟的,而寄存器的时钟是由总线时钟提供的,就是说没有总线时钟的话,你给寄存器值它是不会读入的。使能时钟这根弦时刻要绷紧,就像心脏时刻需要跳动一样
|