非常实用的裸机多任务实现方法

1.相对于上一个版本增加中间接口,全部代码都粘贴到了文章中,无任何收费,大家动动小手点个收藏关注。

2.你是否有这种烦恼?

        1)控制不同灯的不同闪烁频率,每个灯的闪烁速率不同,于是乎,定义了一大堆的标志位去控制不同的周期闪烁?想要控制它停止你又得有其他的标志位,逻辑复杂,标志位特别多,if else特别长?而且几乎不能维护!不是吧,不是吧,还有人这么写的吗?

        2) 我想要一个低速率的PWM方波,1k以下,不想用定时器实现,想用软件实现,于是乎,又是一大堆标志位变量和复杂的逻辑!!!!同样维护成本及高,看得让人头皮发麻,不会有人是这么做的吧?不会吧?

        3)我想要设置一个重复间隔执行动作,比如说开门关门,开门后延时一段时间在关门,再间隔一段时间在开门,这个又需要更加庞大的标志位和变量,维护?不存在的

3.这篇文章呢,就是为了解决这种烦恼,这个适配了大多数场景,如果发现不能适配的可以联系作者,后续更新哦。

        4) 又或者单片机rom装不下市面上的操作系统,又或者ram不够?,用起来麻烦,不会?学习成本高?怕不稳定?

怎么办呢?不会吧,还有人在跑裸机加函数指针数组的形式吧,太落后了,功能太单一了!!!

没事的,我这个能满足你!

4.接下来就是正文了!

5.当然这个也是有不足之处的,比如说,没有优先级,只能顺序执行,这个和操作系统的区别还是很大的,适合用在实时性不是那么强的场景。

6.好处有哪些呢?减少了一大堆的逻辑判断和变量标志,简化了程序设计时间,更加易于维护!

直接上图不罗嗦(图很丑别吐槽)

 这个图够清楚了吧,就不扒拉太多了

typedef struct
{
	char name[12];
	int count; 		//需要执行的次数
	int current; 	//当前计数值
	int timer; 		//一次的时长
	int interval;
	void (* enter_applocation)(const char * name, int  count);//时间到达需要执行的动作
	void (*mid_applocation)(const char * name, int  count);
	void (* exti_applocation)(const char * name, int  count);//时间到达需要执行的动作
	void (*cancel_handle)(const char * name, int  count);
}reckon_by_time;

name:每个任务都有一个固定的任务名,通过这个任务名去添加与删除任务,不会存在相同的任务名,如有相同的自带机制会顶替原有任务。

count:这个任务需要执行多少次,也就是上面说的,闪烁灯,闪多少次,开关门多少次,如果设置为-1为无限次数,不会终止

current:这个你不需要设置,内部用的

其他的图上面有说明了,就不哔哔赖赖了。

程序接口主要用于执行重复性的事情,以及用作裸机任务栈,如果添加任务不成功,可以修改BYTIMESIZE  宏大小,增加任务池大小。

直接上干货,不罗嗦!

chrono.h

#ifndef __CHRONOSCOPE_H__
#define __CHRONOSCOPE_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <string.h>
//#define CHRONO_RTTHREAD 
#define TASKNAMELEN 20
#define BYTIMESIZE  20



typedef struct
{
	char name[TASKNAMELEN];
	int count; 		//需要执行的次数
	int current; 	//当前计数值
	int timer; 		//一次的时长
	int interval;
	void (* enter_applocation)(const char * name, int  count);//时间到达需要执行的动作
	void (*mid_applocation)(const char * name, int  count);
	void (* exti_applocation)(const char * name, int  count);//时间到达需要执行的动作
	void (*cancel_handle)(const char * name, int  count);
}reckon_by_time;


typedef struct
{
	reckon_by_time rbt[BYTIMESIZE];
	int size;
	#ifdef CHRONO_RTTHREAD
	struct rt_mutex rt_mutex_t;
	#endif
}BytimePool;
	
	
void chrono_scope_task(void);

void init_by_time_pool(void);	

int add_by_time_task(const char * name, int count, int timer,int interval, 
	void (* enter_applocation)(), 
		void (* exti_applocation)(),
			void (*cancel_handle)());
		
int add_bt_mid_task(const char * name, int count, int timer,int interval, 
	void (* enter_applocation)(const char * name, int  count), 
		void (* mid_applocation)(const char * name, int  count), 
		void (* exti_applocation)(const char * name, int  count),
			void (*cancel_handle)(const char * name, int  count));
				
int add_bt_simp_task(const char * name, int count, int timer,
	void (* enter_applocation)(const char * name, int  count));		

void delete_by_time_task(const char * name);



#ifdef __cplusplus
}
#endif

#endif 









chrono.c

/*********************************************************************************
  *Copyright(C) -
  *FileName: chrono.c
  *Author: 我不是阿沸
  *Version: 3.6
  *Date: 2023.09.15
  *Description:  程序接口主要用于执行重复性的事情,以及用作裸机任务栈  
  *Others:  使用接口前一定调用初始化接口,这里只适配了rt_thread数据安全接口,如需要使用可以打开相关
  			宏定义,其他操作系统数据安全需自行实现  
  *History:  
     1.Date:2023/08/24
       Author:我不是阿沸 
       Modification:修改原来的任务id为任务名 ,修改原来与id相关的接口,增加简化版初始化接口。
     2.Date:2023/09/15
       Author:我不是阿沸 
       Modification:增加中间接口,用于直行到一半时产生中间异步回调,解决死锁问题。
	 3.其他修改 
**********************************************************************************/

