打印

求教STM32 USART 高速通讯的怪问题

[复制链接]
6655|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ZENG_GJ|  楼主 | 2009-8-11 12:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
俺用的是STM32F103VB,72MHz运行。USART2,半双工通讯,DMA发送,中断接收。在速率为19200、115200时一切正常。

但是项目要求速率达到0.5Mbps,更改波特率设置(用的是FWLib)后,通讯无法进行。示波器查出发送正确。我在接收中断函数

入口处设置一根引线作为探针,发现CPU居然以大约2.5uS的周期反复进入中断程序,因此导致主程序假死。示波器观测,回应信号

基本正确。百思不得其解!

万望高手支援!!
沙发
汉之云| | 2009-8-11 12:09 | 只看该作者
查一查中断使能位和标志位,是不是出现使能了中断,而且标志来了,但没在中断处理程序中清掉的

使用特权

评论回复
板凳
香水城| | 2009-8-11 12:17 | 只看该作者
是否软件响应不够快?为什么接收不用DMA?

使用特权

评论回复
地板
ZENG_GJ|  楼主 | 2009-8-11 14:05 | 只看该作者
感谢楼上兄弟是我回复。

to 2楼:因为以前115200是没问题的,所以您的说法应当不存在。按照手册上所说,只要读取了DR,即可清除标志。而且我还用库函数再执行了一次。

to 3楼:我也曾经考虑过软件响应速度不够的因素,但我无法解释这样的现象:一旦进入了反复中断的状况,即使撤掉外来的信号,中断也不能退出,而且典型的特征是2.5uS左右的中断周期,十分规律。在这种情况下,只要我用调试停止暂停执行一次,然后恢复运行,中断就不再进入了。
    我在中断函数的开始,禁止本中断,在中断返回时恢复中断,并不能解决问题。后来在不断的测试过程中,我还发现有时125kbps通讯也会有此现象,但经复位能够消除。
   未用DMA是因为沿袭了部分老设计。而且由于接收数量未知, DMA也有些麻烦。多个中断配合不如单一的好做。但无论如何,这种中断无法清除的现象我想不通,十分郁闷啊!

使用特权

评论回复
5
香水城| | 2009-8-11 14:29 | 只看该作者
请问在反复进入中断时,从DR中读出的数据对不对?你有没有查看SR寄存器?是否发生了某些错误没有处理?

使用特权

评论回复
6
ZENG_GJ|  楼主 | 2009-8-11 14:40 | 只看该作者
可以肯定数据是不对的,似乎只有两种01和03。SR也曾经看过,RXNE不一定置位。如果说是错误造成的,我曾在中断函数内不管三七二十一所有标志全部清一次。可以肯定,我没有打开除接收中断之外的任何USART中断。而且只要我禁用该中断,就不再反复进入中断函数。

使用特权

评论回复
7
香水城| | 2009-8-11 14:47 | 只看该作者
数据传输的另一端是什么设备?数据格式是什么?

使用特权

评论回复
8
ZENG_GJ|  楼主 | 2009-8-11 15:09 | 只看该作者
另一端是MEGA48+MAX1487,数据格式8,N,1,无校验

“对不起,本站规定会员每小时最多只能发表 5 个帖子。“

二姨不让说话,俺闭嘴了一下:-)

使用特权

评论回复
9
香水城| | 2009-8-11 15:13 | 只看该作者
把你的程序发上来看看。

使用特权

评论回复
10
ST_ARM| | 2009-8-11 15:17 | 只看该作者
对比一下双方的波特率是否相同。是否只是一方改了,另一方没有更改?

使用特权

评论回复
11
ZENG_GJ|  楼主 | 2009-8-11 15:31 | 只看该作者
我刚刚改了一下,USART2发,USART3接收,涛声依旧。

1通道是探针,每次进入USART2中断,反转一次
2是总线数据波形
以下是初始化代码,另一通道一样:
USART_InitStructure.USART_BaudRate = 500000;
  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(USART2, &USART_InitStructure);
//  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
  USART_Cmd(USART2, ENABLE);
  USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
以下是USART2接收中断代码,3通道类似:
void USART2_IRQHandler(void)         // IO Module
{  
  u16 temp=0;
  USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);           
GPIO_WriteBit(GPIOC, GPIO_Pin_9, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_9)));
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET
  /*&& USART_GetFlagStatus(USART2, USART_FLAG_ORE) == RESET
  && USART_GetFlagStatus(USART2, USART_FLAG_NE) == RESET
  && USART_GetFlagStatus(USART2, USART_FLAG_FE) == RESET */ )
  {
temp=*((vu32*)0x40004404);
TIM_ITConfig(TIM2, TIM_IT_CC2, DISABLE);
temp=USART_ReceiveData(USART2);
/* Overwrite protect */
RxBuff_IO[RxBuffWrPt_IO++]=(u8)temp;
if(RxBuffWrPt_IO>=RX_BUFF_SIZE_IO)
{
   IO_CommStatus=130;
   RxBuffWrPt_IO--;
}
else IO_CommStatus = 4;        // Reciving...
temp = TIM_GetCounter(TIM2);      // Wait for Slave
    TIM_SetCompare2(TIM2, temp + IO_COMM_IDLE);   // 3.5bytes for recive end
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
  }  
  USART_ClearITPendingBit(USART2, USART_IT_RXNE);
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
接收方USART3未见回应。

