anobodykey 发表于 2016-10-14 09:18:10

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的值是正确的,有人知道会是什么问题导致的吗?

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
页: [1]
查看完整版本: STM32串口总线空闲检测遇到的条件判断小问题