两轮平衡车_11_代码升级优化

网上DSP用Ucos或者FreeRTOS的资料很少,找DeepSeek分析原因:

=======================================================

         在数字信号处理(DSP)开发中,使用像 ​uC/OS​ 或 ​FreeRTOS​ 这类实时操作系统(RTOS)的情况确实相对较少,尤其是在对性能、实时性、资源占用和确定性要求极高的传统 DSP 应用中。这背后有多方面的原因,下面我们逐一分析:

一、DSP 应用的特性决定了对操作系统的需求不同

  1. ​实时性与确定性要求极高​

许多 DSP 应用(如音频处理、雷达信号处理、电机控制、通信基带处理等)对 ​实时性​ 和 ​确定性​ 要求非常高。

例如,一个音频采样率为 48kHz 的系统,每 20.83 微秒就要处理一个采样点,延迟必须非常精确且可控。

​传统 RTOS(如 FreeRTOS/uC/OS)虽然也是实时的,但它们的任务调度、中断处理、上下文切换等机制会引入一定的不确定性(非严格确定性),这在某些 DSP 场景下是不可接受的。​​

  1. ​资源限制​

许多 DSP 芯片(尤其是低端或专用 DSP,如 TI 的 C5000、C6000 系列早期型号):

​内存有限(RAM/Flash 小)​​

​没有或只有非常基础的多任务支持​

​CPU 主要用于密集的数学运算,而非任务调度​

在这种情况下,运行一个完整的 RTOS(哪怕是轻量级的 FreeRTOS)可能会:

占用宝贵的内存资源

增加不必要的软件复杂度

引入额外的调度延迟,影响实时性能

二、DSP 开发更倾向于“裸机”或专用框架

  1. ​裸机(Bare-metal)开发更为常见​

大多数 DSP 程序是围绕 ​中断驱动​ 和 ​主循环(super-loop)​​ 模式开发的,通过精细的中断管理和任务调度逻辑,可以满足大多数实时需求。

开发者可以完全掌控:

中断优先级

任务执行顺序

内存使用

实时响应时间

相比之下,RTOS 带来了“通用性”的同时,也牺牲了一定程度的“可控性”。

  1. ​使用专用的 DSP 框架或库​

很多 DSP 厂商(如 TI、ADI、NXP)提供了专门用于信号处理的 ​SDK、框架或库,例如:

TI 的 ​DSP/BIOS​(后来的 SYS/BIOS,现集成进 TI-RTOS)

​TI-RTOS​(包含内核、驱动、文件系统等,针对 TI DSP 和 MCU 优化)

​ADI 的 VisualDSP++ 工具链中的调度框架​

​CEVA DSP、NXP S32 等也有配套的实时运行环境​

这些框架通常 ​针对 DSP 架构高度优化,包括:

实时调度

低延迟中断管理

与 DSP 硬件外设(如 DMA、McBSP、硬件加速器)紧密集成

支持多核 DSP 的任务分配

相比之下,​FreeRTOS / uC/OS 是通用型 RTOS,不是为 DSP 的特殊需求(如高速浮点运算、硬件加速器、定点优化等)量身定制的。​​

三、专用 DSP RTOS 更适合该领域

  1. ​TI-RTOS(原 DSP/BIOS)​​

是德州仪器(TI)为其 DSP 和 MCU 提供的实时操作系统,深度集成于 Code Composer Studio (CCS) 开发环境中。

包括:

内核(内核调度、任务管理)

硬件抽象层(HAL)

驱动支持

文件系统(如 FATFS)

网络协议栈(如 IPv4/UDP/TCP,通过 TI 的 Networking Stack)

对 DSP 的外设和指令集有 ​深度优化,调度延迟更小,更适合高实时性信号处理任务。

  1. ​其他厂商的实时方案​

类似地,其他 DSP 厂商也提供 ​定制化的实时运行时环境,而不是直接采用 FreeRTOS 这类通用方案。

 ======================================================

向这种平衡小车环路控制周期为10ms,时间颗粒度无需太精确,用UCos或FreeRTOS操作系统来管理任务的会应该会更有条不紊,于是决定分别用UCos和FreeRTOS来管理平衡小车控制任务;

Ucos的任务管理初始化如下:

