STM32在裸机(无RTOS)环境下,需要手动实现队列机制来替代FreeRTOS的CAN发送接收函数

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队列功能,同时保持了裸机环境下的高效性和可靠性。

相关推荐
一川月白70911 小时前
51单片机---硬件学习(电子琴、主从应答模式、modbus模型、DS18B20传感器显示温度)
嵌入式硬件·51单片机·串口通信·异步通信·串行通信·同步通信·并行通信
逼子格11 小时前
【Proteus仿真】定时器控制系列仿真——秒表计数/数码管显示时间
数据库·单片机·嵌入式硬件·51单片机·proteus·定时器·硬件工程师
2401_8884230913 小时前
51单片机-按键、蜂鸣器、定时器模块及中断
单片机·嵌入式硬件·51单片机
东亚_劲夫13 小时前
STM32—SPI协议
stm32·单片机·嵌入式硬件
♞沉寂15 小时前
c51串口通信原理及实操
单片机·51单片机·c51
猫头虎15 小时前
2025最新超详细FreeRTOS入门教程:第一章 FreeRTOS移植到STM32
stm32·单片机·嵌入式硬件·机器人·硬件架构·freertos·嵌入式实时数据库
清风66666617 小时前
基于STM32单片机的酒驾检测设计
stm32·单片机·嵌入式硬件·毕业设计·课程设计
恒森宇电子有限公司18 小时前
IP5326_BZ 支持C同口输入输出的移动电源芯片 2.4A的充放电电流 支持4LED指示灯
c语言·开发语言·单片机
涂山苏苏⁠18 小时前
STM32之ADC
stm32·单片机·adc
曙曙学编程18 小时前
stm32——NVIC,EXIT
c语言·c++·stm32·单片机·嵌入式硬件