你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32串口总线空闲检测遇到的条件判断小问题

[复制链接]
anobodykey 提问时间:2016-10-14 09:18 /
前几天在群里看到有人咨询stm32串口总线空闲检测的问题,之前也一直没用过该特性,后来看了下手册学习了一下,编辑了一些代码进行测试发现一个小问题,uart源文件代码如下:
  1. #include "uart.h"

  2. uint8_t buffer[100];
  3. __IO uint32_t cnt = 0,idle_detect = 0;

  4. void uart_init (uint32_t baud)
  5. {
  6.         USART_InitTypeDef USART_InitStructure;  
  7.         GPIO_InitTypeDef GPIO_InitStructure;     
  8.         NVIC_InitTypeDef NVIC_InitStructure;

  9.         RCC_AHBPeriphClockCmd(USARTx_GPIO_CLK, ENABLE);
  10.         USARTx_CLK_ENABLE();

  11.         GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_TX_SOURCE, USARTx_TX_AF);
  12.         GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_RX_SOURCE, USARTx_RX_AF);

  13.         GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN| USARTx_RX_PIN;               
  14.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      
  15.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;   
  16.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      
  17.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3;  
  18.         GPIO_Init(USARTx_GPIO_PORT, &GPIO_InitStructure);  

  19.         USART_InitStructure.USART_BaudRate            = baud ;            
  20.         USART_InitStructure.USART_WordLength          = USART_WordLength_8b;  
  21.         USART_InitStructure.USART_StopBits            = USART_StopBits_1;          
  22.         USART_InitStructure.USART_Parity              = USART_Parity_No;     
  23.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  24.         USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;   
  25.         USART_Init(USARTx, &USART_InitStructure);      

  26.         USART_ITConfig(USARTx,USART_IT_RXNE,ENABLE);   
  27.         USART_ITConfig(USARTx,USART_IT_PE,ENABLE);
  28.         USART_ITConfig(USARTx,USART_IT_ERR,ENABLE);
  29.         USART_ITConfig(USARTx,USART_IT_IDLE,ENABLE);       
  30.        

  31.         NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
  32.         NVIC_InitStructure.NVIC_IRQChannelPriority=0;
  33.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  34.         NVIC_Init(&NVIC_InitStructure);

  35.         USART_Cmd(USARTx, ENABLE);  
  36. }

  37. int fputc(int ch, FILE *f)
  38. {
  39.         USART_SendData(USARTx,(uint8_t)ch);
  40.         while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) != SET);
  41.         return ch;
  42. }

  43. void USARTx_IRQHandler(void)
  44. {
  45.         uint8_t temp = 0;
  46.        
  47.         if(USART_GetFlagStatus(USARTx,USART_FLAG_ORE) != RESET)
  48.         {
  49.                 temp = USART_ReceiveData(USARTx);
  50.                 (void)temp;
  51.                 USART_ClearFlag(USARTx,USART_FLAG_ORE);
  52.         }
  53.         if(USART_GetFlagStatus(USARTx,USART_FLAG_NE) != RESET)
  54.         {
  55.                 USART_ClearFlag(USARTx,USART_FLAG_NE);
  56.         }
  57.         if(USART_GetFlagStatus(USARTx,USART_FLAG_FE) != RESET)
  58.         {
  59.                 USART_ClearFlag(USARTx,USART_FLAG_FE);
  60.         }
  61.         if(USART_GetFlagStatus(USARTx,USART_FLAG_PE) != RESET)
  62.         {
  63.                 USART_ClearFlag(USARTx,USART_FLAG_PE);
  64.         }
  65.        
  66.         if(USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET)
  67.         {
  68.                 buffer[cnt++]=USART_ReceiveData(USARTx);  
  69.                 if(cnt >= 100)
  70.                 {
  71.                         cnt = 0;
  72.                 }
  73.                 USART_ClearITPendingBit(USARTx, USART_IT_RXNE);
  74.         }
  75.         if(USART_GetITStatus(USARTx, USART_IT_IDLE) != RESET)
  76.         {
  77.                 USART_ClearITPendingBit(USARTx, USART_IT_IDLE);
  78.                 idle_detect = 1;
  79.                 cnt = cnt;
  80.         }
  81.         return;
  82. }
