应用代码(1)——软件定时器

这一部分代码是在自己实际项目中看到的代码,可以借鉴到其他地方!

原理解析:

举例:有两个定时器任务,2ms和2.5ms的定时任务
在这里插入图片描述

原码分享:

功能1:定时器的添加

//定义一个软件定时器的全局变量
blt_soft_timer_t	blt_timer;
/*	这边是软件定时器的定义:
 * typedef struct blt_soft_timer_t
 *  {
		blt_time_event_t	timer[MAX_TIMER_NUM];  //timer0 - timer3,注意,这个0~3个定时器器是按排序来的,并不是说真的有0~3个定时器,而是有0~3个定时任务
		u8					currentNum;  //total valid timer num 目前的软件定时器数量
	}
 * timer[MAX_TIMER_NUM]; --》是以下的定时器变量包括:
 * typedef struct blt_time_event_t {
	blt_timer_callback_t    cb; 		//定时器超时的回调函数
	u32                     t;			//下一次间隔的时间点
	u32                     interval; 	//设置的时间间隔
} blt_time_event_t;
 */

//user add timer
//添加软件定时器 :带参(回调函数,时间间隔)这是创建软件定时器的地方
int blt_soft_timer_add(blt_timer_callback_t func, u32 interval_us)
{
	int i;
	u32 now = clock_time(); //获取当前的tick时钟
	//不能写入的软件定时器号不能超过设置的最大定时器号
	if(blt_timer.currentNum >= MAX_TIMER_NUM){  //timer full
		return 	0;
	}
	//没有超过的话
	else{
		//绑定回调函数
		blt_timer.timer[blt_timer.currentNum].cb = func;
		//绑定时间间隔
		blt_timer.timer[blt_timer.currentNum].interval = interval_us * CLOCK_16M_SYS_TIMER_CLK_1US;//单位是1us
		//绑定目前的时间+目前的时间间隔
		blt_timer.timer[blt_timer.currentNum].t = now + blt_timer.timer[blt_timer.currentNum].interval;
		blt_timer.currentNum ++; //软件定时器数量+1
		blt_soft_timer_sort(); //排序,根据目前的时间来进行对这几个定时器进行排序,这个排序是核心,目的是让每个定时都能触发到
								//因为在这个定时器的创建中,每次只和表头的那个定时器的目前时间元素(blt_timer.timer[0].t)进行比较
		//这边是因为芯片厂商定义的,如果有定时器就会从低功耗唤醒,我们在使用的过程中可以屏蔽下面的唤醒
		if(blt_timer.currentNum ){ //timer table not empty
    		if( (u32)(blt_timer.timer[0].t - now) < 3000 *  CLOCK_16M_SYS_TIMER_CLK_1MS){
    			bls_pm_setAppWakeupLowPower(blt_timer.timer[0].t,  1);
    		}
    		else{
    			bls_pm_setAppWakeupLowPower(0, 0);  //disable
    		}
	    }
		return  1;
	}
}

子函数_排序:

//if t1 < t2  return 1
#define		TIME_COMPARE_SMALL(t1,t2)   ( (u32)((t2) - (t1)) < BIT(30)  )
// if t1 > t2 return 1
#define		TIME_COMPARE_BIG(t1,t2)   ( (u32)((t1) - (t2)) < BIT(30)  )//这边是因为转换成了无符号数,所以是比较最高位

//按照定时时间将timer排序,便于process时 依次触发timer
int  blt_soft_timer_sort(void)
{
	if(blt_timer.currentNum < 1 || blt_timer.currentNum > MAX_TIMER_NUM){
		write_reg32(0x40000, 0x11111120); while(1); //debug ERR
		return 0;
	}
	else{
		// 冒泡排序  BubbleSort
		int n = blt_timer.currentNum;
		u8 temp[sizeof(blt_time_event_t)];
		for(int i=0;i<n-1;i++)
		{
			for(int j=0;j<n-i-1;j++)
			{
				if(TIME_COMPARE_BIG(blt_timer.timer[j].t, blt_timer.timer[j+1].t))
				{
					//swap
					memcpy(temp, &blt_timer.timer[j], sizeof(blt_time_event_t));
					memcpy(&blt_timer.timer[j], &blt_timer.timer[j+1], sizeof(blt_time_event_t));
					memcpy(&blt_timer.timer[j+1], temp, sizeof(blt_time_event_t));
				}
			}
		}
	}
	return 1;
}

功能2:定时器的删除

有添加就有删除

