马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
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 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. 队列初始化
- 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硬件读取数据...
-
- // 替代xQueueSendToBackFromISR
- Queue_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队列功能,同时保持了裸机情况下的高效性和可靠性。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |