xQueueSendToBackFromISR(ecuCanRxQueue, hcan->pRxMsg, &xHigherPriorityTaskWoken),xQueueReceive(mscCanRxQueue,&mscRxMsg,0)和xQueueSendToBack(mscCanTxQueue, &TxMessageTemp, 0 )這3個函數,在裸機下實現:
在裸機(無RTOS)環境下,需要手動實現隊列機制來替代FreeRTOS的這三個函數。以下是完整的裸機實現方案:
1. 隊列結構定義
#define CAN_RX_QUEUE_SIZE 20 // 接收隊列大小
#define CAN_TX_QUEUE_SIZE 30 // 發送隊列大小/* CAN接收消息結構 */
typedef struct {uint32_t id; // CAN IDuint8_t data[8]; // 數據uint8_t length; // 數據長度
} CanRxMsg_t;/* CAN發送消息結構 */
typedef struct {uint32_t id; // CAN IDuint8_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. 隊列初始化
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
/* 中斷安全入隊函數 */
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硬件讀取數據...// 替代xQueueSendToBackFromISRQueue_SendFromISR(&ecuCanRxQueue, &rxMsg, sizeof(CanRxMsg_t));
}
(2) 替代xQueueReceive
/* 非阻塞出隊函數 */
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
/* 非阻塞入隊函數 */
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. 主循環處理
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隊列功能,同時保持了裸機環境下的高效性和可靠性。