张同学03 2025-03-02 17:02 采纳率: 50%
浏览 6

FreeRTOS平衡车

stm32和FreeRTOS的平衡小车代码如下,能编译不报错,但在小车上不运行OLED都不显示
/* 头文件 */

#include "stm32f10x.h" // Device header
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"  // 包含队列头文件
#include "semphr.h" // 包含信号量头文件
#include "math.h"   // 包含数学函数头文件

#include "OLED.h"
#include "EXTI.h"
#include "encoder.h"
#include "motor.h"
#include "mpu6050.h"
#include "mpuiic.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "pid.h"
//#include "sys.h"
#include "usart2.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
#include "led.h"


// 优先级定义(数值越大优先级越高)
#define TASK_PRIO_HARD_REAL_TIME   4  // 硬实时控制
#define TASK_PRIO_SAFETY           3  // 安全监控
#define TASK_PRIO_SENSOR           5  // 传感器融合
#define TASK_PRIO_COMM             2  // 通信处理
#define TASK_PRIO_HMI              1  // 人机界面

//// 任务句柄
static TaskHandle_t xHardRealTimeHandle = NULL;
static TaskHandle_t xSafetyHandle = NULL;
static TaskHandle_t xSensorFusionHandle = NULL;
static TaskHandle_t xCommHandle = NULL;
static TaskHandle_t xHmiHandle = NULL;

float a=42,b=1.6,c=120,d=0.6;//
int Bluetooth_data;
int Target = 0;
float Angle_turn = 0;
int L_Speed, R_Speed;
float pitch, roll, yaw; // 欧拉角
short aacx, aacy, aacz; // 加速度传感器原始数据
short gyrox, gyroy, gyroz; // 陀螺仪原始数据
extern int Moto1, Moto2;
u8 stop_flag = 0;
//void YunDong(void);
//void My_XianShi(void);
extern u8 Fore, Back, Left, Right;

// 创建互斥锁和队列
SemaphoreHandle_t xMotorMutex;
SemaphoreHandle_t xPidMutex;
QueueHandle_t xAngleQueue;
QueueHandle_t xCmdQueue;

// 函数声明



void Error_Handler(void);
int16_t USART2_Receive(uint8_t *buf, uint16_t len);
u8 mpu_dmp_get_data(float *pitch, float *roll, float *yaw);
void MPU6050_EXTI_Init(void);
u8 mpu_dmp_init(void);
int Velocity(int target, int encoder_left, int encoder_right);

/* 硬件初始化 */
void Hardware_Init(void) {
//    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
//    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
    OLED_Init();
    TIM3_Encoder_Init();
    TIM4_Encoder_Init();
    MOTOR_Init();
    TIM2_PWM_Init(7199, 0);
    MPU6050_EXTI_Init();
    MPU_Init();
    mpu_dmp_init();
    PID_Init();
//    uart2_Init();
    //LED_Init();
    // 在Hardware_Init()中添加检查
        if(mpu_dmp_init() != 0){
                OLED_ShowString(1,1,"DMP FAIL!");
                while(1); // 阻塞初始化
        }
    printf("%0.2f,%0.2f,%0.2f,%0.2f\n",a,b,c,d);
}

//硬实时控制任务(最高优先级)
void vHardRealTimeTask(void *pvParameters)
{
    const TickType_t xPeriod = pdMS_TO_TICKS(1); // 1ms周期
    TickType_t xLastWakeTime = xTaskGetTickCount();
    
    while(1) {
        // 读取编码器(原子操作)
        portENTER_CRITICAL();
        L_Speed = Read_Encoder(3);
        R_Speed = Read_Encoder(4);
        portEXIT_CRITICAL();
        
        // 获取融合后的角度
        float current_angle;
        xQueueReceive(xAngleQueue, &current_angle, 0);

        // PID计算(参数保护)
        xSemaphoreTake(xPidMutex, portMAX_DELAY);
        Moto1 = balance(current_angle, gyrox) + Velocity(Target, L_Speed, R_Speed);
        Moto2 = balance(current_angle, gyrox) + Velocity(Target, L_Speed, R_Speed);
        xSemaphoreGive(xPidMutex);

        // 电机输出(带互斥锁)
        if(xSemaphoreTake(xMotorMutex, pdMS_TO_TICKS(0)) == pdTRUE) {
            Set_Pwm(Moto1, Moto2);
            xSemaphoreGive(xMotorMutex);
        }

        vTaskDelayUntil(&xLastWakeTime, xPeriod);
    }
}

//传感器融合任务
void vSensorFusionTask(void *pvParameters)
{
    float fused_angle = 0;
    while(1) {
        // 获取DMP数据(带超时保护)
        if(mpu_dmp_get_data(&pitch, &roll, &yaw) == 0) {
            // 数据滤波(示例:互补滤波)
            fused_angle = 0.98*(fused_angle + gyrox*0.001) + 0.02*roll;
            
            // 发送到控制任务
            xQueueOverwrite(xAngleQueue, &fused_angle);
        }
        vTaskDelay(pdMS_TO_TICKS(5)); // 200Hz更新
    }
}