/******************************************************************************
 *    FILENAME : Main.c
 *
 *    PURPOSE  : uC/OS-II V2.9x + F28035 创建静态任务
 *
 *    Author: 电笔小新                      Created on: 2025年9月29日
******************************************************************************/
#include "User_Include.h"

//=============================================================================
// *  Variables & Function_Defines
//=============================================================================

CPU_STK_SIZE App_TaskStartStk[APP_TASK_STK_SIZE];

CPU_STK_SIZE App_Task1Stk[APP_TASK1_STK_SIZE];
CPU_STK_SIZE App_Task2Stk[APP_TASK2_STK_SIZE];
CPU_STK_SIZE App_Task3Stk[APP_TASK3_STK_SIZE];

//static OS_EVENT *AppTaskObjSem;

static void App_TaskStart(void *p_arg);

static void App_Task1(void *p_arg);
static void App_Task2(void *p_arg);
static void App_Task3(void *p_arg);

/*============================================================================*/

void main(void) 
{
    InitDSPSystem();
    InitParameter();

	OSInit();
	OSTaskCreateExt(App_TaskStart,
	                (void     *)0,
	                (CPU_STK  *)&App_TaskStartStk[0],
	                (INT8U     )APP_TASK_START_PRIO,
	                (INT16U    )APP_TASK_START_ID,
	                (CPU_STK  *)&App_TaskStartStk[APP_TASK_STK_SIZE-1u],
	                (INT32U    )APP_TASK_STK_SIZE,
	                (void     *)0,
	                (INT16U    )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));
	OSStart();

}


//---------------------------------------------------------------------------
// App_Functions:
//---------------------------------------------------------------------------
void APP_Tick_Init(void)
{
    EALLOW;
    PieVectTable.OS_CPU_RTOSINT = &OS_CPU_RTOSINT_Handler;   //RTOS
    InitCpuTimers();
    ConfigCpuTimer(&CpuTimer0, 60, 1000);   //定时器0初始化,第二个参数为CPU SYSCLK = 60M, 第三个参数为设定的周期,us单位
    CpuTimer0Regs.TCR.bit.TSS = 0;          // To start or restart the CPU-timer, set TSS to 0

    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;      //Enable TINT0 in the PIE
    IER |= M_INT1;                          //Enable group_1 interrupt

    EINT;                                   //Enable Global interrupt INTM
    ERTM;                                   //Enable Global interrupt DBGM
}


static void App_TaskStart(void *p_arg)
{
//   volatile CPU_INT08U os_err;

   (void)&p_arg;
   APP_Tick_Init();

//   AppTaskObjSem = OSSemCreate(0);
   OSTaskCreateExt(App_Task1,
                      (void     *)0,
                      (CPU_STK  *)&App_Task1Stk[0],
                      (INT8U     )APP_TASK1_PRIO,
                      (INT16U    )APP_TASK1_ID,
                      (CPU_STK  *)&App_Task1Stk[APP_TASK1_STK_SIZE-1u],
                      (INT32U    )APP_TASK_STK_SIZE,
                      (void     *)0,
                      (INT16U    )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));

   OSTaskCreateExt(App_Task2,
                      (void     *)0,
                      (CPU_STK  *)&App_Task2Stk[0],
                      (INT8U     )APP_TASK2_PRIO,
                      (INT16U    )APP_TASK2_ID,
                      (CPU_STK  *)&App_Task2Stk[APP_TASK2_STK_SIZE-1u],
                      (INT32U    )APP_TASK_STK_SIZE,
                      (void     *)0,
                      (INT16U    )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));

   OSTaskCreateExt(App_Task3,
                      (void     *)0,
                      (CPU_STK  *)&App_Task3Stk[0],
                      (INT8U     )APP_TASK3_PRIO,
                      (INT16U    )APP_TASK3_ID,
                      (CPU_STK  *)&App_Task3Stk[APP_TASK3_STK_SIZE-1u],
                      (INT32U    )APP_TASK3_STK_SIZE,
                      (void     *)0,
                      (INT16U    )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));
//   while(DEF_TRUE){
// //        os_err = OSSemPost(AppTaskObjSem);
//         OSTimeDlyHMSM(0, 0, 0, 1);
//     }
     OSTaskDel (APP_TASK_START_PRIO);  //删除App_TaskStart任务

}

