xQueueSendToBackFromISR(ecuCanRxQueue, hcan->pRxMsg, &xHigherPriorityTaskWoken),xQueueReceive(mscCanRxQueue,&mscRxMsg,0)和xQueueSendToBack(mscCanTxQueue, &TxMessageTemp, 0 )这3个函数,在裸机下实现:
在裸机(无RTOS)环境下,需要手动实现队列机制来替代FreeRTOS的这三个函数。以下是完整的裸机实现方案:
1. 队列结构定义
c
#define CAN_RX_QUEUE_SIZE 20 // 接收队列大小
#define CAN_TX_QUEUE_SIZE 30 // 发送队列大小
/* CAN接收消息结构 */
typedef struct {
uint32_t id; // CAN ID
uint8_t data[8]; // 数据
uint8_t length; // 数据长度
} CanRxMsg_t;
/* CAN发送消息结构 */
typedef struct {
uint32_t id; // CAN ID
uint8_t data[8]; // 数据
uint8_t length; // 数据长度
} CanTxMsg_t;
/* 环形队列结构 */
typedef struct {
void *buffer; // 数据缓冲区
uint16_t size; // 队列容量
volatile uint16_t head; // 队头
volatile uint16_t tail; // 队尾
volatile uint16_t count; // 当前元素数
} Queue_t;
/* 全局队列实例 */
Queue_t ecuCanRxQueue; // ECU CAN接收队列
Queue_t mscCanRxQueue; // MSC CAN接收队列
Queue_t mscCanTxQueue; // MSC CAN发送队列
/* 队列存储区 */
CanRxMsg_t ecuRxBuffer[CAN_RX_QUEUE_SIZE];
CanRxMsg_t mscRxBuffer[CAN_RX_QUEUE_SIZE];
CanTxMsg_t mscTxBuffer[CAN_TX_QUEUE_SIZE];
2. 队列初始化
c
void Queues_Init(void)
{
/* ECU接收队列 */
ecuCanRxQueue.buffer = ecuRxBuffer;
ecuCanRxQueue.size = CAN_RX_QUEUE_SIZE;
ecuCanRxQueue.head = 0;
ecuCanRxQueue.tail = 0;
ecuCanRxQueue.count = 0;
/* MSC接收队列 */
mscCanRxQueue.buffer = mscRxBuffer;
mscCanRxQueue.size = CAN_RX_QUEUE_SIZE;
mscCanRxQueue.head = 0;
mscCanRxQueue.tail = 0;
mscCanRxQueue.count = 0;
/* MSC发送队列 */
mscCanTxQueue.buffer = mscTxBuffer;
mscCanTxQueue.size = CAN_TX_QUEUE_SIZE;
mscCanTxQueue.head = 0;
mscCanTxQueue.tail = 0;
mscCanTxQueue.count = 0;
}
3. 替代函数实现
(1) 替代xQueueSendToBackFromISR
c
/* 中断安全入队函数 */
uint8_t Queue_SendFromISR(Queue_t *q, void *item, uint16_t itemSize)
{
if (q->count >= q->size) {
return 0; // 队列满
}
__disable_irq(); // 关中断保证原子操作
// 拷贝数据到队尾
memcpy((uint8_t*)q->buffer + q->head * itemSize, item, itemSize);
q->head = (q->head + 1) % q->size;
q->count++;
__enable_irq(); // 开中断
return 1; // 成功
}
/* 使用示例(在CAN中断中)*/
void CAN_RX0_IRQHandler(void)
{
CanRxMsg_t rxMsg;
// 从CAN硬件读取数据...
// 替代xQueueSendToBackFromISR
Queue_SendFromISR(&ecuCanRxQueue, &rxMsg, sizeof(CanRxMsg_t));
}
(2) 替代xQueueReceive
c
/* 非阻塞出队函数 */
uint8_t Queue_Receive(Queue_t *q, void *item, uint16_t itemSize)
{
if (q->count == 0) {
return 0; // 队列空
}
// 从队头取出数据
memcpy(item, (uint8_t*)q->buffer + q->tail * itemSize, itemSize);
q->tail = (q->tail + 1) % q->size;
q->count--;
return 1; // 成功
}
/* 使用示例 */
CanRxMsg_t mscRxMsg;
if (Queue_Receive(&mscCanRxQueue, &mscRxMsg, sizeof(CanRxMsg_t))) {
// 处理接收到的消息
}
(3) 替代xQueueSendToBack
c
/* 非阻塞入队函数 */
uint8_t Queue_Send(Queue_t *q, void *item, uint16_t itemSize)
{
if (q->count >= q->size) {
return 0; // 队列满
}
// 拷贝数据到队尾
memcpy((uint8_t*)q->buffer + q->head * itemSize, item, itemSize);
q->head = (q->head + 1) % q->size;
q->count++;
return 1; // 成功
}
/* 使用示例 */
CanTxMsg_t TxMessageTemp;
// 填充TxMessageTemp...
Queue_Send(&mscCanTxQueue, &TxMessageTemp, sizeof(CanTxMsg_t));
4. 主循环处理
c
int main(void)
{
// 初始化硬件和队列
Queues_Init();
CAN_Init();
while (1) {
// 处理发送队列
CanTxMsg_t txMsg;
if (Queue_Receive(&mscCanTxQueue, &txMsg, sizeof(CanTxMsg_t))) {
// 通过CAN硬件发送消息
CAN_SendMessage(txMsg.id, txMsg.data, txMsg.length);
}
// 其他任务...
}
}
关键点说明
中断安全:在中断中操作队列时使用__disable_irq()/__enable_irq()
内存管理:使用memcpy确保数据正确拷贝
非阻塞设计:所有函数立即返回,不等待
通用队列:通过itemSize参数支持不同消息类型
这个实现完整替代了FreeRTOS队列功能,同时保持了裸机环境下的高效性和可靠性。