本帖最后由 幽明叶 于 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)
{
}
}
|