//软件定时器的删除
int 	blt_soft_timer_delete(blt_timer_callback_t func)
{
	for(int i=0; i<blt_timer.currentNum; i++){
		if(blt_timer.timer[i].cb == func){//通过回调函数的比较,确定当前是哪个定是哪个定时器
			blt_soft_timer_delete_by_index(i);

			if(i == 0){  //删除的是最近的timer,需要更新时间
					//这边是如果距离下次定时器任务在3秒内,那么我们就不进入低功耗状态
				if( (u32)(blt_timer.timer[0].t - clock_time()) < 3000 *  CLOCK_16M_SYS_TIMER_CLK_1MS){
					bls_pm_setAppWakeupLowPower(blt_timer.timer[0].t,  1);
				}
				else{
					//不唤醒
					bls_pm_setAppWakeupLowPower(0, 0);  //disable
				}

			}
			return 1;
		}
	}
	return 0;
}

子函数_软件定时器删除

//timer 本来就是有序的,删除的时候,采用往前覆盖,所以不会破坏顺序,不需要重新排序
int  blt_soft_timer_delete_by_index(u8 index)
{
	//如果删除的值大于最大数,就跳出
	if(index >= blt_timer.currentNum){
		write_reg32(0x40000, 0x11111121); while(1); //debug ERR
		return 0;
	}

	//这个就是把后面的定时器往前移动
	for(int i=index; i<blt_timer.currentNum - 1; i++){
		memcpy(&blt_timer.timer[i], &blt_timer.timer[i+1], sizeof(blt_time_event_t));
	}

	blt_timer.currentNum --;

	return 1;
}

功能3:软件定时器的调用

void bls_pm_registerAppWakeupLowPowerCb(pm_appWakeupLowPower_callback_t cb);

#define		BLT_TIMER_SAFE_MARGIN_PRE	  (CLOCK_16M_SYS_TIMER_CLK_1US<<7)  //128 us
#define		BLT_TIMER_SAFE_MARGIN_POST	  (CLOCK_16M_SYS_TIMER_CLK_1S<<2)   // 4S
static int inline blt_is_timer_expired(u32 t, u32 now) {
	//这边一条是很核心的,其实也是比较u32的值,这边很巧妙的利用了“无符号整型复数为一个很大值”的特性,来进行比较;又很巧妙的利用了
	//如果是正数的时候,不能大于4s的这个条件,来作为时间限制。用一句话抵用了好几句语句。
	return ((u32)(now + BLT_TIMER_SAFE_MARGIN_PRE - t) < BLT_TIMER_SAFE_MARGIN_POST);
}//BLT_TIMER_SAFE_MARGIN_PRE 就是128us,BLT_TIMER_SAFE_MARGIN_POST就是4s

