1.大致思路
主要是两个结构体 :
一个定义了起始指针和结束指针,分别指向接收到的数据的起始位置和结束位置,初始化都为零。
一个定义了缓冲区总数据量来一个数据加1,从零开始,后期判断是否能装下DMA,一次的最大传送量,装不下,他和起始指针直接跳回零。还有当次串口接收和发送到的数据的大小。定义一个标记接收数据起始位置(起始指针),截止位置(结束指针)的结构体的数组。指向标记接收数据起始位置,截止位置的结构体的数组的插入和提取数据的位置还有最后一个数组成员的位置。当插入和提取数据相等表明数据都处理完了,接收一次数据就跳到数组的下一项。
话不多说贴代码 :
#define NUM 10 //标记接收数据起始位置,截止位置的结构体数组成员数量
#define U1_TXBUFF_SIZE 256 //定义串口1 发送缓冲区大小
#define U1_RXBUFF_SIZE 1024*8 //定义串口1 接收缓冲区大小
#define U1_DMARX_SIZE 256 //定义串口1 DMA单次接收的最大数据量
#define U1_COPYBUFF_SIZE U1_DMARX_SIZE //定义处理串口1接收数据的缓冲区副本大小
typedef struct{
uint8_t *StartPtr; //标记本次接收数据的起始位置
uint8_t *EndPtr; //标记本次接收数据的截止位置
}UCB_RxBuffPtrCB; //标记接收数据起始位置,截止位置的结构体
typedef struct{
uint16_t U_RxCounter; //定义一个变量,记录串口接收的数据在缓冲区数组内的位置
uint16_t U_Rxdatalen; //定义一个变量,保存当次串口接收到的数据的大小
uint16_t U_Txdatalen; //定义一个变量,保存当次串口需要发送的数据的大小
UCB_RxBuffPtrCB UCB_RxBuffPtrCB[NUM]; //定义一个标记接收数据起始位置,截止位置的结构体的数组
UCB_RxBuffPtrCB *URxDataInPtr; //指向标记接收数据起始位置,截止位置的结构体的数组的插入数据的位置
UCB_RxBuffPtrCB *URxDataOutPtr; //指向标记接收数据起始位置,截止位置的结构体的数组的提取数据的位置
UCB_RxBuffPtrCB *URxDataEndPtr; //指向标记接收数据起始位置,截止位置的结构体的数组的最后一个数组成员的位置
UART_HandleTypeDef UART_Handler; //串口设置句柄
DMA_HandleTypeDef hdma_rx; //配置接收 DMA的句柄
}UCB_CB; //串口1控制结构体
extern UCB_CB U1_Control; //声明外部变量,控制串口1的结构体
extern uint8_t U1_TxBuff[U1_TXBUFF_SIZE]; //声明外部变量,定义一个数组缓冲区,串口1发送缓冲区
extern uint8_t U1_RxBuff[U1_RXBUFF_SIZE]; //声明外部变量,定义一个数组缓冲区,串口1发接收冲区
extern uint8_t U1Copy_RxBuff[U1_COPYBUFF_SIZE];//声明外部变量,定义一个数组缓冲区,串口1处理接收数据的副本缓冲区
2.主函数指针逻辑
while{ //主循环
/*-----------------------------------------------------------------------------------------*/
/* 处 理 串 口 1 接 收 到 的 数 据 */
/*-----------------------------------------------------------------------------------------*/
if(U1_Control.URxDataOutPtr != U1_Control.URxDataInPtr){ //如果串口1的 URxDataOutPtr指针 和 URxDataInPtr指针不相等,则if成立,说明串口1有数据接收到了
U1_Control.U_Rxdatalen = U1_Control.URxDataOutPtr->EndPtr - U1_Control.URxDataOutPtr->StartPtr; //计算本次接收的数据量
u1_printf("本次接收到 %d 字节数据\r\n",U1_Control.U_Rxdatalen); //串口输出提示信息
memset(U1Copy_RxBuff,0,U1_COPYBUFF_SIZE); //清空缓冲区
memcpy(U1Copy_RxBuff,U1_Control.URxDataOutPtr->StartPtr,U1_Control.U_Rxdatalen); //提取数据
u1_printf("接收到的数据如下:\r\n%s\r\n\r\n",U1Copy_RxBuff); //串口输出提示信息
U1_Control.URxDataOutPtr ++; //串口1的 URxDataOutPtr指针 下移
if(U1_Control.URxDataOutPtr==U1_Control.URxDataEndPtr) //如果到达处理接收数据的结构体数组尾部了
U1_Control.URxDataOutPtr = &U1_Control.UCB_RxBuffPtrCB[0]; //串口1的 URxDataOutPtr指针 回到处理接收数据的结构体数组开头
}
}
3.中断函数逻辑
/*-------------------------------------------------*/
/*函数名:串口1中断处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&U1_Control.UART_Handler,UART_FLAG_IDLE) != RESET){ //如果发生空闲中断
__HAL_UART_CLEAR_IDLEFLAG(&U1_Control.UART_Handler); //清除空闲中断标志
HAL_UART_DMAStop(&U1_Control.UART_Handler); //停止DMA
U1_Control.U_RxCounter += (U1_DMARX_SIZE - __HAL_DMA_GET_COUNTER(&U1_Control.hdma_rx)); //计算本次的接收数据量,定位结束位置
U1_Control.URxDataInPtr->EndPtr = &U1_RxBuff[U1_Control.U_RxCounter]; //记录本次接收的结束位置
U1_Control.URxDataInPtr++; //数据IN指针下移
if(U1_Control.URxDataInPtr==U1_Control.URxDataEndPtr) //如果指针到处理接收数据的结构体数组尾部了
U1_Control.URxDataInPtr = &U1_Control.UCB_RxBuffPtrCB[0]; //指针归位到处理接收数据的结构体数组的起始位置,也就是0号成员
U1_Control.URxDataInPtr->StartPtr = &U1_RxBuff[U1_Control.U_RxCounter]; //记录下次接收的起始位置
if(U1_RXBUFF_SIZE - U1_Control.U_RxCounter >= U1_DMARX_SIZE){ //如果剩余空间大于 DMA接收的单次数据量 进入if
HAL_UART_Receive_DMA(&U1_Control.UART_Handler, &U1_RxBuff[U1_Control.U_RxCounter], U1_DMARX_SIZE); //启动DMA接收
U1_Control.URxDataInPtr->StartPtr = &U1_RxBuff[U1_Control.U_RxCounter]; //记录下次接收的起始位置
}else{ //如果剩余空间不够单次接收量 进入else
U1_Control.U_RxCounter = 0; //U1_Control.U_RxCounter 清零
HAL_UART_Receive_DMA(&U1_Control.UART_Handler, U1_RxBuff, U1_DMARX_SIZE); //启动DMA接收
U1_Control.URxDataInPtr->StartPtr = U1_RxBuff; //记录下次接收的起始位置
}
}
}
4.结构体初始化
/*----------------------------------------------------------*/
/*函数名:初始化处理接收数据的结构体数组 */
/*参 数:无 */
/*返回值:无 */
/*----------------------------------------------------------*/
void U1Rx_Buff_Init(void)
{
U1_Control.URxDataInPtr = &U1_Control.UCB_RxBuffPtrCB[0]; //指向标记接收数据起始位置,截止位置的结构体的数组的插入数据的位置的指针,在最开始的时候指向该数组的0号成员
U1_Control.URxDataOutPtr = U1_Control.URxDataInPtr; //指向标记接收数据起始位置,截止位置的结构体的数组的提取数据的位置的指针,在最开始的时候指向该数组的0号成员
U1_Control.URxDataEndPtr = &U1_Control.UCB_RxBuffPtrCB[NUM-1]; //指向标记接收数据起始位置,截止位置的结构体的数组的结尾数据的位置的指针,在最开始的时候指向该数组的最后一个成员
U1_Control.URxDataInPtr->StartPtr = U1_RxBuff; //起始位置
U1_Control.URxDataInPtr->EndPtr = U1_RxBuff; //起始位置
U1_Control.U_RxCounter = 0; //串口1累计接收位置变量,设置为0
}