//---------------------------------------------------------------------------
// App_task1:
//---------------------------------------------------------------------------
static void App_Task1(void *p_arg)
{
    (void)&p_arg;
    int Balance_Pwm,Velocity_Pwm,Turn_Pwm;              //平衡环PWM变量,速度环PWM变量,转向环PWM变
    while (DEF_TRUE){

         TEST1_H;
         Key_Scan();                                 //扫描按键状态
         Laser_Scan();                               //获取激光扫描结果
         Bat_volt=Get_battery_volt();                //获取电池电压
         UR_distance=Get_Distance();                 //获取超声波测量距离值
         Encoder_Left=Read_Encoder(Left);            //读取左轮编码器的值,前进为正,后退为负
         Encoder_Right=Read_Encoder(Right);          //读取右轮编码器的值,前进为正,后退为负
         Get_Velocity_Form_Encoder(Encoder_Left,Encoder_Right);    //计算车轮速度(mm/s)
         Get_Angle(Way_Angle);                       //更新姿态,10ms一次,更高的采样频率可以改善卡尔曼滤波和互补滤波的效果

         Balance_Pwm=Balance(Angle_Balance,Gyro_Balance);    //平衡PID控制 Gyro_Balance平衡角速度极性:前倾为正,后倾为负
         Velocity_Pwm=Velocity(Encoder_Left,Encoder_Right);  //速度环PID控制  记住,速度反馈是正反馈,就是小车快的时候要慢下来就需要再跑快一点
         Turn_Pwm=Turn(Gyro_Turn);


         Motor_Left=Balance_Pwm+Velocity_Pwm+Turn_Pwm;       //计算左轮电机最终PWM
         Motor_Right=Balance_Pwm+Velocity_Pwm-Turn_Pwm;      //计算右轮电机最终PWM
                                                             //PWM值正数使小车前进,负数使小车后退

         Motor_Left=Output_Limit(Motor_Left,5800,-5800);
         Motor_Right=Output_Limit(Motor_Right,5800,-5800);          //PWM限幅

         if(Pick_Up(Acceleration_Z,Angle_Balance,Encoder_Left,Encoder_Right))//检查是否小车被拿起
         Flag_Stop=1;                                                //如果被拿起就关闭电机

         Choose(Encoder_Left,Encoder_Right);                     //转动右轮选择小车模式
         if(Turn_Off(Angle_Balance,Bat_volt)==0)                  //如果不存在异常
         Set_Pwm(Motor_Left,Motor_Right);                    //赋值给PWM寄存器


         uwScope[5]=Balance_Pwm;
         uwScope[6]=Velocity_Pwm;
         uwScope[7]=Turn_Pwm;

         IPOMS_SnatchGraph();
         TEST1_L;

        OSTimeDlyHMSM(0, 0, 0, 6);
    }
}

//---------------------------------------------------------------------------
// App_task2:
//---------------------------------------------------------------------------
static void App_Task2(void *p_arg)
{
    (void)&p_arg;
    while (DEF_TRUE){
        LED1_TOGGLE;
        oled_show();  //OLED显示
        APP_Show();   //手机APP显示
        OSTimeDlyHMSM(0, 0, 0, 100);
    }
}

//---------------------------------------------------------------------------
// App_task3:
//---------------------------------------------------------------------------
static void App_Task3(void *p_arg)
{
    (void)&p_arg;
    while (DEF_TRUE){

        LED2_TOGGLE;
        TEST2_H;
        pIPOMS_CommandIn0 = u8IPOMS_CommandBuffer0;
        IPOMS_SCI();    //电脑上位机显示
        TEST2_L;

        OSTimeDlyHMSM(0, 0, 0, 500);
    }
}
//=============================================================================
// End of file.
//=============================================================================


 

FreeRTOS任务管理初始化如下:

/******************************************************************************
 *    FILENAME : Main.c
 *
 *    PURPOSE  : FreeRTOS V10.4.6 + F28035 创建静态任务
 *
 *    Author: 电笔小新                      Created on: 2025年9月29日
******************************************************************************/
#include "User_Include.h"

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

//=============================================================================
// *  Variables & Function_Defines
//=============================================================================

//Idle_task
#define STACK_SIZE  256U
static StaticTask_t idleTaskBuffer;
static StackType_t  idleTaskStack[STACK_SIZE];

//Start_task
#define START_TASK_PRIO       1          //任务优先级
#define START_STK_SIZE        128U        //任务堆栈大小
TaskHandle_t StartTask_Handle;           //任务句柄
static StaticTask_t StartTaskBuffer;
static StackType_t  StartTaskStack[START_STK_SIZE];
void Start_task(void* pvParameters);     //任务函数