#include "chrono.h"



static BytimePool bytimePool;


/**
  * @brief  初始化任务池
  * @retval None
  */
void init_by_time_pool(void)
{
    bytimePool.size = 0;
#ifdef CHRONO_RTTHREAD
    if(RT_EOK != rt_mutex_init( &(bytimePool.rt_mutex_t), "bytime_pool", RT_IPC_FLAG_FIFO))
    {

        return;
    }
    rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
}


/**
  * @brief  添加任务
  * @param  count为任务执行次数,如果为-1为永久执行.
  * @param  进入任务与退出任务的执行时间,注意这个时间只与任务监测线程的时间片有关
  * @param  每次任务的间隔时间
  * @param  进入任务事件
  * @param  退出任务事件
  * @param  任务到期完成回调
  * @retval 任务索引
  */
int add_by_time_task(const char * name, int count, int timer,int interval,
                     void (* enter_applocation)(const char * name, int  count),
                     void (* exti_applocation)(const char * name, int  count),
                     void (*cancel_handle)(const char * name, int  count))
{
#ifdef CHRONO_RTTHREAD
    rt_mutex_take(&(bytimePool.rt_mutex_t), RT_WAITING_FOREVER);
#endif
    if(bytimePool.size >= BYTIMESIZE)
    {
#ifdef CHRONO_RTTHREAD
        rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
        return -1;
    }
    int id = -1;
    for(int i = 0; i < bytimePool.size; i++)
    {
        if(strncmp(bytimePool.rbt[i].name, name, TASKNAMELEN) == 0)
        {
            //不允许存在相同名字任务
            id = i;
            break;
        }
    }

    if(id < 0 || id >= bytimePool.size)
    {
        id =  bytimePool.size;
    }

    reckon_by_time * rbt = bytimePool.rbt + id;

    bytimePool.size++;

    if(strlen(name) > TASKNAMELEN-1)
    {
#ifdef CHRONO_RTTHREAD
        rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
        return -1;
    }
    strcpy(rbt->name, name);
    rbt->count = count;
    rbt->timer = timer;
    rbt->interval = timer+interval;
    rbt->current = 0;
    rbt->enter_applocation = enter_applocation;
    rbt->exti_applocation = exti_applocation;
    rbt->cancel_handle = cancel_handle;
#ifdef CHRONO_RTTHREAD
    rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
    return bytimePool.size - 1;
}


/**
  * @brief  添加任务
  * @param  count为任务执行次数,如果为-1为永久执行.
  * @param  进入任务与退出任务的执行时间,注意这个时间只与任务监测线程的时间片有关
  * @param  每次任务的间隔时间
  * @param  进入任务事件
  * @param  中间任务事件
  * @param  退出任务事件
  * @param  任务到期完成回调
  * @retval 任务索引
  */
int add_bt_mid_task(const char * name, int count, int timer,int interval,
                    void (* enter_applocation)(const char * name, int  count),
                    void (* mid_applocation)(const char * name, int  count),
                    void (* exti_applocation)(const char * name, int  count),
                    void (*cancel_handle)(const char * name, int  count))
{
#ifdef CHRONO_RTTHREAD
    rt_mutex_take(&(bytimePool.rt_mutex_t), RT_WAITING_FOREVER);
#endif
    if(bytimePool.size >= BYTIMESIZE)
    {
#ifdef CHRONO_RTTHREAD
        rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
        return -1;
    }
    int id = -1;
    for(int i = 0; i < bytimePool.size; i++)
    {
        if(strncmp(bytimePool.rbt[i].name, name, TASKNAMELEN) == 0)
        {
            //不允许存在相同名字任务
            id = i;
            break;
        }
    }

    if(id < 0 || id >= bytimePool.size)
    {
        id =  bytimePool.size;
    }

    reckon_by_time * rbt = bytimePool.rbt + id;

    bytimePool.size++;

    if(strlen(name) > TASKNAMELEN-1)
    {
#ifdef CHRONO_RTTHREAD
        rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
        return -1;
    }
    strcpy(rbt->name, name);
    rbt->count = count;
    rbt->timer = timer;
    rbt->interval = timer+interval;
    rbt->current = 0;
    rbt->enter_applocation = enter_applocation;
    rbt->mid_applocation = mid_applocation;
    rbt->exti_applocation = exti_applocation;
    rbt->cancel_handle = cancel_handle;
#ifdef CHRONO_RTTHREAD
    rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
    return bytimePool.size - 1;
}

/**
  * @brief  添加任务
  * @param  count为任务执行次数,如果为-1为永久执行.
  * @param  进入任务与退出任务的执行时间,注意这个时间只与任务监测线程的时间片有关
  * @param  进入任务事件
  * @retval 任务索引
  */
