STM32串口总线空闲检测遇到的条件判断小问题
前几天在群里看到有人咨询stm32串口总线空闲检测的问题,之前也一直没用过该特性,后来看了下手册学习了一下,编辑了一些代码进行测试发现一个小问题,uart源文件代码如下:#include "uart.h"
uint8_t buffer;
__IO uint32_t cnt = 0,idle_detect = 0;
void uart_init (uint32_t baud)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(USARTx_GPIO_CLK, ENABLE);
USARTx_CLK_ENABLE();
GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_TX_SOURCE, USARTx_TX_AF);
GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_RX_SOURCE, USARTx_RX_AF);
GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN| USARTx_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3;
GPIO_Init(USARTx_GPIO_PORT, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baud ;
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(USARTx, &USART_InitStructure);
USART_ITConfig(USARTx,USART_IT_RXNE,ENABLE);
USART_ITConfig(USARTx,USART_IT_PE,ENABLE);
USART_ITConfig(USARTx,USART_IT_ERR,ENABLE);
USART_ITConfig(USARTx,USART_IT_IDLE,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USARTx, ENABLE);
}
int fputc(int ch, FILE *f)
{
USART_SendData(USARTx,(uint8_t)ch);
while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) != SET);
return ch;
}
void USARTx_IRQHandler(void)
{
uint8_t temp = 0;
if(USART_GetFlagStatus(USARTx,USART_FLAG_ORE) != RESET)
{
temp = USART_ReceiveData(USARTx);
(void)temp;
USART_ClearFlag(USARTx,USART_FLAG_ORE);
}
if(USART_GetFlagStatus(USARTx,USART_FLAG_NE) != RESET)
{
USART_ClearFlag(USARTx,USART_FLAG_NE);
}
if(USART_GetFlagStatus(USARTx,USART_FLAG_FE) != RESET)
{
USART_ClearFlag(USARTx,USART_FLAG_FE);
}
if(USART_GetFlagStatus(USARTx,USART_FLAG_PE) != RESET)
{
USART_ClearFlag(USARTx,USART_FLAG_PE);
}
if(USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET)
{
buffer=USART_ReceiveData(USARTx);
if(cnt >= 100)
{
cnt = 0;
}
USART_ClearITPendingBit(USARTx, USART_IT_RXNE);
}
if(USART_GetITStatus(USARTx, USART_IT_IDLE) != RESET)
{
USART_ClearITPendingBit(USARTx, USART_IT_IDLE);
idle_detect = 1;
cnt = cnt;
}
return;
}
主函数中的测试代码如下:
#include "uart.h"
extern __IO uint32_t idle_detect,cnt;
extern uint8_t buffer;
int main (void)
{
uint8_t i = 0;
uart_init(115200);
while(1)
{
if(1 == idle_detect && cnt > 0)
{
idle_detect = 0;
printf("\r\ncnt:%X,ctx:",cnt);
for(i = 0; i < cnt; i++)
{
printf("%02X ",buffer);
}
cnt = 0;
}
}
}
运行该代码时结果如下
它输出的cnt值一直为1,但数据内容是正确的,而把cnt的判断放在if条件语句的里面就不会出问题,如下:
#include "uart.h"
extern __IO uint32_t idle_detect,cnt;
extern uint8_t buffer;
int main (void)
{
uint8_t i = 0;
uart_init(115200);
while(1)
{
if(1 == idle_detect)
{
idle_detect = 0;
if(cnt == 0)
continue;
printf("\r\ncnt:%X,ctx:",cnt);
for(i = 0; i < cnt; i++)
{
printf("%02X ",buffer);
}
cnt = 0;
}
}
}运行结果如下:
此时输出的cnt的值是正确的,有人知道会是什么问题导致的吗?
唉,没有人回复。。。经测试发现如果要把cnt变量的判断和idle_detect变量的判断放在一起需要在后面加一段延迟才能保证cnt的输出是正确的,当上位机发送的数据变多时,该延迟就需要相应的增多,因此,还是cnt的判断放在里面好些,这样可以省略延迟 谢谢分享! 本帖最后由 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
页:
[1]