用链表+函数指针+定时器中断实现的一个软件定时器(试用于所有单片机)

本文介绍了一种使用链表、函数指针及定时器中断实现软件定时器的方法,并提供了详细的代码示例与使用步骤。

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

因为需要移植nrf51822的程序到普通单片机上,于是分析了协议栈里的软件定时器,用链表+函数指针+定时器中断的方法实现了软件定时器的功能。

下面介绍代码和使用方法

1、函数指针和链表初始化
typedef void (*app_timer_timeout_handler_t)(void);

typedef  struct app_timer  
{   
    u8 id;                 
    u16 time;
    u16 interval_time;
    app_timer_timeout_handler_t p_timeout_handler;         
    struct app_timer *next;       //指向下一节点的指针  
    bool isrunning ;
}app_timer;

2、为链表申请空间
typedef struct app_timer_t 
{
		uint32_t data[sizeof(uint32_t) ];
} app_timer_t;


/**@brief Timer ID type.
 * Never declare a variable of this type, but use the macro @ref APP_TIMER_DEF instead.*/


typedef app_timer_t * app_timer_name_t;


/**
 * @brief Create a timer identifier and statically allocate memory for the timer.
 *
 * @param timer_name Name of the timer identifier variable that will be used to control the timer.
 */
 
#define APP_TIMER_DEF(timer_name)                                  \
    static app_timer_t timer_name##_data = { {0} };                  \
    static app_timer_name_t timer_name = &timer_name##_data


3、创建定时器
参数 定时器名字 定时器id 定时器工作时长 定时器回调函数
u32 app_timer_create(app_timer_name_t const *      p_timer_name,
										 u8 id,
										 u16 time,
										 app_timer_timeout_handler_t  timeout_handler)
{
  	app_timer * p_node  = (app_timer *)*p_timer_name;
        p_node->id = id;
	p_node->time = time;
	p_node->interval_time = time; //记录下定时器的触发时间
	p_node->p_timeout_handler = timeout_handler ;
	p_node->isrunning = FALSE;
  
  p_head = Insert(p_head,p_node);
}


4、将节点插入链表的最后
参数: 链表头指针 节点指针
返回:指向链表表头的指针
struct app_timer *Insert (struct app_timer *head,struct app_timer *node)  
{  
    struct app_timer *p1;   //p1保存当前需要检查的节点的地址  
		
	//当头节点为空时,将传入的节点作为头节点,返回头节点  
    if (head == NULL)         
    {  	 
        head = node; 
        node->next = NULL;  
        return head;  
    }
		
    p1 = head;  
    while(p1->next != NULL)  
    {  
        p1 = p1->next;       //后移一个节点  
    }  

    if(p1->next == NULL)  //将该节点插入链表的末尾
    {  
        p1->next = node;
	node->next = NULL;
 
    }  
    else
    {
		
    }
    return head;  
}  


5、遍历链表 计算是否有定时器超时
将这个函数放入到定时器中断中,每进入一次定时器中断(软件定时器),将设定的软件定时器值-1,减为0之后就调用一开始创建定时器时注册的函数。
void TraverseList(void)
{
    struct app_timer *p1 = p_head;                  
    
    while( p1!= NULL)  //下一个节点如果不为空
    {			
	if(p1->isrunning == TRUE)
	{		
	  p1->time--;
	}	
	else
	{
	  p1->time = p1->interval_time;
	}
		
	if(p1->time == 0 )
	{	 
	  p1->time = p1->interval_time;
			  
	  p1->p_timeout_handler();
 			 
	}
			
			
	if(p1->next != NULL)
	{
	  p1 = p1->next;                                
	}
	else
	{
	 return ;
	}
		 
  }
}

6、修改定时器工作状态
可以让指定id的定时器启动或停止
参数 定时器id 定时器使能
void app_timer_isrunning(int id, bool isrunning)
{
    struct app_timer *p1 = p_head;  
	
	
    while((p1->id != id) && (p1->next != NULL))  
    {  
        p1 = p1->next;       //后移一个节点  
    }  

    if (p1->id==id)        //找到了 
    {
      p1->isrunning = isrunning;
    }
    else
    {
 	 return ;
		
    }
}

7、使用方法
1)通过宏定义来设置id和定时时间
//定时器id设置
#define MAIN_TIMER_ID 1
//定时器初值设置
#define MAIN_TIMER_INTERVAL 5000

2)通过宏预申请链表空间
APP_TIMER_DEF(main_timer);

3)创建定时器
app_timer_create(&main_timer,MAIN_TIMER_ID,MAIN_TIMER_INTERVAL,main_task_timeout_handler);

4)使能定时器
app_timer_isrunning(MAIN_TIMER_ID,TRUE);

5)初始化硬件定时器,将TraverseList()函数放入硬件定时器中断中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值