学习记录(一) 系统任务调度进程算法 TaskProcess()

本文解析了STM32CubeMX生成的主函数及其任务调度机制。通过滴答时钟中断处理函数更新全局变量OSTick,进而触发任务调度。文章详细介绍了如何利用定时器和中断实现精确的任务调度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主函数为一些STM32CubeMX生成工程时写好的初始化函数,及一个while(1)轮询,里面是系统任务调度进程函数。

int main(void)
{
      /* 初始化 */
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    while (1)
    {
        TaskProcess();    //系统任务调度进程函数
    }
}

该函数定义:当变量OSTickSave和OSTick不相等时进入if语句,而它们都被初始化为0,先看它们何时不相等。

static void TaskProcess(void)
{
    u8 i = 0;
    static u32 OSTickSave = 0;

    if (OSTickSave != OSTick)    //全局变量 vu32 OSTick = 0;
    {
        SetMacbRemarks((u16)(OSTick - OSTickSave));
        OSTickSave = OSTick;

        //  MCL_MAX为任务总个数,如果定义N个任务,
        //  必须对N个任务初始化,否则程序会出错
        for (i = 0; i < MCL_MAX; i++)
        {
            if ( (theComps[i].inrun) && (theComps[i].lpTaskHook != 0) )
            {
                theComps[i].lpTaskHook();
                theComps[i].inrun = 0;
            }
        }
    }
}

通过OSTick找到滴答时钟中断处理函数,该函数在系统滴答时钟句柄函数中调用。在startup文件已写好,每1ms产生一次中断调用此句柄函数。即每1ms OSTick++,所以在TaskProcess()中表现为等待每1ms产生的一次中断使OSTick+1,进入if调用SetMacbRemarks()函数并传入两变量之差,再如上赋值,这使两变量之差一直为1。

/* 滴答时钟中断处理函数 */
void TimingDelay_Decrement(void)
{
    OSTick++;	//task counter
}
/* stm32g4xx_it.c */

void SysTick_Handler(void)
{
	TimingDelay_Decrement();
}

再看SetMacbRemarks()函数定义,for循环对任务数组遍历,每个成员的clock元素+dif(=1),当clock加到>=timer且mode为AUTO时将clock清零inrun置一,当mode为ALWAYS时inrun置一。先研究任务数组如下(直接拷贝了原例程)。

void SetMacbRemarks(u16 dif)
{
    u8 i = 0;
    for (i = 0; i < MCL_MAX; i++)    //MCL_MAX为任务总数
    {
        theComps[i].clock += dif;
        if ( (theComps[i].clock >= theComps[i].timer) && (theComps[i].mode == MCM_AUTO) )
        {
            theComps[i].clock = 0;
            theComps[i].inrun = 1;
        }
        else if (theComps[i].mode == MCM_ALWAYS)
        {
            theComps[i].inrun = 1;
        }
    }
}
typedef struct _MAINAPP_COMPONENTS
{
	u8 inrun;
	u16 clock;
	u16 timer;
	u8 mode;
	void (*lpTaskHook)(void);
} MAINAPP_COMPONENTS;


#ifdef START_APP_FUNCTION
/* Local array variable in this file.
** ==================================================================
**    theComps			: application task in array list.
**    theCans			: can data buffer in array list.
**    theUartCommand    : uart command in array list.
** ==================================================================
*/

static MAINAPP_COMPONENTS	theComps[] =
{
    //{  0,	0,	100,        MCM_AUTO,		App_Led      },
    //{  0,	0,	1000,       MCM_AUTO,		App_ADC5      },
#if FMSTR_USART_DEBUG
    {  0,	0,	1,          MCM_AUTO,		App_FMSTR      },
#endif
#if SENSOR_FILTER_MS
    {  0,   0,  1,          MCM_AUTO,       App_SensorFilter_ms},
#endif 
    {  0,   0,  5,          MCM_AUTO,       App_FeedWD     },
    {  0,   0,  900,        MCM_AUTO,       App_GetDate    },
#ifdef ERROR_CHECK
	{  0,	0,	5,          MCM_AUTO,		App_ERROR_T1    },
	{  0,	0,	1,          MCM_AUTO,		App_ERROR_T2      },
#endif //ERROR_CHECK
    {  0,   0,  100,        MCM_AUTO,       App_CoolingFan  },
    
    // 空进程,若需添加软件定时处理过程,请在此之前添加,并在main.h MAINAPP_COMPONENTS_LIST枚举中按顺序添加新成员
    {  0,   0,  1000,       MCM_AUTO,       App_EndProcess  },

};

#endif

可看出inrun是任务运行标志,clock相当于每1ms+1的计数器,而timer相当于调用周期,mode是运行模式,lpTaskHook是函数指针。

最后回看TaskProcess()函数可知当任务inrun为1且lpTaskHook非0时,执行一次lpTaskHook所指函数且将inrun清零。

综上所述,一个初始化为{  0,    0,    100,       MCM_AUTO,        App_Xxx }的任务,每100ms执行一次APP_Xxx函数,可根据需求改变。



优化,删去暂不会用的,增加偏移量,考虑可能有单个轮询周期执行任务超过1ms(堵塞)情况,为保证同周期不同任务偏移生效改了算法:

typedef struct _MAINAPP_COMPONENTS
{
	u8 offset;
	u16 clock;
	u32 period_counter;
	u16 period;
	void (*p_func)(void);

} MAINAPP_COMPONENTS;


static void task_process_func(MAINAPP_COMPONENTS* p_comps, u32 number_of_tasks)
{
    static u32 OSTick_last = 0;

    if (OSTick_last != SYS_TICK)
    {
        OSTick_last = SYS_TICK;
        
        for (u8 i = 0; i < number_of_tasks; i++)
        {
            if(SYS_TICK - p_comps[i].clock >= p_comps[i].period + p_comps[i].offset
            && p_comps[i].p_func != 0 )
            {
                p_comps[i].period_counter++;
                p_comps[i].clock = p_comps[i].period_counter * p_comps[i].period;
                p_comps[i].p_func();
            }
            else{}
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值