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");
}
}