//安全监控任务
void vSafetyTask(void *pvParameters)
{
    float current_angle;
    while(1) {
        xQueuePeek(xAngleQueue, &current_angle, portMAX_DELAY);
        
        // 倾角保护
        if(fabs(current_angle) > 40.0f) {
            xSemaphoreTake(xMotorMutex, portMAX_DELAY);
            Motor_EmergencyStop();
            xSemaphoreGive(xMotorMutex);
            vTaskSuspendAll();
        }
        
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

//通信任务优化
void vCommTask(void *pvParameters)
{
//    uint8_t uart_buf[64];
    while(1) {
            
//            USART2_IRQHandler();
//        // 非阻塞读取
//        int16_t len = USART2_Receive(uart_buf, sizeof(uart_buf));
//        if(len > 0) {
//            // 协议解析
//            if(parse_bluetooth_cmd(uart_buf, len)) {
//                xQueueSend(xCmdQueue, &Bluetooth_data, 0);
//            }
//        }
//        
//        // 发送状态数据
//        static uint32_t last_send = 0;
//        if(xTaskGetTickCount() - last_send > pdMS_TO_TICKS(20)) {
//            send_status_packet();
//            last_send = xTaskGetTickCount();
//        }
        
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}

//人机界面任务
void vHmiTask(void *pvParameters)
{
    OLED_Clear();
    while(1) {
        //OLED_ShowHexNum(1, 1, Bluetooth_data, 2);
        OLED_ShowSignedNum(2, 1, L_Speed, 5);
        OLED_ShowSignedNum(3, 1, R_Speed, 5);
        OLED_ShowSignedNum(4, 1, pitch, 5);
        OLED_ShowSignedNum(5, 1, roll, 5);
        OLED_ShowSignedNum(6, 1, yaw, 5);
//        // 双缓冲显示
//        static uint8_t disp_buf[2][128];
//        static uint8_t front = 0;
//        
//        // 后台准备数据
//        prepare_display_data(disp_buf[1-front]);
//        
//        // 切换显示缓冲
//        OLED_Refresh(disp_buf[front]);
//        front = !front;
        
        vTaskDelay(pdMS_TO_TICKS(100)); // 10Hz刷新
    }
}

void EXTI9_5_IRQHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    if(EXTI_GetITStatus(EXTI_Line8) == SET) {
        // 直接处理关键操作
        Motor_QuickBrake();
        
        // 发送快速通知
        xTaskNotifyFromISR(xSafetyHandle, 
                          1 << 0, // SAFETY_EVENT_OBSTACLE
                          eSetBits,
                          &xHigherPriorityTaskWoken);
        
        EXTI_ClearITPendingBit(EXTI_Line8);
    }
    
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}


/* 添加缺失的函数实现 */
void Error_Handler(void) 
{
    OLED_ShowString(1, 1, "SYSTEM FAULT!");

}

///* MPU6050初始化状态检查 */
//void MPU_Init(void) {
//    if(!MPU6050_Init()) {
//        Error_Handler();
//    }
//}
int main(void)
{
    Hardware_Init();
    
    // 创建RTOS对象
    xAngleQueue = xQueueCreate(1, sizeof(float));
    xCmdQueue = xQueueCreate(5, sizeof(int));
    xMotorMutex = xSemaphoreCreateMutex();
    xPidMutex = xSemaphoreCreateMutex();
    
    // 确保互斥锁和队列创建成功
    if (xMotorMutex == NULL || xAngleQueue == NULL || xCmdQueue == NULL || xPidMutex == NULL) {
        // 处理创建失败的情况
        Error_Handler();
    }

    // 初始释放互斥锁
    xSemaphoreGive(xMotorMutex);

    // 创建任务
    xTaskCreate(vHardRealTimeTask, "Ctrl", 256, NULL, TASK_PRIO_HARD_REAL_TIME, &xHardRealTimeHandle);
    xTaskCreate(vSafetyTask, "Safety", 192, NULL, TASK_PRIO_SAFETY, &xSafetyHandle);
    xTaskCreate(vSensorFusionTask, "Sensor", 384, NULL, TASK_PRIO_SENSOR, &xSensorFusionHandle);
    xTaskCreate(vCommTask, "Comm", 256, NULL, TASK_PRIO_COMM, &xCommHandle);
    xTaskCreate(vHmiTask, "HMI", 192, NULL, TASK_PRIO_HMI, &xHmiHandle);
    
    // 启动调度器
    vTaskStartScheduler();
    
    // 故障处理
    while(1) {
        Error_Handler();
    }
}

  • 写回答

3条回答 默认 最新

  • 阿里嘎多学长 2025-03-02 17:03
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    问题解答

    你提供了stm32和FreeRTOS的平衡小车代码,但是小车上OLED不显示。首先,我们需要检查代码是否正确无误,是否有任何错误或警告。

    从代码中可以看到,你使用了stm32f10x.h头文件,这个头文件是stm32的官方头文件,可以使用。

    接下来,我们需要检查FreeRTOS的配置和初始化是否正确。FreeRTOS需要在main函数中初始化,使用xTaskCreate函数创建任务,使用vTaskStartScheduler函数启动任务调度器。

    在你的代码中,可能缺少FreeRTOS的初始化和任务创建代码。下面是一个简单的示例代码:

    #include "FreeRTOS.h"
    #include "task.h"
    
    int main(void)
    {
        // 初始化FreeRTOS
        vTaskStartScheduler();
        return 0;
    }
    
    void vApplicationIdleHook(void)
    {
        // 在这里可以添加idle任务的处理代码
    }
    

    在上面的代码中,我们使用vTaskStartScheduler函数初始化FreeRTOS,使用vApplicationIdleHook函数在idle状态下执行任务。

    如果你已经初始化了FreeRTOS,但是OLED仍然不显示,那么可能是OLED驱动代码的问题。需要检查OLED驱动代码是否正确无误,是否有任何错误或警告。

    总之,问题可能出在FreeRTOS的初始化和任务创建代码中,或者OLED驱动代码中。需要检查代码和调试代码来解决问题。

    评论

报告相同问题?

问题事件

  • 创建了问题 3月2日