由于串口中断服务函数处理串口的数据寄存器的数据时,存储数据和处理数据需要一定的时间,所以接收数据的频率不能太快。为了解决这个问题,在中断服务函数中将串口的数据寄存器值存储在环形队列中,只做存储功能,处理数据的功能放在主函数中。这样一来,就不会遗漏任何一个字节的数据。
串口的数据寄存器可以存放一个字节的数据,通过非空标志位触发中断,在中断服务函数中把数据存放在环形队列中,并清除标志位。等待下一次中断。环形队列就是一个蓄水池,不管数据多少,先装下不浪费。
typedef struct
{
uint32_t head; //数组下标,指向队头
uint32_t tail; //数组下标,指向队尾
uint32_t size; //队列缓存长度(初始化时赋值)
uint8_t *buffer; //队列缓存数组(初始化时赋值)
} QueueType_t;
typedef enum
{
QUEUE_OK = 0, //队列正常
QUEUE_ERROR, //队列错误
QUEUE_OVERLOAD, //队列已满
QUEUE_EMPTY //队列已空
} QueueStatus_t;
/**
****************************************************************
* @brief 初始化(创建)队列,每个队列须先执行该函数才能使用
* @param queue, 队列变量指针
* @param buffer, 队列缓存区地址
* @param size, 队列缓存区长度
* @return
****************************************************************
*/
void QueueInit(QueueType_t *queue, uint8_t *buffer, uint32_t size)
{
queue->buffer = buffer;
queue->size = size;
queue->head = 0;
queue->tail = 0;
}
/**
****************************************************************
* @brief 压入数据到队列中
* @param queue, 队列变量指针
* @param data, 待压入队列的数据
* @return 压入队列是否成功
****************************************************************
*/
QueueStatus_t QueuePush(QueueType_t *queue, uint8_t data)
{
uint32_t index = (queue->tail + 1) % queue->size;
if (index == queue->head)
{
return QUEUE_OVERLOAD;
}
queue->buffer[queue->tail] = data;
queue->tail = index;
return QUEUE_OK;
}
/**
****************************************************************
* @brief 从队列中弹出数据
* @param queue, 队列变量指针
* @param pdata, 待弹出队列的数据缓存地址
* @return 弹出队列是否成功
****************************************************************
*/
QueueStatus_t QueuePop(QueueType_t *queue, uint8_t *pdata)
{
if(queue->head == queue->tail)
{
return QUEUE_EMPTY;
}
*pdata = queue->buffer[queue->head];
queue->head = (queue->head + 1) % queue->size;
return QUEUE_OK;
}
/**
****************************************************************
* @brief 压入一组数据到队列中
* @param queue, 队列变量指针
* @param pArray, 待压入队列的数组地址
* @param len, 待压入队列的元素个数
* @return 实际压入到队列的元素个数
****************************************************************
*/
uint32_t QueuePushArray(QueueType_t *queue, uint8_t *pArray, uint32_t len)
{
uint32_t i;
for (i = 0; i < len; i++)
{
if(QueuePush(queue, pArray[i]) == QUEUE_OVERLOAD)
{
break;
}
}
return i;
}
/**
****************************************************************
* @brief 从队列中弹出一组数据
* @param queue, 队列变量指针
* @param pArray, 待弹出队列的数据缓存地址
* @param len, 待弹出队列的数据的最大长度
* @return 实际弹出数据的数量
****************************************************************
*/
uint32_t QueuePopArray(QueueType_t *queue, uint8_t *pArray, uint32_t len)
{
uint32_t i;
for(i = 0; i < len; i++)
{
if (QueuePop(queue, &pArray[i]) == QUEUE_EMPTY)
{
break;
}
}
return i;
}
/**
****************************************************************
* @brief 获取队列中数据的个数
* @param queue, 队列变量指针
* @return 队列中数据的个数
****************************************************************
*/
uint32_t QueueCount(QueueType_t *queue)
{
if (queue->head <= queue->tail)
{
return queue->tail - queue->head;
}
return queue->size + queue->tail - queue->head;
}
/**
***********************************************************
* @brief 串口0中断服务函数
* @param
* @return
***********************************************************
*/
void USART0_IRQHandler(void)
{
if (usart_interrupt_flag_get(g_uartHwInfo.uartNo, USART_INT_FLAG_RBNE) != RESET)
{
usart_interrupt_flag_clear(g_uartHwInfo.uartNo, USART_INT_FLAG_RBNE);//清除标志位
uint8_t uData = (uint8_t)usart_data_receive(g_uartHwInfo.uartNo);//接收数据
pProcUartDataFunc(uData);//回调函数,将数据存入队列
}
}