最近在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);