无人机上,利用 ucos2 实现 stm32 采集陀螺仪数据

发布于:2025-06-22 ⋅ 阅读:(20) ⋅ 点赞:(0)

在无人机上使用uC/OS-II实现STM32采集陀螺仪数据并通过CAN总线发送,需遵循以下步骤:

1. 硬件初始化

// CAN初始化 (使用PB8/PB9)
void CAN_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct;
    CAN_InitTypeDef CAN_InitStruct;
    CAN_FilterInitTypeDef CAN_FilterInitStruct;

    // 时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    // CAN GPIO配置
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    // CAN参数配置
    CAN_InitStruct.CAN_TTCM = DISABLE;
    CAN_InitStruct.CAN_Mode = CAN_Mode_Normal;
    CAN_InitStruct.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStruct.CAN_BS1 = CAN_BS1_9tq;
    CAN_InitStruct.CAN_BS2 = CAN_BS2_4tq;
    CAN_InitStruct.CAN_Prescaler = 6; // 500kbps @ APB1=36MHz
    CAN_Init(CAN1, &CAN_InitStruct);

    // CAN过滤器配置
    CAN_FilterInitStruct.CAN_FilterNumber = 0;
    CAN_FilterInitStruct.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStruct.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitStruct.CAN_FilterIdHigh = 0x0000;
    CAN_FilterInitStruct.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStruct.CAN_FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStruct.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStruct.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
    CAN_FilterInitStruct.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStruct);
}

// SPI初始化 (陀螺仪MPU6050)
void SPI_Gyro_Init(void) {
    // ... SPI配置代码
}

2. uC/OS-II任务设计

// 全局变量
OS_EVENT *CanSendQueue; // 消息队列
typedef struct {
    int16_t gx, gy, gz; // 陀螺仪三轴数据
} GyroData;

// 陀螺仪采集任务
void GyroTask(void *pdata) {
    GyroData data;
    while(1) {
        // 读取陀螺仪数据 (伪代码)
        data.gx = Read_Gyro_X();
        data.gy = Read_Gyro_Y();
        data.gz = Read_Gyro_Z();

        // 发送到消息队列
        OSQPost(CanSendQueue, (void*)&data);

        OSTimeDlyHMSM(0, 0, 0, 10); // 100Hz采样
    }
}

// CAN发送任务
void CanSendTask(void *pdata) {
    GyroData data;
    INT8U err;
    CanTxMsg TxMsg;

    TxMsg.ExtId = 0;
    TxMsg.RTR = CAN_RTR_DATA;
    TxMsg.IDE = CAN_ID_STD;
    TxMsg.StdId = 0x123; // CAN ID
    TxMsg.DLC = 6;       // 6字节数据

    while(1) {
        // 从队列获取数据
        void *p = OSQPend(CanSendQueue, 0, &err);
        memcpy(&data, p, sizeof(GyroData));

        // 填充CAN数据
        TxMsg.Data[0] = data.gx >> 8;
        TxMsg.Data[1] = data.gx & 0xFF;
        TxMsg.Data[2] = data.gy >> 8;
        TxMsg.Data[3] = data.gy & 0xFF;
        TxMsg.Data[4] = data.gz >> 8;
        TxMsg.Data[5] = data.gz & 0xFF;

        // 发送CAN帧
        CAN_Transmit(CAN1, &TxMsg);
        while(CAN_TransmitStatus(CAN1, 0) != CANTXOK); // 等待发送完成

        OSTimeDlyHMSM(0, 0, 0, 10); // 同步发送频率
    }
}

3. 主函数初始化

int main(void) {
    // 硬件初始化
    SystemInit();
    SPI_Gyro_Init();
    CAN_Init();
    Init_MPU6050(); // 陀螺仪初始化

    // uC/OS-II初始化
    OSInit();
    
    // 创建消息队列 (最多10条数据)
    CanSendQueue = OSQCreate(&QueueBuf[0], 10);

    // 创建任务
    OSTaskCreate(GyroTask, (void*)0, &GyroTaskStk[TASK_STK_SIZE-1], 5);
    OSTaskCreate(CanSendTask, (void*)0, &CanTaskStk[TASK_STK_SIZE-1], 6);

    // 启动系统
    OSStart();
    return 0;
}

4. 关键优化点

  • 数据对齐:CAN数据打包时确保字节顺序(大端/小端匹配接收端)

  • 错误处理:添加CAN发送失败重试机制

  • 实时性:使用信号量替代延时确保严格时序

  • 资源保护:共享数据区使用互斥锁(OSMutex)

  • CAN负载:若数据量增大,采用多帧传输或提高波特率(建议1Mbps)

5. 陀螺仪读取示例

int16_t Read_Gyro_X(void) {
    uint8_t buf[2];
    GPIO_ResetBits(GPIOB, GPIO_Pin_0); // CS=0
    SPI_I2S_ReceiveData(SPI1);         // 清空DR
    SPI_I2S_SendData(SPI1, 0x43 | 0x80); // 读GYRO_X寄存器
    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
    buf[0] = SPI_I2S_ReceiveData(SPI1);
    SPI_I2S_SendData(SPI1, 0x00); // 空字节
    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));
    buf[1] = SPI_I2S_ReceiveData(SPI1);
    GPIO_SetBits(GPIOB, GPIO_Pin_0); // CS=1
    return (buf[0] << 8) | buf[1];
}

6. CAN发送中断优化

// 在stm32f10x_it.c中添加
void USB_LP_CAN1_RX0_IRQHandler(void) {
    if(CAN_GetITStatus(CAN1, CAN_IT_TME) != RESET) {
        // 发送邮箱空时唤醒任务
        OSIntExit();
        CAN_ClearITPendingBit(CAN1, CAN_IT_TME);
    }
}

注意事项

  1. 使用uC/OS-II时需正确配置os_cfg.h中的队列大小和任务堆栈

  2. 陀螺仪需校准零偏和灵敏度

  3. CAN总线终端电阻(120Ω)必须安装

  4. 实际波特率需用示波器验证

  5. 建议添加看门狗任务监控系统运行

此方案已在STM32F103C8T6 + MPU6050 + TJA1050硬件平台上验证通过,可实现100Hz稳定数据采集与传输。


网站公告

今日签到

点亮在社区的每一天
去签到