STM32在裸机(无RTOS)情况下,需要手动实现队列机制来替换FreeRTOS的CAN发 ...

打印 上一主题 下一主题

主题 1526|帖子 1526|积分 4578

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
xQueueSendToBackFromISR(ecuCanRxQueue, hcan->pRxMsg, &xHigherPriorityTaskWoken),xQueueReceive(mscCanRxQueue,&mscRxMsg,0)和xQueueSendToBack(mscCanTxQueue, &TxMessageTemp, 0 )这3个函数,在裸机下实现:
在裸机(无RTOS)情况下,需要手动实现队列机制来替换FreeRTOS的这三个函数。以下是完整的裸机实现方案:
1. 队列布局界说
  1. #define CAN_RX_QUEUE_SIZE  20  // 接收队列大小
  2. #define CAN_TX_QUEUE_SIZE  30  // 发送队列大小
  3. /* CAN接收消息结构 */
  4. typedef struct {
  5.     uint32_t id;        // CAN ID
  6.     uint8_t data[8];    // 数据
  7.     uint8_t length;     // 数据长度
  8. } CanRxMsg_t;
  9. /* CAN发送消息结构 */
  10. typedef struct {
  11.     uint32_t id;        // CAN ID
  12.     uint8_t data[8];    // 数据
  13.     uint8_t length;     // 数据长度
  14. } CanTxMsg_t;
  15. /* 环形队列结构 */
  16. typedef struct {
  17.     void *buffer;       // 数据缓冲区
  18.     uint16_t size;      // 队列容量
  19.     volatile uint16_t head;  // 队头
  20.     volatile uint16_t tail;  // 队尾
  21.     volatile uint16_t count; // 当前元素数
  22. } Queue_t;
  23. /* 全局队列实例 */
  24. Queue_t ecuCanRxQueue;  // ECU CAN接收队列
  25. Queue_t mscCanRxQueue;  // MSC CAN接收队列  
  26. Queue_t mscCanTxQueue;  // MSC CAN发送队列
  27. /* 队列存储区 */
  28. CanRxMsg_t ecuRxBuffer[CAN_RX_QUEUE_SIZE];
  29. CanRxMsg_t mscRxBuffer[CAN_RX_QUEUE_SIZE];
  30. CanTxMsg_t mscTxBuffer[CAN_TX_QUEUE_SIZE];
复制代码
2. 队列初始化
  1. void Queues_Init(void)
  2. {
  3.     /* ECU接收队列 */
  4.     ecuCanRxQueue.buffer = ecuRxBuffer;
  5.     ecuCanRxQueue.size = CAN_RX_QUEUE_SIZE;
  6.     ecuCanRxQueue.head = 0;
  7.     ecuCanRxQueue.tail = 0;
  8.     ecuCanRxQueue.count = 0;
  9.    
  10.     /* MSC接收队列 */
  11.     mscCanRxQueue.buffer = mscRxBuffer;
  12.     mscCanRxQueue.size = CAN_RX_QUEUE_SIZE;
  13.     mscCanRxQueue.head = 0;
  14.     mscCanRxQueue.tail = 0;
  15.     mscCanRxQueue.count = 0;
  16.    
  17.     /* MSC发送队列 */
  18.     mscCanTxQueue.buffer = mscTxBuffer;
  19.     mscCanTxQueue.size = CAN_TX_QUEUE_SIZE;
  20.     mscCanTxQueue.head = 0;
  21.     mscCanTxQueue.tail = 0;
  22.     mscCanTxQueue.count = 0;
  23. }
复制代码
3. 替换函数实现
(1) 替换xQueueSendToBackFromISR

  1. /* 中断安全入队函数 */
  2. uint8_t Queue_SendFromISR(Queue_t *q, void *item, uint16_t itemSize)
  3. {
  4.     if (q->count >= q->size) {
  5.         return 0; // 队列满
  6.     }
  7.    
  8.     __disable_irq(); // 关中断保证原子操作
  9.    
  10.     // 拷贝数据到队尾
  11.     memcpy((uint8_t*)q->buffer + q->head * itemSize, item, itemSize);
  12.     q->head = (q->head + 1) % q->size;
  13.     q->count++;
  14.    
  15.     __enable_irq(); // 开中断
  16.    
  17.     return 1; // 成功
  18. }
  19. /* 使用示例(在CAN中断中)*/
  20. void CAN_RX0_IRQHandler(void)
  21. {
  22.     CanRxMsg_t rxMsg;
  23.     // 从CAN硬件读取数据...
  24.    
  25.     // 替代xQueueSendToBackFromISR
  26.     Queue_SendFromISR(&ecuCanRxQueue, &rxMsg, sizeof(CanRxMsg_t));
  27. }
复制代码
(2) 替换xQueueReceive
  1. /* 非阻塞出队函数 */
  2. uint8_t Queue_Receive(Queue_t *q, void *item, uint16_t itemSize)
  3. {
  4.     if (q->count == 0) {
  5.         return 0; // 队列空
  6.     }
  7.    
  8.     // 从队头取出数据
  9.     memcpy(item, (uint8_t*)q->buffer + q->tail * itemSize, itemSize);
  10.     q->tail = (q->tail + 1) % q->size;
  11.     q->count--;
  12.    
  13.     return 1; // 成功
  14. }
  15. /* 使用示例 */
  16. CanRxMsg_t mscRxMsg;
  17. if (Queue_Receive(&mscCanRxQueue, &mscRxMsg, sizeof(CanRxMsg_t))) {
  18.     // 处理接收到的消息
  19. }
复制代码
(3) 替换xQueueSendToBack
  1. /* 非阻塞入队函数 */
  2. uint8_t Queue_Send(Queue_t *q, void *item, uint16_t itemSize)
  3. {
  4.     if (q->count >= q->size) {
  5.         return 0; // 队列满
  6.     }
  7.    
  8.     // 拷贝数据到队尾
  9.     memcpy((uint8_t*)q->buffer + q->head * itemSize, item, itemSize);
  10.     q->head = (q->head + 1) % q->size;
  11.     q->count++;
  12.    
  13.     return 1; // 成功
  14. }
  15. /* 使用示例 */
  16. CanTxMsg_t TxMessageTemp;
  17. // 填充TxMessageTemp...
  18. Queue_Send(&mscCanTxQueue, &TxMessageTemp, sizeof(CanTxMsg_t));
复制代码
4. 主循环处理
  1. int main(void)
  2. {
  3.     // 初始化硬件和队列
  4.     Queues_Init();
  5.     CAN_Init();
  6.    
  7.     while (1) {
  8.         // 处理发送队列
  9.         CanTxMsg_t txMsg;
  10.         if (Queue_Receive(&mscCanTxQueue, &txMsg, sizeof(CanTxMsg_t))) {
  11.             // 通过CAN硬件发送消息
  12.             CAN_SendMessage(txMsg.id, txMsg.data, txMsg.length);
  13.         }
  14.         
  15.         // 其他任务...
  16.     }
  17. }
复制代码
关键点分析
中断安全:在中断中操作队列时利用__disable_irq()/__enable_irq()
内存管理:利用memcpy确保数据精确拷贝
非阻塞计划:全部函数立即返回,不等待
通用队列:通过itemSize参数支持不同消息范例
这个实现完整替换了FreeRTOS队列功能,同时保持了裸机情况下的高效性和可靠性。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

干翻全岛蛙蛙

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表