网上DSP用Ucos或者FreeRTOS的资料很少,找DeepSeek分析原因:
=======================================================
在数字信号处理(DSP)开发中,使用像 uC/OS 或 FreeRTOS 这类实时操作系统(RTOS)的情况确实相对较少,尤其是在对性能、实时性、资源占用和确定性要求极高的传统 DSP 应用中。这背后有多方面的原因,下面我们逐一分析:
一、DSP 应用的特性决定了对操作系统的需求不同
- 实时性与确定性要求极高
许多 DSP 应用(如音频处理、雷达信号处理、电机控制、通信基带处理等)对 实时性 和 确定性 要求非常高。
例如,一个音频采样率为 48kHz 的系统,每 20.83 微秒就要处理一个采样点,延迟必须非常精确且可控。
传统 RTOS(如 FreeRTOS/uC/OS)虽然也是实时的,但它们的任务调度、中断处理、上下文切换等机制会引入一定的不确定性(非严格确定性),这在某些 DSP 场景下是不可接受的。
- 资源限制
许多 DSP 芯片(尤其是低端或专用 DSP,如 TI 的 C5000、C6000 系列早期型号):
内存有限(RAM/Flash 小)
没有或只有非常基础的多任务支持
CPU 主要用于密集的数学运算,而非任务调度
在这种情况下,运行一个完整的 RTOS(哪怕是轻量级的 FreeRTOS)可能会:
占用宝贵的内存资源
增加不必要的软件复杂度
引入额外的调度延迟,影响实时性能
二、DSP 开发更倾向于“裸机”或专用框架
- 裸机(Bare-metal)开发更为常见
大多数 DSP 程序是围绕 中断驱动 和 主循环(super-loop) 模式开发的,通过精细的中断管理和任务调度逻辑,可以满足大多数实时需求。
开发者可以完全掌控:
中断优先级
任务执行顺序
内存使用
实时响应时间
相比之下,RTOS 带来了“通用性”的同时,也牺牲了一定程度的“可控性”。
- 使用专用的 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 更适合该领域
- TI-RTOS(原 DSP/BIOS)
是德州仪器(TI)为其 DSP 和 MCU 提供的实时操作系统,深度集成于 Code Composer Studio (CCS) 开发环境中。
包括:
内核(内核调度、任务管理)
硬件抽象层(HAL)
驱动支持
文件系统(如 FATFS)
网络协议栈(如 IPv4/UDP/TCP,通过 TI 的 Networking Stack)
对 DSP 的外设和指令集有 深度优化,调度延迟更小,更适合高实时性信号处理任务。
- 其他厂商的实时方案
类似地,其他 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)
