一、简介
- 匿名飞控的任务调度还是比较简单的,没有操作系统什么的。
- 可以大概分成两块:
(1)利用systick定时器实现的定时执行任务,这部分都是各种逻辑,执行速度很快
(2)借助Icm20602输出的1ms脉冲实现的外部中断任务。这里主要执行传感器数据获取,执行速度比较慢,但是可以打断第一部分的各种任务。经过咨询匿名客服,这里使用传感器1ms脉冲的原因是:用传感器自己提供的时钟会让检测更准确
二、代码分析
(1)1ms中断部分
void Drv_Icm20602IrqHandler(void)
{
GPIOIntClear(ICM20602_READY_PORT, ICM20602_READY_PIN);
INT_1ms_Task();
}
void Drv_Icm20602ReadyPinInit(void)
{
ROM_SysCtlPeripheralEnable(ICM_READYPIN_SYSCTL);
ROM_GPIODirModeSet(ICM20602_READY_PORT, ICM20602_READY_PIN, GPIO_DIR_MODE_IN);
ROM_GPIOPinTypeGPIOInput(ICM20602_READY_PORT, ICM20602_READY_PIN);
ROM_GPIOPadConfigSet(ICM20602_READY_PORT,ICM20602_READY_PIN,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPD);
ROM_GPIOIntTypeSet(ICM20602_READY_PORT, ICM20602_READY_PIN , GPIO_RISING_EDGE);
GPIOIntRegister(ICM20602_READY_PORT, Drv_Icm20602IrqHandler);
GPIOIntEnable(ICM20602_READY_PORT, ICM20602_READY_PIN);
ROM_IntPrioritySet(ICM20602_READY_INT_PORT, USER_INT7);
}
#define CIRCLE_NUM 20
static u8 lt0_run_flag;
static u8 circle_cnt[2];
void INT_1ms_Task()
{
lt0_run_flag ++;
LED_1ms_DRV();
circle_cnt[0] ++;
circle_cnt[0] %= CIRCLE_NUM;
if(!circle_cnt[0])
{
}
}
static void Loop_Task_0()
{
Fc_Sensor_Get();
Sensor_Data_Prepare(1);
IMU_Update_Task(1);
WCZ_Acc_Get_Task();
WCXY_Acc_Get_Task();
Flight_State_Task(1,CH_N);
Swtich_State_Task(1);
ANO_DT_Data_Exchange();
}
(2)systick定时器调度部分
typedef struct
{
void(*task_func)(u32 dT_us);
u32 interval_ticks;
u32 last_run;
}sched_task_t;
static sched_task_t sched_tasks[] =
{
{Loop_Task_1 , 2000, 0 },
{Loop_Task_2 , 6000, 0 },
{Loop_Task_5 , 11000, 0 },
{Loop_Task_8 , 20000, 0 },
{Loop_Task_9 , 50000, 0 },
};
#define TASK_NUM (sizeof(sched_tasks)/sizeof(sched_task_t))
u8 Main_Task(void)
{
uint8_t index = 0;
if(lt0_run_flag!=0)
{
lt0_run_flag--;
Loop_Task_0();
}
uint32_t time_now,delta_time_us;
for(index=0;index < TASK_NUM;index++)
{
time_now = GetSysRunTimeUs();
if(time_now - sched_tasks[index].last_run >= sched_tasks[index].interval_ticks)
{
delta_time_us = (u32)(time_now - sched_tasks[index].last_run);
sched_tasks[index].last_run = time_now;
sched_tasks[index].task_func(delta_time_us);
}
}
return 0;
}
- 可以看到这里用了一个
sched_task_t
型的数组,存储了若干不同执行频率的“线程”,利用systick定时器判断执行时机。如果有两个任务赶在同一个时间执行,会根据任务在数组中的位置从小到大依次执行。 - 最后再看一下systick定时器读取当前时间的实现方法
static uint64_t SysRunTimeMs = 0;
void SysTick_Init(void )
{
ROM_SysTickPeriodSet(ROM_SysCtlClockGet()/1000);
ROM_SysTickIntEnable();
ROM_SysTickEnable();
}
void SysTick_Handler(void)
{
SysRunTimeMs++;
}
uint32_t GetSysRunTimeMs(void)
{
return SysRunTimeMs;
}
uint32_t GetSysRunTimeUs(void)
{
return SysRunTimeMs*1000 + (SysTick->LOAD - SysTick->VAL) * 1000 / SysTick->LOAD;
}