//App_task1
#define APP_TASK1_PRIO        4
#define TASK1_STK_SIZE        256U
TaskHandle_t AppTask1_Handle;
static StaticTask_t AppTask1Buffer;
static StackType_t  AppTask1Stack[TASK1_STK_SIZE];
void App_task1(void * pvParameters);

//App_task2
#define APP_TASK2_PRIO        2
#define TASK2_STK_SIZE        256U
TaskHandle_t AppTask2_Handle;
static StaticTask_t AppTask2Buffer;
static StackType_t  AppTask2Stack[TASK2_STK_SIZE];
void App_task2(void* pvParameters);

//App_task3
#define APP_TASK3_PRIO        3
#define TASK3_STK_SIZE        512U
TaskHandle_t AppTask3_Handle;
static StaticTask_t AppTask3Buffer;
static StackType_t  AppTask3Stack[TASK3_STK_SIZE];
void App_task3(void* pvParameters);

//-------------------------------------------------------------------------------------------------
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
{
    while(1);
}

//-------------------------------------------------------------------------------------------------
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
    *ppxIdleTaskTCBBuffer = &idleTaskBuffer;
    *ppxIdleTaskStackBuffer = idleTaskStack;
    *pulIdleTaskStackSize = STACK_SIZE;
}

//============================================================================
// * Function    :  main()
// * Purpose     :  主函数程序入口.
// * Parameters  :
// * Return      :  Null
//============================================================================
void main(void)
{
    InitDSPSystem();
    InitParameter();

/* 创建Start_task任务 */
    StartTask_Handle = xTaskCreateStatic((TaskFunction_t ) Start_task,           // Function that implements the task.
                                         (const char*    ) "Start_task",         // Text name for the task.
                                         (uint16_t       ) START_STK_SIZE,       // Number of indexes in the xStack array.
                                         (void*          ) NULL,                 // Parameter passed into the task.
                                         (UBaseType_t    ) START_TASK_PRIO,      // Priority at which the task is created.
                                         (StackType_t*   ) StartTaskStack,       // Array to use as the task's stack.
                                         (StaticTask_t*  ) &StartTaskBuffer );   // Variable to hold the task's data structure.
    vTaskStartScheduler();
}

//============================================================================
// * Function    :  Start_task()
// * Purpose     :  为了方便管理,所有的任务创建函数都放在这个函数里面.
// * Parameters  :
// * Return      :  Null
//============================================================================
void Start_task(void* pvParameters)
{

  taskENTER_CRITICAL(); //进入临界区

/* 创建APP_task1任务 */
  AppTask1_Handle = xTaskCreateStatic((TaskFunction_t ) App_task1,           // Function that implements the task.
                                      (const char*    ) "App_task1",         // Text name for the task.
                                      (uint16_t       ) TASK1_STK_SIZE,      // Number of indexes in the xStack array.
                                      (void*          ) NULL,                // Parameter passed into the task.
                                      (UBaseType_t    ) APP_TASK1_PRIO,      // Priority at which the task is created.
                                      (StackType_t*   ) AppTask1Stack,       // Array to use as the task's stack.
                                      (StaticTask_t*  ) &AppTask1Buffer );   // Variable to hold the task's data structure.

/* 创建APP_task2任务 */
  AppTask2_Handle = xTaskCreateStatic((TaskFunction_t ) App_task2,           // Function that implements the task.
                                      (const char*    ) "App_task2",         // Text name for the task.
                                      (uint16_t       ) TASK2_STK_SIZE,      // Number of indexes in the xStack array.
                                      (void*          ) NULL,                // Parameter passed into the task.
                                      (UBaseType_t    ) APP_TASK2_PRIO,      // Priority at which the task is created.
                                      (StackType_t*   ) AppTask2Stack,       // Array to use as the task's stack.
                                      (StaticTask_t*  ) &AppTask2Buffer );   // Variable to hold the task's data structure.

/* 创建APP_task3任务 */
  AppTask3_Handle = xTaskCreateStatic((TaskFunction_t ) App_task3,           // Function that implements the task.
                                      (const char*    ) "App_task3",         // Text name for the task.
                                      (uint16_t       ) TASK3_STK_SIZE,      // Number of indexes in the xStack array.
                                      (void*          ) NULL,                // Parameter passed into the task.
                                      (UBaseType_t    ) APP_TASK3_PRIO,      // Priority at which the task is created.
                                      (StackType_t*   ) AppTask3Stack,       // Array to use as the task's stack.
                                      (StaticTask_t*  ) &AppTask3Buffer );   // Variable to hold the task's data structure.


  vTaskDelete(StartTask_Handle); //删除AppTaskCreate任务

  taskEXIT_CRITICAL();    //退出临界区
}