int add_bt_simp_task(const char * name, int count, int timer,
                     void (* enter_applocation)(const char * name, int  count))
{
#ifdef CHRONO_RTTHREAD
    rt_mutex_take(&(bytimePool.rt_mutex_t), RT_WAITING_FOREVER);
#endif
    if(bytimePool.size >= BYTIMESIZE)
    {
#ifdef CHRONO_RTTHREAD
        rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
        return -1;
    }
    int id = -1;
    for(int i = 0; i < bytimePool.size; i++)
    {
        if(strncmp(name, bytimePool.rbt[i].name, TASKNAMELEN) == 0)
        {
            //不允许存在相同名字任务
            id = i;
            break;
        }
    }

    if(id < 0 || id >= bytimePool.size)
    {
        id =  bytimePool.size;
    }

    reckon_by_time * rbt = bytimePool.rbt + id;

    bytimePool.size++;

    if(strlen(name) > TASKNAMELEN-1)
    {
#ifdef CHRONO_RTTHREAD
        rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
        return -1;
    }
    strcpy(rbt->name, name);
    rbt->count = count;
    rbt->timer = timer;
    rbt->interval = timer+0;
    rbt->current = 0;
    rbt->enter_applocation = enter_applocation;
    rbt->mid_applocation = NULL;
    rbt->exti_applocation = NULL;
    rbt->cancel_handle = NULL;
#ifdef CHRONO_RTTHREAD
    rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
    return bytimePool.size - 1;
}


/**
  * @brief  删除任务
  * @param  任务ID
  * @retval None
  */
void delete_by_time_task(const char * name)
{
#ifdef CHRONO_RTTHREAD
    rt_mutex_take(&(bytimePool.rt_mutex_t), RT_WAITING_FOREVER);
#endif
    int id = -1;
    for(int i = 0; i < bytimePool.size; i++)
    {
        if(strcmp(bytimePool.rbt[i].name, name) == 0)
        {
            //不允许存在相同名字任务
            id = i;
            break;
        }
    }
    if(id < 0 || id >= bytimePool.size)
    {
#ifdef CHRONO_RTTHREAD
        rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
        return;
    }
    else	if(bytimePool.rbt[id].cancel_handle != NULL)
    {
        bytimePool.rbt[id].cancel_handle(bytimePool.rbt[id].name, bytimePool.rbt[id].count);
    }

    bytimePool.rbt[id] = bytimePool.rbt[bytimePool.size - 1];
    bytimePool.size--;
#ifdef CHRONO_RTTHREAD
    rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
}

/**
  * @brief  任务池监测线程,时基会影响任务定时的执行,一般为1ms为时基
  * @retval None
  */
void chrono_scope_task(void)
{
#ifdef CHRONO_RTTHREAD
    rt_mutex_take(&(bytimePool.rt_mutex_t), RT_WAITING_FOREVER);
#endif
    for(int i = 0; i < bytimePool.size; i++)
    {
        reckon_by_time * rbt = bytimePool.rbt + i;
        if(rbt->count > 0 || rbt->count < 0)
        {
            if(rbt->current == 0)
            {
                if(rbt->enter_applocation != NULL)
                {
                    rbt->enter_applocation(rbt->name, rbt->count);
                }

            }
            //第二阶段
            if(rbt->current == rbt->timer)
            {
                if(rbt->exti_applocation != NULL)
                {
                    rbt->exti_applocation(rbt->name, rbt->count);
                }
            }

            if(rbt->current == rbt->timer/2)
            {
                if(rbt->mid_applocation != NULL)
                {
                    rbt->mid_applocation(rbt->name, rbt->count);
                }

            }
            rbt->current++;

            //第三阶段 重置
            if(rbt->current == rbt->interval)
            {
                rbt->current = 0;
                if(rbt->count > 0) rbt->count--;
            }
        }
        else
        {
            if(bytimePool.rbt[i].cancel_handle != NULL)
            {
                bytimePool.rbt[i].cancel_handle(rbt->name, rbt->count);
            }

            //直接拿最后一个替换
            bytimePool.rbt[i] = bytimePool.rbt[bytimePool.size - 1];

            bytimePool.size--;
        }
    }
#ifdef CHRONO_RTTHREAD
    rt_mutex_release(&(bytimePool.rt_mutex_t));
#endif
}


示例:

void expand_enter(const char * name, int count)
{
	static int __time_ex = 0;
	if(__time_ex >= 20) __time_ex = 0;
	__time_ex++;
	pwm_para pwm;
	
	//if(__time_ex == NULL) return;
	
	pwm_ctr.freq = __freq_bf[__time_ex];
	cmp_by_angle(&pwm_ctr, &pwm);
	set_pwm_value(&pwm);
}

AF_DATA_TYPE switch_convert(AF_DATA_TYPE data, AF_DATA_TYPE src){
	if(preset.expand > 0 && data % 2 == 1)
	{
		__freq_bf = rand_freq(preset.freq, preset.expand);
		//开启拓频
		add_by_time_task("expand", -1, 1, 1, expand_enter, NULL, NULL);
	}
	else
	{
		delete_by_time_task("expand");
	}
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值