嵌软功能场景-单个时钟源复用多事务框架

发布于:2023-10-25 ⋅ 阅读:(95) ⋅ 点赞:(0)

 一、场景

单片机一般提供2-8个时钟,通过设置参数,启动时钟。代码定义时钟回调函数,定时执行特定的业务功能。但是,业务场景正常不可能只有2-8个定时业务。基于这个情况,分享一个好用的时钟业务框架。

原理:使用开启单个时钟源,在时钟回调函数中轮询时钟事务列表,到时规定计数时,定期执行列表事务。

适用场景:时钟源少且业务定时执行精确度要求不高的场景。

缺点:时钟事务执行时间影响设置的定时精确度。

二、功能代码

以下代码使用stm32举例:

1、定义时钟事务列表

//定义定时事务结构体
typedef struct __TIMER
{
	u32 Timeoutcnt;//循环计数值
    u32 Timeout;//备份循环计数值
	void (*Timeoutfuc)(void* parameter);//定时回调函数
	void* Parameter;//传入参数
	u8 Timerflag;//是否循环(一次或者定时循环)
}Timer_typedef;

//Timerflag 标志位
#define TIMER_ONESHOT		0   //只执行一次
#define TIMER_PERIOD		1   //循环执行
#define TIMER_CLOSE		    2   //关闭

//定义事务
enum TIM_Timer_BUSSINESS{
	LED_TIMER_INDE=0,//事务1 
    STOPMODE_TIMER_INDEX=1, //事务2
	MAX_TIM_TIMER,//事务数量
};

//实例化:定义时钟事务表
static Timer_typedef TimerList[MAX_TIM_TIMER];

2、硬件时钟初始化

设置硬件闹钟1ms一次循环启动


void TIM_TimerInitialisation()
{
	u8 i = 0;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    
    TIM_DeInit(TIM2);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    //TIM2的时钟源是72M--设置TIM_Prescaler进行分频,TIM_Period为计数多少次溢出
    //如下设置72M/72=1000000HZ=1US,1ms=1000/1=1000(-1是因为0算一次计数)

    TIM_TimeBaseStructure.TIM_Period = 1000-1;                        
	TIM_TimeBaseStructure.TIM_Prescaler = 72-1; 
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	TIM_SetAutoreload(TIM2, 1000-1); 
	TIM_ARRPreloadConfig(TIM2, ENABLE); 

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  
    TIM_Cmd(TIM2, ENABLE);	
	
    //初始化时间业务表
	for(i = 0; i < MAX_TIM_TIMER; i++)
	{
		TimerList[i].Timeoutcnt = 86400001;
        TimerList[i].Timeout = 86400001;
		TimerList[i].Timeoutfuc = (void*)0;
		TimerList[i].Parameter = (void*)0;
	} 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
}

3、编写回调函数

3.1 系统注册

void TIM2_IRQHandler(void)
{
 
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
	{
		TIMER_Execute();
		//清除TIM2的中断待处理位
		TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
	}
}

3.2 业务轮询

void TIMER_Execute(void)
{
	u8 i = 0;															
	for(i = 0; i < MAX_TIM_TIMER; i++)												
	{
		if((TimerList[i].Timeoutcnt != 0) && (TimerList[i].Timeoutcnt <= 86400000))
		{
			TimerList[i].Timeoutcnt--;										
			if(TimerList[i].Timeoutcnt == 0)								
			{
				if(TimerList[i].Timerflag != TIMER_PERIOD)				
				{
					TimerList[i].Timeoutcnt = 86400001;						
				}
				else
				{
					TimerList[i].Timeoutcnt = TimerList[i].Timeout;			
				}
				if(TimerList[i].Timeoutfuc != NULL)
				{
					TimerList[i].Timeoutfuc(TimerList[i].Parameter);
				}			
			}
		}
	}
}

4、时钟事务注册和开始

void TIMER_TimerStart(u8 TimerIdent, u32 TimeOut, void (*Timeoutfuc)(void* parameter), void* parameter, u8 flag)
{
	if(TimerIdent > MAX_TIM_TIMER-1)
	{
		return;
	}
	
	//__disable_irq();
	
	TimerList[TimerIdent].Timeoutcnt = TimeOut;
	TimerList[TimerIdent].Timeout = TimeOut;
	TimerList[TimerIdent].Timeoutfuc = Timeoutfuc;
	TimerList[TimerIdent].Parameter = parameter;
	TimerList[TimerIdent].Timerflag = flag;
	
	//__enable_irq();
}

5、时钟事务停止

void TIMER_STOP(s32 index)
{
   if(index> MAX_TIM_TIMER-1)
	{
		return;
	}
	TimerList[index].Timeoutcnt = 86400001;
	TimerList[index].Timeout = 86400001;
	TimerList[index].Timerflag = TIMER_CLOSE;
}

三、main使用

1、编写定时事务

void led_timer_update(void * para)		//运行完需要4秒
{
	led_update();
}

void stop_timer_update(void * para)		//运行完需要4秒
{
    printf("stop"):
}

  2、注册使用

int main(){
    TIM_TimerInitialisation()
    //定时1000ms循环执行一次led_timer_update事务
    TIMER_TimerStart(LED_TIMER_INDEX, 1000, led_timer_update, (void*)0, TIMER_PERIOD);

    //定时60s后只执行一次led_timer_update事务
    TIMER_TimerStart(STOPMODE_TIMER_INDEX, 60*1000, stop_timer_update, (void*)0, TIMER_ONESHOT);
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到