这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » [转]STM2F070RB有关串口通信的几个坑以及硬件流控制

共1条 1/1 1 跳转至

[转]STM2F070RB有关串口通信的几个坑以及硬件流控制

菜鸟
2021-03-17 12:27:30     打赏

在整理串口库函数时发现有几个以前没有注意到的问题


问题一:


   如果使能了接收中断,即USART_ITConfig(USART1,USART_IT_RXNE,ENABLE),则默认ORE溢出中断也开启,且此时溢出中断标志USART_IT_ORE不能通过USART_GetITStatus()来检测到,而只能通过USART_GetFlagStatus()检测到,且此时USART_ClearITPendingBit(USART1, USART_IT_ORE)也不起作用。这种情况下,如果在中断处理函数中有if(USART_GetITStatus(USART1,USART_IT_ORE) != RESET)判断,则程序每接收一个字符都会进入到溢出中断(不过暂时检测到对接收数据的读取没有很大影响)


解决办法:


   在串口初始化时使能溢出中断USART_ITConfig(USART1,USART_IT_ORE,ENABLE);只有使能了这个USART_ClearITPendingBit(USART1, USART_IT_ORE)才可以起作用


   在串口中断处理函数中检测溢出标志,如果产生溢出中断则清除标志,且读取串口RDR寄存器清空接收缓存器


 


问题二:


   在使用串口助手向单片机串口发送数据时,如果不勾选“发送新行”,则接收到的字符串将丢失最后一个字符;而只有勾选“发送新行”后,接收到的字符串才是完整的


解决办法:


   经过排查,查到了真正原因,和原子那边的“串口接收定义收到换行符才判断为接收结束”没有任何关系,真正原因在于我在串口中断处理函数中检测中断标志用的USART_GetFlagStatus()而不是USART_GetITStatus(),前者的返回值是中断标志位状态(读ISR寄存器),后者的返回值是中断发生与否(读CR寄存器)。


    从CR寄存器中读取的是RXNEIE,发生接收中断时该位就被置位,且该标志位的置位和清除都是通过软件来完成的


    从ISR寄存器中读取的是RXNE,这个位则是当RDR移位寄存器向USART_RDR寄存器移数据时,由硬件自动置位,它的清除可以通过读取RDR寄存器内的数据清除或者软件置位RXFRQ来完成


    所以我这里的问题在于,我判断RXNE Flag Status等于RESET后才进行数据的读取,如果我发送的字符串是“helloworld”,那么当我发完d后,因为没有新的数据发过来,所以就不存在有“RDRRDR移位寄存器向USART_RDR寄存器移数据”这个动作,因此ISR中的RXNE就不会被置位。所以最后一个"d"字母就没有被存储处理。这个时候其实还是进了中断,只是不是USART_GetFlagStatus(USART1,USART_IT_RXNE)这一项,因而也就没有对最后一位数据进行存储处理。事实证明,当我再接着发送新的字符串时,之前的"d"字符会重新出现在新的字符串的第一位,同理这个时候新字符串的最后一位也没有被存储。


   同样的,如果使用USART_GetFlagStatus(USART1,USART_IT_RXNE) != RESET判断,即便我在串口助手中勾选了“发送新行”,根据得到的数据也可以发现串口接收buffer里面丢了换行符(两个ASCII值)的一个ASCII码值。


 


细节三:


    在官方给的串口中断处理函数中,读取接收字符的代码为:RxBuffer[RxCount++] = (USART_ReceiveData(USART1) & 0x7F);这里为什么与的不是0xFF而是0x7F,查看手册了解到无论串口配置时选的数据宽度为8bit还是9bit,其最高位一般保留为奇偶检验的结果位,因此如果读取实际数据的话应该省掉最高位


 


细节四:


    开启串口的DMA中断传输后,每次串口接收到一个字节后DMA就会自动去串口的RDR寄存器中读取数据,这时串口接收中断不会产生


DMA_DeInit(DMA1_Channel3);

DMA_InitTypeDef DMA_InitStructure;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->RDR);

DMA_InitStructure.DMA_BufferSize = (uint16_t)10;

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AckBuffer;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_Init(DMA1_Channel3,&DMA_InitStructure);

//USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);

//USART_ITConfig(USART1,USART_IT_ORE,ENABLE);

USART_Cmd(USART1,ENABLE);

USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);

/**************************************

* 查询传输用 while(DMA_GetFlagStatus(DMA1_IT_TC3) == RESET)

***************************************/

DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);  

DMA_Cmd(DMA1_Channel3,ENABLE);

 


细节五:重定向printf函数,记得#include <stdio.h>


#ifdef __GNUC__

  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

#else

#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)

#endif

PUTCHAR_PROTOTYPE

{

USART_SendData(USART1, (uint16_t) ch);

while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET)

{}

return ch;

}

 


串口通信的硬件流控制


   流控制的相关解释:https://blog.csdn.net/zeroboundary/article/details/8966586


串口设备使用硬件流控制的连接方式:


     TX   ————>  RX


   CTS  <————  RTS


    RX  <————   TX 


   RTS  ————>  CTS


 


因为手上也没有足够的板子做测试,只能用串口助手做个简单的测试,首先是配置CTS/RTS两个复用GPIO口,然后配置硬件流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS;


 /******USART1 CTS/RTS GPIO_Pins Configuration*******/

    GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_1);   //CTS

    GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_1);   //RTS

    

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOA,&GPIO_InitStructure);

我用的是串口USB转接口,只有TX和RX,测试CTS,我在主程序中循环打印“hello world”,可以发现如果将PA11接高电平或者悬空,字符不能正常打印,只有接低电平时字符串才能正常打印。即CTS低电平有效


 


RS232 RS485不同协议和串口的应用(待补充)

————————————————


原文链接:https://blog.csdn.net/yhl_sophia/article/details/88695434




共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]