复制代码
主函数中的测试代码如下:
  1. #include "uart.h"                  

  2. extern __IO uint32_t idle_detect,cnt;
  3. extern uint8_t buffer[100];
  4. int main (void)
  5. {
  6.         uint8_t i = 0;
  7.         uart_init(115200);

  8.         while(1)
  9.         {
  10.                 if(1 == idle_detect && cnt > 0)
  11.                 {
  12.                         idle_detect = 0;
  13.        
  14.                         printf("\r\ncnt:%X,ctx:",cnt);
  15.                         for(i = 0; i < cnt; i++)
  16.                         {
  17.                                 printf("%02X ",buffer[i]);
  18.                         }
  19.                         cnt = 0;
  20.                 }
  21.         }
  22. }
复制代码
运行该代码时结果如下
QQ截圖20161011104038.png
它输出的cnt值一直为1,但数据内容是正确的,而把cnt的判断放在if条件语句的里面就不会出问题,如下:
  1. #include "uart.h"                  

  2. extern __IO uint32_t idle_detect,cnt;
  3. extern uint8_t buffer[100];
  4. int main (void)
  5. {
  6.         uint8_t i = 0;
  7.         uart_init(115200);

  8.         while(1)
  9.         {
  10.                 if(1 == idle_detect)
  11.                 {
  12.                         idle_detect = 0;
  13.        
  14.                         if(cnt == 0)
  15.                                 continue;
  16.                         printf("\r\ncnt:%X,ctx:",cnt);
  17.                         for(i = 0; i < cnt; i++)
  18.                         {
  19.                                 printf("%02X ",buffer[i]);
  20.                         }
  21.                         cnt = 0;
  22.                 }
  23.         }
  24. }
复制代码
运行结果如下:
QQ截圖20161011104209.png
此时输出的cnt的值是正确的,有人知道会是什么问题导致的吗?
收藏 2 评论3 发布时间:2016-10-14 09:18

举报

3个回答
anobodykey 回答时间:2016-10-14 12:00:40
唉,没有人回复。。。经测试发现如果要把cnt变量的判断和idle_detect变量的判断放在一起需要在后面加一段延迟才能保证cnt的输出是正确的,当上位机发送的数据变多时,该延迟就需要相应的增多,因此,还是cnt的判断放在里面好些,这样可以省略延迟
mark0668 回答时间:2016-10-14 14:58:11
谢谢分享!
watershade 回答时间:2016-10-15 11:20:00
本帖最后由 watershade 于 2016-10-15 11:46 编辑

我觉得RXNE和IDLE LINE这两个中断的发生时间需要测试一下。
这两个的发生时间我理解的可能不正确。若有错误请指正。

在我的理解里,RXNE是接受buffer里面有数据准备被DR读取的时候产生的。数据手册里面的描述是Received Data Ready to be Read.或者Read data register not empty.
而idle line是硬件检测到的空闲间隔。当出现idle line的时候RXNE一定发生。【The IDLE bit will not be set again until the RXNE bit has been set itself 】
在我的测试中是在HAL中进行的,使用中断idle line来实现不定常接收。就出现了每一个字节都接受,反而idle line没有什么效果。

所以你的第一段代码中cnt一直是1.你第二个出现正确的结果,个人猜测是因为你用了
  • if(cnt == 0)
  •                                 continue;

这样其实如果你跟踪程序的话,会发现你的idle line第一次出现是的确是cnt==0或者==1.

  •                         printf("\r\ncnt:%X,ctx:",cnt);
  •                         for(i = 0; i < cnt; i++)
  •                         {
  •                                 printf("%02X ",buffer);
  •                         }
你的这段代码可以看出cnt早printf时和printf之后明显改变了。你过你把cnt赋值给另一个数你就每次只能打印出一个数。


所以第二段代码其实也没有解决你的真实问题。不信你拿50个左右的字符试一试。然后printf用另一个更快的端口输出。或者直接在内存调试。


推荐的方法是DMA+IDLE探测。不开启RXNE
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
13245底部标题123相同标题
12底部标题123相同标题
33333底部标题123相同序号
3435底部标题-无链接
关注我们
st-img 微信公众号
st-img 手机版