完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
2个回答
|
|
STM32串口驱动不定长数据接收带环形缓冲区
使用涉及4个文件,UART_Port.c UART_Port.h CircularQueue.h CircularQueue.c 使用方法 1、在配置串口中使能DMA传输 ,全局中断 2、在串口初始化完成后调用Uart_Port_Init(); 3、在串口中断服务函数中调用USER_UART_IRQHandler(UART_HandleTypeDef *huart); 4、获取数据接口,请查看CircularQueue.h提供的缓冲区提取数据接口 5、注意事项:malloc无法申请内存的需调整堆栈大小,或者调整缓冲区大小 源码 串口接口文件 PS:默认使用串口1作为调试回环打印接口 需调整宏定义DEBUG_UART USE_LOOPBACK /* * FILE: UART_Port.c * * Created on: 2020/2/22 * * Author: aron66 * * DESCRIPTION:-- */ #ifdef __cplusplus //use C compiler extern "C" { #endif #include "UART_Port.h"/*外部接口*/ #define USE_LOOPBACK 1 #define DEBUG_UART &huart1 /* External variables --------------------------------------------------------*/ extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart3; extern UART_HandleTypeDef huart4; extern UART_HandleTypeDef huart5; extern UART_HandleTypeDef huart6; extern DMA_HandleTypeDef hdma_usart1_rx; extern DMA_HandleTypeDef hdma_usart1_tx; extern DMA_HandleTypeDef hdma_usart2_rx; extern DMA_HandleTypeDef hdma_usart2_tx; extern DMA_HandleTypeDef hdma_usart3_rx; extern DMA_HandleTypeDef hdma_usart3_tx; extern DMA_HandleTypeDef hdma_usart4_rx; extern DMA_HandleTypeDef hdma_usart4_tx; extern DMA_HandleTypeDef hdma_usart5_rx; extern DMA_HandleTypeDef hdma_usart5_tx; extern DMA_HandleTypeDef hdma_usart6_rx; extern DMA_HandleTypeDef hdma_usart6_tx; static uint8_t get_uart_index(USART_TypeDef *Instance); static Uart_Dev_info_t *Create_Uart_Dev(Uart_num_t uart_num ,UART_HandleTypeDef *huart ,DMA_HandleTypeDef *hdma_rx ,uint16_t rx_temp_size ,uint32_t rxsize ,int work_mode ,osSemaphoreId *pRX_Sem); /*预定义串口设备信息*/ Uart_Dev_info_t *Uart_pDevice[UART_MAX_NUM+1]; /** ****************************************************************** * @brief 初始化串口设备信息 * @author aron66 * @version v1.0 * @date 2020/3/15 ****************************************************************** */ void Uart_Port_Init(void) { Uart_pDevice[UART_NUM_1] = Create_Uart_Dev(UART_NUM_1 ,&huart1 ,&hdma_usart1_rx ,128 ,128 ,0 ,NULL); Uart_pDevice[UART_NUM_2] = Create_Uart_Dev(UART_NUM_2 ,&huart2 ,&hdma_usart2_rx ,128 ,128 ,0 ,NULL); } /** ****************************************************************** * @brief 建立串口设备,为其建立双缓冲区-->使能串口空闲中断 * @param 串口号 串口设备指针 dma操作地址 ,临时缓冲大小 接收队列大小 工作模式 二值信号量(适用于带FreeRTOS操作系统的工程) * @author aron66 * @version v1.0 * @date 2020/3/15 ****************************************************************** */ static Uart_Dev_info_t *Create_Uart_Dev(Uart_num_t uart_num ,UART_HandleTypeDef *huart ,DMA_HandleTypeDef *hdma_rx ,uint16_t rx_temp_size ,uint32_t rxsize ,int work_mode ,osSemaphoreId *pRX_Sem) { Uart_Dev_info_t *pUart_Dev = (Uart_Dev_info_t *)malloc(sizeof(Uart_Dev_info_t)); pUart_Dev->phuart = huart; pUart_Dev->phdma_rx = hdma_rx; pUart_Dev->cb = cb_create(rxsize); pUart_Dev->MAX_RX_Temp = rx_temp_size; pUart_Dev->RX_Buff_Temp = (uint8_t *)malloc(sizeof(uint8_t)*rx_temp_size); if(NULL == pUart_Dev->RX_Buff_Temp) { return NULL; } pUart_Dev->Is_Half_Duplex = work_mode; pUart_Dev->pRX_Sem = pRX_Sem; //打开空闲中断 __HAL_UART_ENABLE_IT(huart,UART_IT_IDLE); //使能DMA接收 HAL_UART_Receive_DMA(huart, pUart_Dev->RX_Buff_Temp, pUart_Dev->MAX_RX_Temp); return pUart_Dev; } /************************************************************ * @brief Rx Transfer IRQ * @param huart UART handle. * @return None * @author aron66 * @date 2020/3/15 * @version v1.0 * @note @@ ***********************************************************/ void USER_UART_IRQHandler(UART_HandleTypeDef *huart) { uint8_t index = get_uart_index(huart->Instance); if(index != 0) { if((__HAL_UART_GET_FLAG(Uart_pDevice[index]->phuart ,UART_FLAG_IDLE) != RESET)) { /* 首先停止DMA传输, 1.防止后面又有数据接收到,产生干扰,因为此时的数据还未处理。 2.DMA需要重新配置。 */ HAL_UART_DMAStop(Uart_pDevice[index]->phuart); /*清楚空闲中断标志,否则会一直不断进入中断*/ __HAL_UART_CLEAR_IDLEFLAG(Uart_pDevice[index]->phuart); /*计算本次接收数据长度*/ uint32_t data_length = Uart_pDevice[index]->MAX_RX_Temp - __HAL_DMA_GET_COUNTER(Uart_pDevice[index]->phdma_rx); /*将数据记录至环形区*/ CQ_putData(Uart_pDevice[index]->cb ,Uart_pDevice[index]->RX_Buff_Temp ,(uint32_t)data_length); #if USE_LOOPBACK HAL_UART_Transmit(DEBUG_UART, (uint8_t *)Uart_pDevice[index]->RX_Buff_Temp,(uint16_t)data_length,0xFFFF); #endif /*清空临时缓冲区*/ memset(Uart_pDevice[index]->RX_Buff_Temp ,0 ,data_length); data_length = 0; /*打开空闲中断*/ __HAL_UART_ENABLE_IT(Uart_pDevice[index]->phuart ,UART_IT_IDLE); /*重启开始DMA传输*/ HAL_UART_Receive_DMA(Uart_pDevice[index]->phuart ,Uart_pDevice[index]->RX_Buff_Temp, Uart_pDevice[index]->MAX_RX_Temp); } } } /*获得当前串口信息索引*/ static uint8_t get_uart_index(USART_TypeDef *Instance) { uint8_t index = 0; for(;index < UART_MAX_NUM+1;index++) { if(Uart_pDevice[index]->phuart->Instance == Instance) { return index; } } return 0; } #if (USE_NEW_REDIRECT == 0) #include "stdio.h" /************************************************* * 函数功能: 重定向c库函数printf到HAL_UART_Transmit * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(DEBUG_UART, (uint8_t *)&ch, 1, 10);//原来使用阻塞式传输 return ch; } /** * 函数功能: 重定向c库函数getchar,scanf * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */ int fgetc(FILE * f) { uint8_t ch = 0; while(HAL_UART_Receive(DEBUG_UART,&ch, 1, 0xffff)!=HAL_OK); return ch; } #else /*新式重定向*/ #include "stdio.h" int __io_putchar(int ch) { HAL_UART_Transmit(DEBUG_UART ,()uint8_t)&ch ,1 ,0xFFFF); return ch; } int __write(int file, char *ptr, int len) { int DataIdx; for(DataIdx = 0; DataIdx < len; DataIdx++) { __io_putchar(*ptr++); } return len; } #endif #ifdef __cplusplus //end extern c } #endif UART_Port.h文件 /* * FILE: UART_Port.h * * Created on: 2020/2/22 * * Author: aron566 * * DESCRIPTION:-- */ #ifndef UART_PORT_H #define UART_PORT_H #ifdef __cplusplus //use C compiler extern "C" { #endif /*库接口*/ #include #include #include #include /*外部接口*/ #include "stm32f1xx_hal.h" #include "usart.h" #include "cmsis_os.h" /*内部接口*/ #include "CircularQueue.h" #define UART_MAX_NUM 6 typedef enum { UART_NUM_0 = 0, UART_NUM_1, UART_NUM_2, UART_NUM_3, UART_NUM_4, UART_NUM_5, UART_NUM_6, }Uart_num_t; typedef struct { UART_HandleTypeDef *phuart; //uart端口 DMA_HandleTypeDef *phdma_rx; CQ_handleTypeDef *cb; //环形队列 uint8_t *RX_Buff_Temp; //接收缓冲 uint16_t MAX_RX_Temp; //最大接收数量 int Is_Half_Duplex; //半双工模式 osSemaphoreId *pRX_Sem; //接收二值信号量,如果没有使用FreeRTOS则屏蔽即可 }Uart_Dev_info_t; void Uart_Port_Init(void); void USER_UART_IRQHandler(UART_HandleTypeDef *huart); #ifdef __cplusplus //end extern c } #endif #endif |
|
|
|
环形缓冲区接口文件
CircularQueue.c文件 /** * @file CircularQueue.c * * @date 2020/6/25 * * @author aron566 * * @copyright None * * @brief None * * @details None * * @version v1.1 */ #ifdef __cplusplus /// extern "C" { #endif /** Includes -----------------------------------------------------------------*/ /* Private includes ----------------------------------------------------------*/ #include "CircularQueue.h" #if USE_LINUX_SYSTEM #include #endif /** Private typedef ----------------------------------------------------------*/ /** Private macros -----------------------------------------------------------*/ /** * @name 返回值定义 * @{ */ #define TRUE true #define FALSE false /** @}*/ /** Private constants --------------------------------------------------------*/ /** Public variables ---------------------------------------------------------*/ /** Private variables --------------------------------------------------------*/ /** Private function prototypes ----------------------------------------------*/ /** Private user code --------------------------------------------------------*/ /** Private application code -------------------------------------------------*/ /******************************************************************************* * * Static code * ******************************************************************************** */ /** Public application code --------------------------------------------------*/ /******************************************************************************* * * Public code * ******************************************************************************** */ /*初始化参数定义: *CircularQueue作为环形冲区的记录器是个结构体 *memAdd 作为实际数据存储区, *len 记录实际存储区的最大长度,需为2的整数倍 */ bool CQ_init(CQ_handleTypeDef *CircularQueue ,uint8_t *memAdd, uint16_t len) { CircularQueue->size = len; if (!IS_POWER_OF_2(CircularQueue->size)) return FALSE; if(memAdd == NULL) { return FALSE; } CircularQueue->dataBufer = memAdd; memset(CircularQueue->dataBufer, 0, len); CircularQueue->entrance = CircularQueue->exit = 0; return TRUE; } /*环形缓冲区判断是否为空: *CircularQueue作为环形冲区的记录器,是个结构体 *若写入数据与,读取数据长度一致,那么缓冲区为空return 1 */ bool CQ_isEmpty(CQ_handleTypeDef *CircularQueue) { if (CircularQueue->entrance == CircularQueue->exit) return TRUE; else return FALSE; } /*环形缓冲区判断是否为满 *CircularQueue作为环形冲区的记录器,是个结构体 *若 【已】写入数据与,减去 【已】读取数据长度 = 剩余空间 剩余空间==总长度 判断满 */ bool CQ_isFull(CQ_handleTypeDef *CircularQueue) { if ((CircularQueue->entrance - CircularQueue->exit) == CircularQueue->size)//MAXSIZE=5,Q.rear=2,Q.front=3? return TRUE;//空 else return FALSE; } /*环形缓冲区获取剩余空间长度: *CircularQueue作为环形冲区的记录器,是个结构体 *若 【已】写入数据与,减去 【已】读取数据长度 = 剩余空间 */ uint32_t CQ_getLength(CQ_handleTypeDef*CircularQueue) { return (CircularQueue->entrance - CircularQueue->exit); } /*环形缓冲区清空操作: *CircularQueue作为环形冲区的记录器,是个结构体 * 已读和可读数据长度清零 实际存储区清空 */ void CQ_emptyData(CQ_handleTypeDef*CircularQueue) { CircularQueue->entrance = CircularQueue->exit = 0; memset(CircularQueue->dataBufer, 0, CircularQueue->size); } /* *环形缓冲区读走数据: *CircularQueue作为环形冲区的记录器,是个结构体 *targetBuf 为临时数据处理处 *len 为本次数据读取长度 *使用写入长度-读取的长度 == 剩余可读 ,要读 取小值 */ uint32_t CQ_getData(CQ_handleTypeDef *CircularQueue, uint8_t *targetBuf, uint32_t len) { uint32_t size = 0; /*此次读取的实际大小,取 缓存事件数据大小 和 目标读取数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->entrance - CircularQueue->exit);// 假设总大小10 写入了5 - 已读4 == 1 未读 要读5个 返回1 /*原理雷同存入*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->exit & (CircularQueue->size - 1)));//10 - 0 > 1 返回1 memcpy(targetBuf, CircularQueue->dataBufer + (CircularQueue->exit & (CircularQueue->size - 1)), size);//偏移0个 复制一个字节 memcpy(targetBuf + size, CircularQueue->dataBufer, len - size);// 存储区偏移0个字节 /*利用无符号数据的溢出特性*/ CircularQueue->exit += len;//取出数据加 len 记录 return len; } /*环形缓冲区加入新数据:存入数据功能已做修改:每次数据帧开头先存入本帧的数据长度,所以每次先取一个字节得到包长度,再按长度取包 *CircularQueue作为环形冲区的记录器,是个结构体 *sourceBuf 为实际存储区地址 *len 为本次数据存入长度 *使用总长度-已写入+读取完的 == 可用空间大小 *对kfifo->size取模运算可以转化为与运算,如:kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1) */ uint32_t CQ_putData(CQ_handleTypeDef *CircularQueue, uint8_t * sourceBuf, uint32_t len) { uint32_t size = 0; /*此次存入的实际大小,取 剩余空间 和 目标存入数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->size - CircularQueue->entrance + CircularQueue->exit); /*&(size-1)代替取模运算,同上原理,得到此次存入队列入口到末尾的大小*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->entrance & (CircularQueue->size - 1))); memcpy(CircularQueue->dataBufer + (CircularQueue->entrance & (CircularQueue->size - 1)), sourceBuf, size); memcpy(CircularQueue->dataBufer, sourceBuf + size, len - size);//下次需要写入的数据长度 /*利用无符号数据的溢出特性*/ CircularQueue->entrance += len; //写入数据记录 return len; } /*修改后的-->环形缓冲区加入新数据:存入数据功能已做修改:每次数据帧开头先存入本帧的数据长度,所以每次先取一个字节得到包长度,再按长度取包 *CircularQueue作为环形冲区的记录器 *sourceBuf 为实际存储区地址 *len 为本次数据存入长度 *使用总长度-已写入+读取完的 == 可用空间大小 *对kfifo->size取模运算可以转化为与运算,如:kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1) */ uint32_t DQ_putData(CQ_handleTypeDef *CircularQueue, uint8_t * sourceBuf, uint32_t len) { uint32_t size = 0; uint32_t lenth = 1; uint32_t pack_len = len; /*此次存入的实际大小,取 剩余空间 和 目标存入数量 两个值小的那个*/ len = GET_MIN(len+lenth, CircularQueue->size - CircularQueue->entrance + CircularQueue->exit);//长度上头部加上数据长度记录 /*&(size-1)代替取模运算,同上原理,得到此次存入队列入口到末尾的大小*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->entrance & (CircularQueue->size - 1))); memcpy(CircularQueue->dataBufer + (CircularQueue->entrance & (CircularQueue->size - 1)), &pack_len, lenth); memcpy(CircularQueue->dataBufer + (CircularQueue->entrance & (CircularQueue->size - 1))+lenth, sourceBuf, size-lenth); memcpy(CircularQueue->dataBufer, sourceBuf + size - lenth, len - size); /*利用无符号数据的溢出特性*/ CircularQueue->entrance += len; return len; } /* *修改后的-->环形缓冲区读走数据:DQ会调用CQ取走一字节数据用来判断本次数据包长度 *CircularQueue作为环形冲区的记录器,是个结构体 *targetBuf 为临时数据处理处 *len 为本次数据读取长度 *使用写入长度-读取的长度 == 剩余可读 ,要读 取小值 */ uint32_t DQ_getData(CQ_handleTypeDef *CircularQueue, uint8_t *targetBuf) { uint32_t size = 0; uint32_t len = 0; //存储帧头 长度信息 uint8_t package_len[1]; //获取长度信息 CQ_getData(CircularQueue, (uint8_t *)package_len, 1); len = package_len[0]; /*此次读取的实际大小,取 缓存事件数据大小 和 目标读取数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->entrance - CircularQueue->exit); /*原理雷同存入*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->exit & (CircularQueue->size - 1))); memcpy(targetBuf, CircularQueue->dataBufer + (CircularQueue->exit & (CircularQueue->size - 1)), size); memcpy(targetBuf + size, CircularQueue->dataBufer, len - size); /*利用无符号数据的溢出特性*/ CircularQueue->exit += len; return len; } /* *环形缓冲区读走数据:(手动缓冲区长度记录---适用于modbus解析) *CircularQueue作为环形冲区的记录器,是个结构体 *targetBuf 为临时数据处理处 *len 为本次数据读取长度 *使用写入长度-读取的长度 == 剩余可读 ,要读 取小值 */ uint32_t CQ_ManualGetData(CQ_handleTypeDef *CircularQueue, uint8_t *targetBuf, uint32_t len) { uint32_t size = 0; /*此次读取的实际大小,取 缓存事件数据大小 和 目标读取数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->entrance - CircularQueue->exit); /*原理雷同存入*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->exit & (CircularQueue->size - 1))); memcpy(targetBuf, CircularQueue->dataBufer + (CircularQueue->exit & (CircularQueue->size - 1)), size); memcpy(targetBuf + size, CircularQueue->dataBufer, len - size); return len; } /** * [CQ_ManualGet_Offset_Data 读取指定索引号的数据] * @param CircularQueue [环形缓冲区句柄] * @param index [索引号] */ uint8_t CQ_ManualGet_Offset_Data(uint32_t index ,CQ_handleTypeDef *CircularQueue) { /*计算偏移*/ uint32_t read_offset = ((CircularQueue->exit + index) & (CircularQueue->size - 1)); /*取出数据*/ uint8_t data = *((uint8_t*)CircularQueue->dataBufer + read_offset); return data; } /** * [CQ_ManualOffsetInc 手动增加已取出长度] * @param CircularQueue [环形缓冲区句柄] * @param len [偏移长度] */ void CQ_ManualOffsetInc(CQ_handleTypeDef *CircularQueue, uint32_t len) { CircularQueue->exit += len ; } /** * [cb_create 申请并初始化环形缓冲区] * @param buffsize [申请环形缓冲区大小] * @return [环形队列管理句柄] */ CQ_handleTypeDef *cb_create(uint32_t buffsize) { if (!IS_POWER_OF_2(buffsize)) return NULL; CQ_handleTypeDef *cb = (CQ_handleTypeDef *)malloc(sizeof(CQ_handleTypeDef)); if(NULL == cb) { return NULL; } buffsize = (buffsize <= 2048 ? buffsize : 2048); cb->size = buffsize; cb->exit = 0; cb->entrance = 0; //the buff never release! cb->dataBufer = (uint8_t *)malloc(sizeof(uint8_t)*cb->size); if(NULL == cb->dataBufer) { return NULL; } return cb; } /** * [CQ_16_init 静态初始化16bit环形缓冲区] * @param CircularQueue [缓冲区指针] * @param memAdd [uint16_t 缓冲区地址] * @param len [缓冲区长度>1] * @return [初始化状态] */ bool CQ_16_init(CQ_handleTypeDef *CircularQueue ,uint16_t *memAdd,uint16_t len) { CircularQueue->size = len; if (!IS_POWER_OF_2(CircularQueue->size)) return FALSE; if(memAdd == NULL) { return FALSE; } CircularQueue->data16Bufer = memAdd; memset(CircularQueue->data16Bufer, 0, len*2); CircularQueue->entrance = CircularQueue->exit = 0; return TRUE; } /** * [cb_16create 动态申请并初始化环形缓冲区] * @param buffsize [申请环形缓冲区大小] * @return [环形队列管理句柄] */ CQ_handleTypeDef *cb_16create(uint32_t buffsize) { if (!IS_POWER_OF_2(buffsize)) return NULL; CQ_handleTypeDef *cb = (CQ_handleTypeDef *)malloc(sizeof(CQ_handleTypeDef)); if(NULL == cb) { return NULL; } buffsize = (buffsize <= 2048 ? buffsize : 2048); cb->size = buffsize; cb->exit = 0; cb->entrance = 0; //the buff never release! cb->data16Bufer = (uint16_t *)malloc(sizeof(uint16_t)*cb->size); if(NULL == cb->data16Bufer) { return NULL; } return cb; } /** * [CQ_16getData 取出数据] * @param CircularQueue [环形缓冲区句柄] * @param targetBuf [目标地址] * @param len [取出长度] * @return [取出长度] */ uint32_t CQ_16getData(CQ_handleTypeDef *CircularQueue, uint16_t *targetBuf, uint32_t len) { uint32_t size = 0; uint32_t len_temp = 0; uint32_t size_temp = 0; /*此次读取的实际大小,取 缓存事件数据大小 和 目标读取数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->entrance - CircularQueue->exit);// 假设总大小10 写入了5 - 已读4 == 1 未读 要读5个 返回1 /*原理雷同存入*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->exit & (CircularQueue->size - 1)));//10 - 0 > 1 返回1 len_temp = 2*len; size_temp = 2*size; memcpy(targetBuf, CircularQueue->data16Bufer + (CircularQueue->exit & (CircularQueue->size - 1)), size_temp);//偏移0个 复制一个字节 memcpy(targetBuf + size, CircularQueue->data16Bufer, len_temp - size_temp);// 存储区偏移0个字节 /*利用无符号数据的溢出特性*/ CircularQueue->exit += len;//取出数据加 len 记录 return len; } /** * [CQ_16putData 加入数据] * @param CircularQueue [环形缓冲区句柄] * @param sourceBuf [源地址] * @param len [长度] * @return [加入数据长度] */ uint32_t CQ_16putData(CQ_handleTypeDef *CircularQueue, uint16_t * sourceBuf, uint32_t len) { uint32_t size = 0; uint32_t len_temp = 0; uint32_t size_temp = 0; /*此次存入的实际大小,取 剩余空间 和 目标存入数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->size - CircularQueue->entrance + CircularQueue->exit); /*&(size-1)代替取模运算,同上原理,得到此次存入队列入口到末尾的大小*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->entrance & (CircularQueue->size - 1))); len_temp = 2*len; size_temp = 2*size; memcpy(CircularQueue->data16Bufer + (CircularQueue->entrance & (CircularQueue->size - 1)), sourceBuf, size_temp); memcpy(CircularQueue->data16Bufer, sourceBuf + size, len_temp - size_temp); /*利用无符号数据的溢出特性*/ CircularQueue->entrance += len; //写入数据记录 return len; } /** * [CQ_32_init 静态初始化16bit环形缓冲区] * @param CircularQueue [缓冲区指针] * @param memAdd [uint16_t 缓冲区地址] * @param len [缓冲区长度>1] * @return [初始化状态] */ bool CQ_32_init(CQ_handleTypeDef *CircularQueue ,uint32_t *memAdd ,uint16_t len) { CircularQueue->size = len; if (!IS_POWER_OF_2(CircularQueue->size)) return FALSE; if(memAdd == NULL) { return FALSE; } CircularQueue->data32Bufer = memAdd; memset(CircularQueue->data32Bufer, 0, len*4); CircularQueue->entrance = CircularQueue->exit = 0; return TRUE; } /** * [cb_32create 动态申请并初始化环形缓冲区] * @param buffsize [申请环形缓冲区大小] * @return [环形队列管理句柄] */ CQ_handleTypeDef *cb_32create(uint32_t buffsize) { if (!IS_POWER_OF_2(buffsize)) return NULL; CQ_handleTypeDef *cb = (CQ_handleTypeDef *)malloc(sizeof(CQ_handleTypeDef)); if(NULL == cb) { return NULL; } buffsize = (buffsize <= 2048 ? buffsize : 2048); cb->size = buffsize; cb->exit = 0; cb->entrance = 0; //the buff never release! cb->data32Bufer = (uint32_t *)malloc(sizeof(uint32_t)*cb->size); if(NULL == cb->data32Bufer) { return NULL; } return cb; } /** * [CQ_32putData 加入数据] * @param CircularQueue [环形缓冲区句柄] * @param sourceBuf [源地址] * @param len [长度] * @return [加入数据长度] */ uint32_t CQ_32putData(CQ_handleTypeDef *CircularQueue ,uint32_t * sourceBuf ,uint32_t len) { uint32_t size = 0; uint32_t len_temp = 0; uint32_t size_temp = 0; /*此次存入的实际大小,取 剩余空间 和 目标存入数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->size - CircularQueue->entrance + CircularQueue->exit); /*&(size-1)代替取模运算,同上原理,得到此次存入队列入口到末尾的大小*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->entrance & (CircularQueue->size - 1))); len_temp = 4*len; size_temp = 4*size; memcpy(CircularQueue->data32Bufer + (CircularQueue->entrance & (CircularQueue->size - 1)), sourceBuf, size_temp); memcpy(CircularQueue->data32Bufer, sourceBuf + size, len_temp - size_temp);//下次需要写入的数据长度 /*利用无符号数据的溢出特性*/ CircularQueue->entrance += len; //写入数据记录 return len; } /** * [CQ_32getData 取出数据] * @param CircularQueue [环形缓冲区句柄] * @param targetBuf [目标地址] * @param len [取出长度] * @return [取出长度] */ uint32_t CQ_32getData(CQ_handleTypeDef *CircularQueue ,uint32_t *targetBuf ,uint32_t len) { uint32_t size = 0; uint32_t len_temp = 0; uint32_t size_temp = 0; /*此次读取的实际大小,取 缓存事件数据大小 和 目标读取数量 两个值小的那个*/ len = GET_MIN(len, CircularQueue->entrance - CircularQueue->exit);// 假设总大小10 写入了5 - 已读4 == 1 未读 要读5个 返回1 /*原理雷同存入*/ size = GET_MIN(len, CircularQueue->size - (CircularQueue->exit & (CircularQueue->size - 1)));//10 - 0 > 1 返回1 len_temp = 4*len; size_temp = 4*size; memcpy(targetBuf, CircularQueue->data32Bufer + (CircularQueue->exit & (CircularQueue->size - 1)), size_temp);//偏移0个 复制一个字节 memcpy(targetBuf + size, CircularQueue->data32Bufer, len_temp - size_temp);// 存储区偏移0个字节 /*利用无符号数据的溢出特性*/ CircularQueue->exit += len;//取出数据加 len 记录 return len; } #ifdef __cplusplus /// #endif /******************************** End of file *********************************/ CircularQueue.h文件 /** * @file CircularQueue.h * * @date 2020/6/25 * * @author aron566 * * @brief None * * @version v1.1 */ #ifndef CIRCULARQUEUE_H_ #define CIRCULARQUEUE_H_ #ifdef __cplusplus /// extern "C" { #endif /** Includes -----------------------------------------------------------------*/ #include #include #include #include #include #include /** Private includes ---------------------------------------------------------*/ /** Private defines ----------------------------------------------------------*/ /** Exported typedefines -----------------------------------------------------*/ /** 数据结构体*/ typedef struct { uint8_t *dataBufer; /**< for 8bit buffer*/ uint16_t *data16Bufer; /**< for 16bit buffer*/ uint32_t *data32Bufer; /**< for 32bit buffer*/ uint32_t size; uint32_t entrance; uint32_t exit; }CQ_handleTypeDef; /** Exported constants -------------------------------------------------------*/ /** Exported macros-----------------------------------------------------------*/ #define GET_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define IS_POWER_OF_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) /** Exported variables -------------------------------------------------------*/ /** Exported functions prototypes --------------------------------------------*/ /*============================= Common ================================*/ bool CQ_isEmpty(CQ_handleTypeDef *CircularQueue); bool CQ_isFull(CQ_handleTypeDef *CircularQueue); void CQ_emptyData(CQ_handleTypeDef*CircularQueue); uint32_t CQ_getLength(CQ_handleTypeDef *CircularQueue); /*手动缩减缓冲区长度--用作:错误帧偏移-正确帧读取后剔除*/ void CQ_ManualOffsetInc(CQ_handleTypeDef *CircularQueue, uint32_t len); /*===========================8 Bit Option==============================*/ bool CQ_init(CQ_handleTypeDef *CircularQueue ,uint8_t *memAdd,uint16_t len); /*分配一个缓冲区并进行初始化--替代--CQ_init*/ CQ_handleTypeDef *cb_create(uint32_t buffsize); uint32_t CQ_getData(CQ_handleTypeDef *CircularQueue, uint8_t *targetBuf, uint32_t len); uint32_t CQ_putData(CQ_handleTypeDef *CircularQueue, uint8_t *sourceBuf, uint32_t len); /*修改后的加入数据操作--数据长度作为帧头先存入缓冲区*/ uint32_t DQ_putData(CQ_handleTypeDef *CircularQueue, uint8_t *sourceBuf, uint32_t len); /*修改后的取数据操作--会直接读取帧长度信息,依据当前一包长度加入缓冲区*/ uint32_t DQ_getData(CQ_handleTypeDef *CircularQueue, uint8_t *targetBuf); /*修改后的获取数据操作--数据读取后不会减小缓冲区长度,需手动减小,目的为了分步取出完整数据*/ uint32_t CQ_ManualGetData(CQ_handleTypeDef *CircularQueue, uint8_t *targetBuf, uint32_t len); /*修改后的获取数据操作--读取指定偏移的数据,不会减小缓冲区长度,目的为了验证数据,判断帧头等*/ uint8_t CQ_ManualGet_Offset_Data(uint32_t index ,CQ_handleTypeDef *CircularQueue); /*===========================16 Bit Option==============================*/ /*16bit环形缓冲区初始化*/ bool CQ_16_init(CQ_handleTypeDef *CircularQueue ,uint16_t *memAdd,uint16_t len); /*分配一个缓冲区并进行初始化--替代--CQ_16_init*/ CQ_handleTypeDef *cb_16create(uint32_t buffsize); /*加入16bit类型数据*/ uint32_t CQ_16putData(CQ_handleTypeDef *CircularQueue, uint16_t * sourceBuf, uint32_t len); /*取出16bit类型数据*/ uint32_t CQ_16getData(CQ_handleTypeDef *CircularQueue, uint16_t *targetBuf, uint32_t len); /*===========================32 Bit Option==============================*/ /*32bit环形缓冲区初始化*/ bool CQ_32_init(CQ_handleTypeDef *CircularQueue ,uint32_t *memAdd,uint16_t len); /*分配一个缓冲区并进行初始化--替代--CQ_32_init*/ CQ_handleTypeDef *cb_32create(uint32_t buffsize); /*加入32bit类型数据*/ uint32_t CQ_32putData(CQ_handleTypeDef *CircularQueue, uint32_t * sourceBuf, uint32_t len); /*取出32bit类型数据*/ uint32_t CQ_32getData(CQ_handleTypeDef *CircularQueue, uint32_t *targetBuf, uint32_t len); #ifdef __cplusplus /// #endif #endif /******************************** End of file *********************************/ 移植图示 1、加入接口代码文件至工程 2、确定自己的平台库文件 3、加入串口中断服务接口处理方法 4、main.c初始化代码加入 5、测试结果 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1817 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1631 浏览 1 评论
1103 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
739 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1692 浏览 2 评论
1951浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
755浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
586浏览 3评论
605浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
568浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 15:31 , Processed in 1.010343 second(s), Total 78, Slave 63 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号