//---------------------------------------------------------------------------
// App_task1:
//---------------------------------------------------------------------------
void App_task1(void * pvParameters)
{
    int Balance_Pwm,Velocity_Pwm,Turn_Pwm;              //平衡环PWM变量,速度环PWM变量,转向环PWM变

    while (1)
    {

        TEST1_H;

        Key_Scan();                                 //扫描按键状态
        Laser_Scan();                               //获取激光扫描结果
        Bat_volt=Get_battery_volt();                //获取电池电压
        UR_distance=Get_Distance();                 //获取超声波测量距离值
        Encoder_Left=Read_Encoder(Left);            //读取左轮编码器的值,前进为正,后退为负
        Encoder_Right=Read_Encoder(Right);          //读取右轮编码器的值,前进为正,后退为负
        Get_Velocity_Form_Encoder(Encoder_Left,Encoder_Right);    //计算车轮速度(mm/s)
        Get_Angle(Way_Angle);                       //更新姿态,10ms一次,更高的采样频率可以改善卡尔曼滤波和互补滤波的效果

        Balance_Pwm=Balance(Angle_Balance,Gyro_Balance);    //平衡PID控制 Gyro_Balance平衡角速度极性:前倾为正,后倾为负
        Velocity_Pwm=Velocity(Encoder_Left,Encoder_Right);  //速度环PID控制  记住,速度反馈是正反馈,就是小车快的时候要慢下来就需要再跑快一点
        Turn_Pwm=Turn(Gyro_Turn);


        Motor_Left=Balance_Pwm+Velocity_Pwm+Turn_Pwm;       //计算左轮电机最终PWM
        Motor_Right=Balance_Pwm+Velocity_Pwm-Turn_Pwm;      //计算右轮电机最终PWM
                                                            //PWM值正数使小车前进,负数使小车后退

        Motor_Left=Output_Limit(Motor_Left,5800,-5800);
        Motor_Right=Output_Limit(Motor_Right,5800,-5800);          //PWM限幅

        if(Pick_Up(Acceleration_Z,Angle_Balance,Encoder_Left,Encoder_Right))//检查是否小车被拿起
        Flag_Stop=1;                                                //如果被拿起就关闭电机

        Choose(Encoder_Left,Encoder_Right);                     //转动右轮选择小车模式
        if(Turn_Off(Angle_Balance,Bat_volt)==0)                  //如果不存在异常
        Set_Pwm(Motor_Left,Motor_Right);                    //赋值给PWM寄存器


        uwScope[5]=Balance_Pwm;
        uwScope[6]=Velocity_Pwm;
        uwScope[7]=Turn_Pwm;


        IPOMS_SnatchGraph();
        TEST1_L;

        vTaskDelay(6 / portTICK_PERIOD_MS);
    }
}

//---------------------------------------------------------------------------
// App_task2:
//---------------------------------------------------------------------------
void App_task2(void * pvParameters)
{
    while (1)
    {
        LED1_TOGGLE;

        oled_show();  //OLED显示
        APP_Show();   //手机APP显示

        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

//---------------------------------------------------------------------------
// App_task3:
//---------------------------------------------------------------------------
void App_task3(void * pvParameters)
{
    while (1)
    {
        LED2_TOGGLE;
        TEST2_H;
        pIPOMS_CommandIn0 = u8IPOMS_CommandBuffer0;
        IPOMS_SCI();    //电脑上位机显示
        TEST2_L;
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

//============================================================================
// End of file.
//============================================================================

也顺便优化了一下巡线功能,之前没有考虑有多辆车子在巡线的情况,很容易发生追尾问题;针对这个问题,增加了在巡线过程,如果超声波检测到距离小于150mm,车子自动后退刹车。

优化后测试效果(红色手套的是用Ucos,白色手套用的是FreeRTOS)

 

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 4
收藏 4
关注 123
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