//------------------------------定时器的初始化-----------------------------
void 	blt_soft_timer_init(void)
{
	bls_pm_registerAppWakeupLowPowerCb(blt_soft_timer_process);
}
//初始化实际调用的函数
void  blt_soft_timer_process(int type)
{
	if(type == CALLBACK_ENTRY){ //callback trigger

	}
	u32 now = clock_time();//获取当前的时间
	if(!blt_timer.currentNum){//如果没有定时任务
		//不唤醒
		bls_pm_setAppWakeupLowPower(0, 0);
		return;
	}
//如果   (现在的时间+128us) - 下次间隔的时间点 < 4S 这边的128是128us的补偿
	//------------------------------timer[0]是最先要触发的定时器任务---------------------
	if( !blt_is_timer_expired(blt_timer.timer[0].t, now) ){//每次都是比较表头(最先执行的定时器),所以要排序

		return;
	}
	int change_flg = 0;
	int result;
	for(int i=0; i<blt_timer.currentNum; i++){
		//定时器超时判断  ---》这里元素t = (now0 + blt_timer.timer[i].interval)
		//blt_is_timer_expired函数里就是---》now1 +128us - (now0 + blt_timer.timer[i].interval) 是否>0
		//如果大于0了就为真,也就是触发了
		//--------------------定时时间到触发的判断条件--------------------
		if(blt_is_timer_expired(blt_timer.timer[i].t ,now) ){ //timer trigger

			if(blt_timer.timer[i].cb == NULL){
				write_reg32(0x40000, 0x11111122); while(1); //debug ERR
			}
			else{
				result = blt_timer.timer[i].cb();//执行回调函数

				if(result < 0){
					blt_soft_timer_delete_by_index(i);
				}
				//定时器任务执行成功的话
				else if(result == 0){
					change_flg = 1;
					blt_timer.timer[i].t = now + blt_timer.timer[i].interval;
				}
				else{  //set new timer interval
					change_flg = 1;
					blt_timer.timer[i].interval = result * CLOCK_16M_SYS_TIMER_CLK_1US;
					blt_timer.timer[i].t = now + blt_timer.timer[i].interval;
				}
			}
		}
	}

	if(blt_timer.currentNum ){ //timer table not empty
		if(change_flg){
			blt_soft_timer_sort();
		}

		if( (u32)(blt_timer.timer[0].t - now) < 3000 *  CLOCK_16M_SYS_TIMER_CLK_1MS){
			bls_pm_setAppWakeupLowPower(blt_timer.timer[0].t,  1);
		}
		else{
			bls_pm_setAppWakeupLowPower(0, 0);  //disable
		}
	}
	else{
		bls_pm_setAppWakeupLowPower(0, 0);  //disable
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 CC2430 的应用开发中,定时器中断是非常常用的一个功能。下面我们将介绍几个关于定时器中断的基础实验。 ## 实验一:定时器中断实验 ### 实验目的 了解 CC2430 的定时器模块,并掌握其中断的使用方法。 ### 实验原理 CC2430 的定时器模块有三个定时器:T1、T2 和 T3。其中,T1 和 T2 是 16 位的定时器,T3 是 8 位的定时器。在本实验中,我们将以 T1 定时器为例,介绍定时器中断的使用方法。 T1 定时器的计数器是一个 16 位的寄存器,它可以通过以下寄存器进行配置: - T1CC0H/T1CC0L:T1 的比较器 0,可以用来产生比较中断。 - T1CC1H/T1CC1L:T1 的比较器 1,可以用来产生比较中断。 - T1CC2H/T1CC2L:T1 的比较器 2,可以用来产生比较中断。 - T1IE:T1 中断使能寄存器,用来使能 T1 的中断。 - T1CTL:T1 控制寄存器,用来配置 T1 的计数模式、时钟源等参数。 在本实验中,我们将使用 T1 的比较器 0,配置为每隔 1 秒钟产生一次中断。 ### 实验步骤 1. 配置 T1 的计数模式、时钟源等参数。 ```c T1CTL |= 0x0C; // T1 计数模式为比较器模式 T1CTL &= ~0x03; // T1 时钟源为时钟源选择寄存器 CLKCON 的 CLKSPD 位所选择的时钟源 T1CTL &= ~0x30; // T1 比较器模式为单次比较模式 ``` 2. 配置 T1 的比较器 0。 ```c T1CC0L = 0x00; // T1 的比较器 0 的低 8 位 T1CC0H = 0x80; // T1 的比较器 0 的高 8 位 ``` 3. 使能 T1 的中断。 ```c T1IE = 1; // 使能 T1 的中断 ``` 4. 在主函数中进入循环,等待定时器中断的触发。 ```c while(1); ``` 5. 在定时器中断服务函数中处理中断事件。 ```c #pragma vector = T1_VECTOR __interrupt void T1_ISR(void) { T1IF = 0; // 清除 T1 中断标志 // 中断处理代码 } ``` ### 实验结果 当程序运行后,每隔 1 秒钟会触发一次定时器中断。在中断服务函数中可以添加相应的处理代码实现定时器中断的功能。 ## 实验二:定时器中断实现 LED 闪烁 ### 实验目的 通过定时器中断实现 LED 的闪烁。 ### 实验原理 在上一个实验中,我们已经学习了如何使用定时器中断。在本实验中,我们将以 T1 定时器为例,通过定时器中断实现 LED 的闪烁。 在本实验中,我们将使用 P0.0 引脚控制 LED 的状态。LED 亮时,P0.0 输出低电平;LED 灭时,P0.0 输出高电平。我们可以通过改变 P0.0 引脚的电平状态,实现 LED 的闪烁。 ### 实验步骤 1. 配置 P0.0 引脚为输出模式。 ```c P0SEL &= ~0x01; // P0.0 引脚配置为 GPIO 模式 P0DIR |= 0x01; // P0.0 引脚配置为输出模式 ``` 2. 配置 T1 的计数模式、时钟源等参数。 ```c T1CTL |= 0x0C; // T1 计数模式为比较器模式 T1CTL &= ~0x03; // T1 时钟源为时钟源选择寄存器 CLKCON 的 CLKSPD 位所选择的时钟源 T1CTL &= ~0x30; // T1 比较器模式为单次比较模式 ``` 3. 配置 T1 的比较器 0。 ```c T1CC0L = 0x00; // T1 的比较器 0 的低 8 位 T1CC0H = 0x80; // T1 的比较器 0 的高 8 位 ``` 4. 使能 T1 的中断。 ```c T1IE = 1; // 使能 T1 的中断 ``` 5. 在定时器中断服务函数中处理中断事件,改变 P0.0 引脚的电平状态。 ```c #pragma vector = T1_VECTOR __interrupt void T1_ISR(void) { T1IF = 0; // 清除 T1 中断标志 P0_0 = ~P0_0; // P0.0 引脚电平状态取反 } ``` 6. 在主函数中进入循环,等待定时器中断的触发。 ```c while(1); ``` ### 实验结果 当程序运行后,LED 会以 1 秒钟的频率闪烁。如果需要改变 LED 闪烁的频率,可以通过修改 T1 的比较器 0 的值来实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mhj258258

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值