×
单片机 > 单片机程序设计 > 详情

STM32填坑:时钟使能必须在外设初始化之前

发布时间:2020-06-01 发布时间:
|

最近在STM32上写了一份串口通信的程序,但下载复位后串口却不能工作,初始化的代码如下:


//发送/接收的GPIO、串口和中断的初始化结构体

GPIO_InitTypeDef GPIO_InitStructureTx;

GPIO_InitTypeDef GPIO_InitStructureRx;

USART_InitTypeDef USART_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;


//设置发送和接收引脚

GPIO_InitStructureTx.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructureRx.GPIO_Pin = GPIO_Pin_10;

//发送引脚设置为推挽复用、接收引脚设置为浮空输入

GPIO_InitStructureTx.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructureRx.GPIO_Mode = GPIO_Mode_IN_FLOATING;

//设置引脚工作频率

GPIO_InitStructureRx.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructureTx.GPIO_Speed = GPIO_Speed_50MHz;

//引脚初始化

GPIO_Init(GPIOA, &GPIO_InitStructureTx);

GPIO_Init(GPIOA, &GPIO_InitStructureRx);


//波特率

USART_InitStructure.USART_BaudRate = USART_BaudRate;

//数据长度

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

//停止位

USART_InitStructure.USART_StopBits = USART_StopBits_1;

//校验位

USART_InitStructure.USART_Parity = USART_Parity_No;

//流控制

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

//打开发送和接收模式

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

//初始化串口1

USART_Init(USART1, &USART_InitStructure);

 

//时钟使能

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

 

//配置中断优先级

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = SubPriority;

NVIC_InitStructure.NVIC_IRQChannelCmd = state;

//中断初始化

NVIC_Init(&NVIC_InitStructure);

 

//串口1使能

USART_Cmd(USART1, ENABLE);

 

//打开串口1接收中断

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);


可以看到,外设时钟使能放在了GPIO和USART的初始化之后。在网上查了下资料,发现STM32外设未被使能的情况下外设的寄存器无法被设置。引用一个解释:


 “ARM的芯片,外设通常都是给了时钟后才能设置它的寄存器(即才能使用这个外设)。STM32、LPC1XXX等等都是这样,这么做的目的是为了省电,使用了所谓时钟门控的技术。寄存器是基于触发器的,触发器的赋值是一定需要时钟的,而寄存器的时钟是由总线时钟提供的,就是说没有总线时钟的话,你给寄存器值它是不会读入的。”


因此,把外设时钟使能放在GPIO和USART初始化之前,就解决了这个问题,最终代码如下:


//发送/接收的GPIO、串口和中断的初始化结构体

GPIO_InitTypeDef GPIO_InitStructureTx;

GPIO_InitTypeDef GPIO_InitStructureRx;

USART_InitTypeDef USART_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

 

//时钟使能(时钟使能放在GPIO和USART初始化之前)

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

 

//设置发送和接收引脚

GPIO_InitStructureTx.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructureRx.GPIO_Pin = GPIO_Pin_10;

//发送引脚设置为推挽复用、接收引脚设置为浮空输入

GPIO_InitStructureTx.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructureRx.GPIO_Mode = GPIO_Mode_IN_FLOATING;

//设置引脚工作频率

GPIO_InitStructureRx.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructureTx.GPIO_Speed = GPIO_Speed_50MHz;

//引脚初始化

GPIO_Init(GPIOA, &GPIO_InitStructureTx);

GPIO_Init(GPIOA, &GPIO_InitStructureRx);


//波特率

USART_InitStructure.USART_BaudRate = USART_BaudRate;

//数据长度

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

//停止位

USART_InitStructure.USART_StopBits = USART_StopBits_1;

//校验位

USART_InitStructure.USART_Parity = USART_Parity_No;

//流控制

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

//打开发送和接收模式

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

//初始化串口1

USART_Init(USART1, &USART_InitStructure);

 

 

//配置中断优先级

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = SubPriority;

NVIC_InitStructure.NVIC_IRQChannelCmd = state;

//中断初始化

NVIC_Init(&NVIC_InitStructure);

 

//串口1使能

USART_Cmd(USART1, ENABLE);

 

//打开串口1接收中断

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会