列表 上一篇 下一篇

STM32:非中断模式USART实验总结

先上代码

#include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_usart.h" int main() { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200; 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; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); /* 以上是对串口的初始化部分,USART1初始化设置:115200-8-n-1 */ /*---------------------------程序主要部分-----------------------------------------*/ while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);//收到数据 USART_SendData(USART1, 'c'); //while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 USART_SendData(USART1, 'c'); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);//再次检查接收数据标志 USART_SendData(USART1, USART_ReceiveData(USART1));//读出刚才接收的数据并发送 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 for(;;); }

根据以上程序说一下几个注意点:

  1. 根据手册上说的“处于空闲状态,对USART_DR寄存器的写操作直接把数据放进移位寄存器,数据传输开始,TXE 位立即被置起。”,所以37、39行的发送的两个字符应该正常发送,但实验结果是:
    上位机输入b,则会接收到cb。 如果取消38行的注释,则实验结果是:上位机输入b,则会接收到ccb

    小结一下,这是不是说明参考手册上说的“处于空闲状态,对USART_DR寄存器的写操作直接把数据放进移位寄存器”有错。另一方面,处于空闲状态时TXE位不是已经置起码?为什么还说“TXE 位立即被置起。”。总之猜不透这一点,编程时的办法:在发送数据之前,要检查TXE位,注意这是在串口没有开启中断的时候的方案。
  2. 关于手册中“包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR) ,一个给接收用(RDR) ,该寄存器兼具读和写的功能。”的验证。36行在接收到数据之后并没有对数据读取,而是37、39行发送了两个数据,然后再次检查接收数据标志,根据1中的实验结果说明接收数据标志还有效,所以发送和接收的数据寄存器互不影响,%90说明了“由于它是由两个寄存器组成的”。

    另外,这个前面ns16550串口模块的收发寄存器差不多:当时看到两个寄存器定义在一个地址很怀疑(参考ns16550文章中软件置位数据收、数据发的错误理解)。

    前两条小结一下:在没有开启中断的情况下,串口的收发之前要检查RXNE、TXE,就像ns16550的驱动那样。所以37行、44行之前最好也添加while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空。虽然40行已经检查过USART_DR寄存器已经为空,但44行之前最好还是添加对USART_DR的检查。
  3. 说一下STM32串口的TXE、TC位,TXE标志着数据寄存器为空,TC位标志着数据寄存器、移位寄存器都为空(当移位寄存器发送完成<包括结束位>,如果TXE位置起<数据寄存器为空,说明没有要数据发送了>,则TC位置起,如果TXE位没有置起,说明还有数据要发送,则进入移位寄存器,TXE位置起,注意此时TC位不会置起)。
  4. 注意一下USART寄存器的几个位
    UE:USART使能 (USART enable)
    TE:发送使能 (Transmitter enable)
    RE:接收使能 (Receiver enable)
    TXE:发送寄存器空,由硬件置1,只能对USART_DR的写会自动置0。软件不能设置该位(下面void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)说明可以看到)。另外还要注意TXE位的说明:This bit is set by hardware when the content of the TDR register has been transferred into the shift register. An interrupt is generated if the TXEIE bit =1 in the USART_CR1 register. It is cleared by a write to the USART_DR register.并不是中文手册上说的:当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1寄存器中的TXEIE 为1,则产生中断。对USART_DR的写操作,将该位清零。
    RXNE:接收寄存器不为空,由硬件置1,对USART_DR的读取会自动置0,也可以软件置0(忽略接收到的数据),但是软件一般不设置该位

    void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)定义
/** * @brief Clears the USARTx's pending flags. * @param USARTx: Select the USART or the UART peripheral. * This parameter can be one of the following values: * USART1, USART2, USART3, UART4 or UART5. * @param USART_FLAG: specifies the flag to clear. * This parameter can be any combination of the following values: * @arg USART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5). * @arg USART_FLAG_LBD: LIN Break detection flag. * @arg USART_FLAG_TC: Transmission Complete flag. * @arg USART_FLAG_RXNE: Receive data register not empty flag. * * @note * - PE (Parity error), FE (Framing error), NE (Noise error), ORE (OverRun * error) and IDLE (Idle line detected) flags are cleared by software * sequence: a read operation to USART_SR register (USART_GetFlagStatus()) * followed by a read operation to USART_DR register (USART_ReceiveData()). * - RXNE flag can be also cleared by a read to the USART_DR register * (USART_ReceiveData()). * - TC flag can be also cleared by software sequence: a read operation to * USART_SR register (USART_GetFlagStatus()) followed by a write operation * to USART_DR register (USART_SendData()). * - TXE flag is cleared only by a write to the USART_DR register * (USART_SendData()). * @retval None */ void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG) { /* Check the parameters */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_CLEAR_FLAG(USART_FLAG)); /* The CTS flag is not available for UART4 and UART5 */ if ((USART_FLAG & USART_FLAG_CTS) == USART_FLAG_CTS) { assert_param(IS_USART_123_PERIPH(USARTx)); } USARTx->SR = (uint16_t)~USART_FLAG; }