!真心感谢楼上兄弟!

使用特权

评论回复
12
香水城| | 2009-8-11 15:47 | 只看该作者
1)这句话做什么的?  temp=*((vu32*)0x40004404);

2)RxBuff_IO有多大,是否溢出了?

3)请在中断函数开始和结尾各翻转I/O一次,这样可以看到中断函数的执行时间。

4)每次进中断都有这个条件吗?USART_IT_RXNE

使用特权

评论回复
13
ZENG_GJ|  楼主 | 2009-8-11 16:25 | 只看该作者
to 香主:
  1: 如果不错的话那是DR寄存器地址;
  2:RxBuff SIZE 为 12字节,所要接收的数据只有8字节;
  3:在250kbps下,能够测到处理时间约2.5uS,在500kbps下似乎中断从未返回,感谢您的提醒。
  4:很难满足RXNE条件。

我想我明白问题所在了,十分感谢您的帮助,我会尝试用DMA接收的!再次感谢!

使用特权

评论回复
14
ST_ARM| | 2009-8-11 17:41 | 只看该作者
把中断里这一行去掉:USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);

使用特权

评论回复
15
ZENG_GJ|  楼主 | 2009-8-12 08:06 | 只看该作者
这一句本来是没有的。如果波特率低——19200试过,似乎加也无妨。

使用特权

评论回复
16
ST_ARM| | 2009-8-12 10:19 | 只看该作者
再次详读你的代码,有如下之不解?望解惑!

void USART2_IRQHandler(void)         // IO Module
{  
  u16 temp=0;
  USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);           
GPIO_WriteBit(GPIOC, GPIO_Pin_9, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_9)));
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET
  /*&& USART_GetFlagStatus(USART2, USART_FLAG_ORE) == RESET
  && USART_GetFlagStatus(USART2, USART_FLAG_NE) == RESET
  && USART_GetFlagStatus(USART2, USART_FLAG_FE) == RESET */ )
  {
temp=*((vu32*)0x40004404);           ->已经读取了串口的数据了
TIM_ITConfig(TIM2, TIM_IT_CC2, DISABLE); ->定时器的意欲何为?
temp=USART_ReceiveData(USART2);   ->为何二进宫,再次读取串口数据?
/* Overwrite protect */                        ->防范接收溢出乎?大惑!
RxBuff_IO[RxBuffWrPt_IO++]=(u8)temp;
if(RxBuffWrPt_IO>=RX_BUFF_SIZE_IO)
{
   IO_CommStatus=130;
   RxBuffWrPt_IO--;
}
else IO_CommStatus = 4;        // Reciving...
temp = TIM_GetCounter(TIM2);      // Wait for Slave
    TIM_SetCompare2(TIM2, temp + IO_COMM_IDLE);   // 3.5bytes for recive end   ->3.5个字节?不解之?
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
  }  
  USART_ClearITPendingBit(USART2, USART_IT_RXNE);
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}

使用特权

评论回复
17
ZENG_GJ|  楼主 | 2009-8-12 14:13 | 只看该作者
楼上兄弟很细心啊!
1.USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); 这句确实不行,我后来做了特别测试,似乎加上后会清掉RXNE位。
2.temp=*((vu32*)0x40004404);是在反复测试过程中加上的,这句也不严谨,临时忘了注释掉。
3.接收过程没有定时守护程序,因此可能有缓存溢出情况。这段保证溢出部分不影响其它内存。
4.   3.5bytes for recive end是通讯协议的一部分。我采用的是空闲线协议,依此来分组。
5.以下是经过手工代码优化的程序,运行时间缩短到大约2uS。
void USART2_IRQHandler(void)                   // IO Module
{        
  u16 temp=0;
   
  GPIO_SetBits(GPIOC, GPIO_Pin_9);                 // Test

  if(USART2->SR & 0x20)                          /* Test RXNE bit */
  {       
      TIM2->DIER &= (u16)~TIM_IT_CC2;                    // TIM_IT_CC2, DISABLE
      temp=(u16)(USART2->DR & (u16)0xFF);              // ReceiveData
      RxBuff_IO[RxBuffWrPt_IO++]=(u8)temp;
      if(RxBuffWrPt_IO>=RX_BUFF_SIZE_IO)          /* Overwrite protect */
     {
        IO_CommStatus=130;
        RxBuffWrPt_IO--;
     }
     else IO_CommStatus = 4;                                 // Reciving...
     temp = TIM2->CNT;
    TIM2->CCR2 =  temp + IO_COMM_IDLE;        // 3.5bytes for recive end
    TIM2->SR = (u16)~TIM_IT_CC2;
    TIM2->DIER |= TIM_IT_CC2;                  // TIM_IT_CC2, ENABLE
  }               
  USART2->SR=(u16)(~0x0020);                 // Clear RXNE
   
  GPIO_ResetBits(GPIOC, GPIO_Pin_9);         // Test
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

24

帖子

0

粉丝