打印
[STM32F7]

结帖---UART中断接收问题 HAL库 接收数据长度设置大于1时

[复制链接]
3790|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
幽明叶|  楼主 | 2018-11-25 23:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 幽明叶 于 2018-11-28 01:08 编辑

结帖
更新3:找到问题了
   /*rx_cache_buffer > 1 溢出分析:
        当1个数据过来后触发中断-->USART1_IRQHandler-->HAL_UART_IRQHandler-->UART_Receive_IT
                               -->将数据读入RDR(此时并没有将huart->RxState = HAL_UART_STATE_READY!!!!)
                                  而是直接退出等待下个数据过来后中断继续写入RDR
                                  直到RDR数据达到rx_cache_buffer时,才将huart->RxState = HAL_UART_STATE_READY
        但是,下面却判断并等待READY,只有到rx_cache_buffer存满时,才会是READY!!!
        因此下面两个while判断都将超时退出!!导致了大量延迟!导致ORE溢出
        判断READY只能在rx_cache_buffer==1时使用!!!*/

//串口中断服务函数---串口总中断函数
void USART1_IRQHandler()
{   
    //调用uart中断处理函数
    HAL_UART_IRQHandler(&UART1_Handle);

    if(rx_size==1)
    {
        timeout=0;
        while (HAL_UART_GetState(&UART1_Handle)!=HAL_UART_STATE_READY)//等待就绪!若rx_cache_buffer>1,此时状态并不是READY,函数超时!
        {
            timeout++;////超时处理
            if(timeout>maxDelay) break;        
        }

        timeout=0;
        while(HAL_UART_Receive_IT(&UART1_Handle,(uint8_t*)rx_cache_buffer, rx_size)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
        {
            timeout++; //超时处理
            if(timeout>maxDelay) break;        
        }
    } //end if
    else
    {
        HAL_UART_Receive_IT(&UART1_Handle,(uint8_t*)rx_cache_buffer, rx_size);
    }
}



------------------------------
更新2:

又想了想,不太对啊,如果是ORE溢出发生error中断,那为什么buffer size=1时就没问题?? 按理说buffer size=1时,如果一口气发过去10字节数据,读取RDR有延迟的话,也会发生RDR被覆盖的情况啊
--------------------------------------------------------------
更新1:
找到问题了,出在对中断处理超时判断上了!!!!
接收中断发生条件:
1.RXNE=1   
2.ORE=1发生溢出(新的数据准备传输到RDR,但RXNE=1 RDR中旧的数据还未被读取)

正常情况:RXNE=1数据已经从移位寄存器传输到RDR寄存器-->USART1_IRQHandler-->HAL_UART_IRQHandler-->UART_Receive_IT读取RDR(置0 RXNE)hal的buff中存数据;当多次中断发生后,buffer count==0 buffer size达到预设值,则--->callback

异常情况:RXNE=1(RDR中已经有数据), 且在读取RDR之前,又有新的数据从移位寄存器转移到RDR(此时旧的RDR数据还未被读取)--->ORE由硬件=1-->发生中断USART1_IRQHandler-->ERROR-->放弃当前接收,重置buffer count=buffer size。

当使用debug发送多个数据时,或者在每次中断中 UART_Receive_IT读取RDR的过程中出现了while延迟,将会导致异常情况!!!

因此,原因分析如下:---主要是延迟导致了读取RDR速度跟不上移位寄存器写入RDR速度
出现了异常情况!在USART1_IRQHandler中,在第一次调用完HAL_UART_IRQHandler-->UART_Receive_IT读取RDR关闭中断后,加入了while判断状态(延迟期间导致了接收速度跟不上了),才去使能新一次的HAL_UART_Receive_IT接收中断使能,在while等待过程中,>2个的新数据又移到了RDR中,导致ORE触发中断USART1_IRQHandler->HAL_UART_IRQHandler-->此中断被当作error处理放弃了接收并重置了buffer count=buffer size-->使能接收中断使能(此时buffer count已经被重置)--->loop

//串口中断服务函数---串口总中断函数
void USART1_IRQHandler()
{   

    //调用uart中断处理函数
    HAL_UART_IRQHandler(&UART1_Handle);


    timeout=0;
    while (HAL_UART_GetState(&UART1_Handle)!=HAL_UART_STATE_READY)//等待就绪
    {
        timeout++;////超时处理
        if(timeout>maxDelay) break;        
    }



    timeout=0;
    while(HAL_UART_Receive_IT(&UART1_Handle,(uint8_t*)rx_cache_buffer, 10)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
    {
        timeout++; //超时处理
        if(timeout>maxDelay) break;        
    }
}

改为:可解决问题!!

void USART1_IRQHandler()
{   

    //调用uart中断处理函数
    HAL_UART_IRQHandler(&UART1_Handle);

    HAL_UART_Receive_IT(&UART1_Handle,(uint8_t*)rx_cache_buffer, 10);   

}

-------------------------------------------------------------------------------------------------------
学习原子哥的UART,板子时F767,用HAL库的UART中断接收数据。

HAL库中接收数据长度设置 size=1时 接收正常,每次可以接收1个字节。

当设size>1,比如size=10时,按理说应该接到10个字节后,回调CALLBACK。
实际测试发现,每次发送1个数据data=1,发送10次后,可以正常调用callback;
但一次发送10个数据abcdefg...过去后,不调用callback。debug调试发现,在UART_Receive_IT函数中 if(--huart->RxXferCount == 0) 指针"减1"之后并没有保存RxXferCount的值,下次再进中断后RxXferCount=A了,导致RxXferCount永远减不到0。

包括使用原子哥uart例子,把size改成10,也会出现同样的问题。
这是为什么??是我哪里理解有问题吗,还是我那个地方设置不对

求助
一些关键代码:
u16 rx_size=10;
u8 rx_cache_buffer[100];


HAL_UART_Receive_IT(&UART1_Handle,(uint8_t*)rx_cache_buffer, rx_size ;//一次处理完成之后,重新开启中断并设置RxXferCount为1
//uart接收中断用户callback
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        u8 rec[]={0};
        int a;
//        u8 rec;
        int i=0;
        if(huart->Instance==USART1)//如果是串口1
        {
                for(i=0;i<rx_size;i++)
                {
                        rec=*(huart->pRxBuffPtr-(rx_size-i));
                        HAL_UART_Transmit(&UART1_Handle,&rec,1,1000);
//                        printf("uart==%c\n",rec);
                }        
        }
}



下面是我所有代码:
#include "sys.h"
#include "delay.h"
#include "usart.h"

UART_HandleTypeDef UART1_Handle; //HANDLE是句柄,对于句柄,则定义成全局变量,因为很多地方需要用到
u16 rx_size=10;
u8 rx_cache_buffer[100];
u32 timeout=0;
u32 maxDelay=0x1FFFF;

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化        
        {
                GPIO_InitTypeDef uartgpio;
               
                __HAL_RCC_GPIOA_CLK_ENABLE();
               
                uartgpio.Pin=GPIO_PIN_9|GPIO_PIN_10;
                uartgpio.Mode=GPIO_MODE_AF_PP;
                uartgpio.Pull=GPIO_PULLUP;
                uartgpio.Speed=GPIO_SPEED_FAST;
                uartgpio.Alternate=GPIO_AF7_USART1;
                HAL_GPIO_Init(GPIOA,&uartgpio);
               
                //开启+设置串口中断线,放在此函数内,可以区分不同uart的中断分开设置优先级
                HAL_NVIC_EnableIRQ(USART1_IRQn);
                HAL_NVIC_SetPriority(USART1_IRQn,3,3);               
        }
}

void uart_ini()
{
        
        __HAL_RCC_USART1_CLK_ENABLE();

        UART1_Handle.Instance=USART1;
        UART1_Handle.Init.BaudRate=115200;
        UART1_Handle.Init.WordLength=UART_WORDLENGTH_8B;
        UART1_Handle.Init.StopBits=UART_STOPBITS_1;
        UART1_Handle.Init.Parity=USART_PARITY_NONE;
        UART1_Handle.Init.Mode=UART_MODE_TX_RX;
        UART1_Handle.Init.HwFlowCtl=UART_HWCONTROL_NONE;
        UART1_Handle.Init.OverSampling=UART_OVERSAMPLING_16;
        HAL_UART_Init(&UART1_Handle);
        
        /*
        **HAL_UART_Init--->HAL_UART_MspInit--->HAL_UART_Init,在HAL_UART_Init函数的最后,有UART_CheckIdleState函数去设置
        **  huart->gState= HAL_UART_STATE_READY; 以及 huart->RxState= HAL_UART_STATE_READY;
        **        
        **        而HAL_UART_Receive_IT函数需要判断 huart->RxState == HAL_UART_STATE_READY
        **         所以HAL_UART_Receive_I函数放在msp中是无法执行的!!必须在HAL_UART_Init之后!!!
        */
        //开启uart接收中断,RXNEIE置位--HAL库中,执行完成中断后自动关闭该中断!!
        timeout=0;
        while(HAL_UART_Receive_IT(&UART1_Handle,(uint8_t*)rx_cache_buffer, rx_size)!=HAL_OK)//开启中断并设置RxXferCount为1
        {
                timeout++; //超时处理
                if(timeout>maxDelay) break;               
        }        
}

//串口中断服务函数---串口总中断函数
void USART1_IRQHandler()
{        
        //调用uart中断处理函数
        HAL_UART_IRQHandler(&UART1_Handle);

        timeout=0;
    while (HAL_UART_GetState(&UART1_Handle)!=HAL_UART_STATE_READY)//等待就绪
        {
        timeout++;////超时处理
        if(timeout>maxDelay) break;               
        }

        timeout=0;
        while(HAL_UART_Receive_IT(&UART1_Handle,(uint8_t*)rx_cache_buffer, rx_size)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
        {
        timeout++; //超时处理
        if(timeout>maxDelay) break;               
        }
}

//uart接收中断用户callback
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        u8 rec[]={0};
        int a;
//        u8 rec;
        int i=0;
        if(huart->Instance==USART1)//如果是串口1
        {
//                rec = (--*(huart->pRxBuffPtr)); //*(huart->pRxBuffPtr)所指向的地址空间中的内容--;假如pRxBuffPtr==5,则运算结果==4
               
                for(i=0;i<rx_size;i++)
                {
                        rec=*(huart->pRxBuffPtr-(rx_size-i));
                        HAL_UART_Transmit(&UART1_Handle,&rec,1,1000);
//                        printf("uart==%c\n",rec);
                }        

               
//                rec = *(--(huart->pRxBuffPtr));        //huart->pRxBuffPtr 指向的地址数--,==指向上一个地址               
//                HAL_UART_Transmit(&UART1_Handle,&rec,rx_size,1000);
        }
}

int main(void)
{
        uint8_t buffer[]="我是\n";
        uint8_t a=0x22;
        uint32_t Timeout=10; //ms
        
        Cache_Enable(); //打开 L1-Cache
        HAL_Init(); //初始化 HAL 库
        Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz
        delay_init(216);
        
        uart_ini();           
//        a=sizeof(int *);
//        
//        buffer[0]=a;
        
//        while(1)
//        {
//                while(1)
//                {
//                if(HAL_UART_Transmit(&UART1_Handle,buffer,sizeof(buffer),Timeout)!=HAL_OK)
//                {
//                        printf("delay\n");
//                        break;
//                }
//                delay_ms(100);
//                }
//        }
               
        while(1)
        {
        }
               
               
}
沙发
幽明叶|  楼主 | 2018-11-26 21:20 | 只看该作者
求助

使用特权

评论回复
板凳
磨砂| | 2018-12-3 13:05 | 只看该作者
这个帖子好 能涨知识和经验

使用特权

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

本版积分规则

2

主题

8

帖子

0

粉丝