Rt-Thread 移植8--定时器的实现(KF32)

1 思路

之前线程需要延时的时候,就初始化remaining_tick,只是将线程就绪优先级组中对应的位清0,并不会将线程从就绪列表中删除。每次systick中断,就remaining_tick递减,如果为0表示延时时间到,将该线程就绪(就绪优先级组中对应的位置1),然后等待系统写一次调度。缺点是所有扫描线程一遍,费时,优点是容易理解。
在新的方案里,每个线程都内置一个定时器,当线程需要延时,就将线程挂起,然后内置的定时器就会启动,并将定时器插入到一个全局的系统定时器列表上rt_timer_list.节点按照延时时间大小做升序排列。当sysTICK来,系统扫描定时器列表的第一个定时器,如果定时器到期,就让该线程就绪,如果时间不到,就退出扫描。

2.实现定时器

2.1系统定时器列表

timer.c中

static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];

rtdef.h中

#ifndef RT_TIMER_SKIP_LIST_LEVEL
#define RT_TIMER_SKIP_LIST_LEVEL          1
#endif

2.2 定时器列表初始化

timer.c中

void rt_system_timer_init(void)
{
	int i;
	for(i = 0; i < sizeof(rt_timer_list)/sizeof(rt_timer_list[0]);i++)
	{
		rt_list_init(rt_timer_list+i);
	}
}

2.3 定义定时器结构体

rtdef.h中

struct rt_timer
{
    struct rt_object parent;                            /**< inherit from rt_object */

    rt_list_t        row[RT_TIMER_SKIP_LIST_LEVEL];

    void (*timeout_func)(void *parameter);              /**< timeout function */
    void            *parameter;                         /**< timeout function's parameter */

    rt_tick_t        init_tick;                         /**< timer timeout tick */
    rt_tick_t        timeout_tick;                      /**< timeout tick */
};

2.4 线程控制块中内置定时器

struct rt_thread
{
	char name[RT_NAME_MAX];
	rt_uint8_t type;
	rt_uint8_t flag;
	rt_list_t list;
	void        *sp;	          /* 线程栈指针 */
	void        *entry;	          /* 线程入口地址 */
	void        *parameter;	      /* 线程形参 */	
	void        *stack_addr;      /* 线程起始地址 */
	rt_uint32_t stack_size;       /* 线程栈大小,单位为字节 */
	
	rt_list_t   tlist;            /* 线程链表节点 */

	rt_ubase_t remaining_tick;

	rt_uint8_t current_priority;
	rt_uint8_t init_priority;
	rt_uint32_t number_mask;
	rt_err_t error;
	rt_uint8_t stat;

	**struct rt_timer thread_timer;**
};

2.5 定时器初始化

timer.c中

void rt_timer_init(rt_timer_t	timer,
					const char *name,
					void (*timeout)(void *parameter),
					void *parameter,
					rt_tick_t time,
					rt_uint8_t flag)
{
	rt_object_init((rt_object_t)timer,RT_Object_Class_Timer,name);
	_rt_timer_init(timer,timeout,parameter,time,flag);
}

static void _rt_timer_init(rt_timer_t	timer,
		void (*timeout)(void *parameter),
		void *parameter,
		rt_tick_t time,
		rt_uint8_t flag)
{
	int i;
	timer->parent.flag = flag;
	timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
	timer->timeout_func = timeout;
	timer->parameter = parameter;
	timer->timeout_tick = 0;
	timer->init_tick = time;
	for(i = 0; i < RT_TIMER_SKIP_LIST_LEVEL;i++)
	{
		rt_list_init(&(timer->row[i]));
	}
}

redef.h中定义标志

#define RT_TIMER_FLAG_DEACTIVATED		0x0
#define RT_TIMER_FLAG_ACTIVATED			0x1

#define RT_TIMER_FLAG_ONE_SHOT			0x0
#define RT_TIMER_FLAG_PERIODIC			0x02

#define RT_TIMER_FLAG_HARD_TIMER		0x0
#define RT_TIMER_FLAG_SOFT_TIMER		0x4

2.6定时器删除函数

rt_inline void _rt_timer_remove(rt_timer_t timer)
{
	int i;
	for(i = 0; i < RT_TIMER_SKIP_LIST_LEVEL;i++)
	{
		rt_list_remove(&timer->row[i]);
	}
}

2.7 定时器停止函数

rt_err_t rt_timer_stop(rt_timer_t timer)
{
	register rt_base_t level;
	if(!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
		return -RT_ERROR;
	level = rt_hw_interrupt_disable();
	_rt_timer_remove(timer);
	rt_hw_interrupt_enable(level);
	timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
	return RT_EOK;
}

2.8 定时器控制函数

rt_err_t rt_timer_control(rt_timer_t timer,int cmd,void *arg)
{
	switch(cmd)
	{
		case RT_TIMER_CTRL_GET_TIME:
			*(rt_tick_t *)arg = timer->init_tick;
			break;
		case RT_TIMER_CTRL_SET_TIME:
			timer->init_tick = *(rt_tick_t *)arg;
			break;
		case RT_TIMER_CTRL_SET_ONESHOT:
			timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
			break;
		case RT_TIMER_CTRL_SET_PERODIC:
			timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
			break;
	}
	return RT_EOK;
}

rtdef.h中定义控制命令

#define RT_TIMER_CTRL_SET_TIME			0x0
#define RT_TIMER_CTRL_GET_TIME			0x1
#define RT_TIMER_CTRL_SET_ONESHOT		0x2
#define RT_TIMER_CTRL_SET_PERODIC		0x3

2.9 定义启动函数

rt_err_t rt_timer_start(rt_timer_t timer)
{
	unsigned int row_lvl = 0;
	rt_list_t *timer_list;
	register rt_base_t level;
	rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
	unsigned int tst_nr;
	static unsigned int random_nr;

	level = rt_hw_interrupt_disable();
	_rt_timer_remove(timer);
	timer->parent.flag  &= ~RT_TIMER_FLAG_ACTIVATED;
	rt_hw_interrupt_enable(level);
	timer->timeout_tick = rt_tick_get() + timer->init_tick;
	level = rt_hw_interrupt_disable();
	timer_list = rt_timer_list;
	row_head[0]=&timer_list[0];

	for(row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL;row_lvl++)
	{
		for(;row_head[row_lvl]!=timer_list[row_lvl].prev;row_head[row_lvl]=row_head[row_lvl]->next)
		{
			struct rt_timer *t;
			rt_list_t *p = row_head[row_lvl]->next;
			t = rt_list_entry(p,struct rt_timer,row[row_lvl]);
			if((t->timeout_tick-timer->timeout_tick)==0)
			{
				continue;
			}
			else if((t->timeout_tick-timer->timeout_tick)<RT_TICK_MAX/2)
			{
				break;
			}
		}
		if(row_lvl != RT_TIMER_SKIP_LIST_LEVEL -1)
		{
			row_head[row_lvl+1]=row_head[row_lvl]+1;
		}
	}
	random_nr++;
	tst_nr = random_nr;
	P_DBG("row_lvl %d inset timer %s\n",row_lvl,timer->parent.name);
	rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL-1],&(timer->row[RT_TIMER_SKIP_LIST_LEVEL-1]));
	for(row_lvl = 2;row_lvl <= RT_TIMER_SKIP_LIST_LEVEL;row_lvl)
	{
		if(!(tst_nr & RT_TIMER_SKIP_LIST_LEVEL))
			rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL-row_lvl],&(timer->row[RT_TIMER_SKIP_LIST_LEVEL-row_lvl]));
		else
			break;
		tst_nr >>= (RT_TIMER_SKIP_LIST_MASK+1)>>1;

	}
	timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
	rt_hw_interrupt_enable(level);
	return -RT_EOK;
}

2.10 定时器扫描函数

void rt_timer_check(void)
{
	struct rt_timer *t;
	rt_tick_t current_tick;
	register rt_base_t level;
	current_tick = rt_tick_get();
	level = rt_hw_interrupt_disable();
	//P_DBG("check...\n");
	while(!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL-1]))
	{
		t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL-1].next,struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL-1]);
		if((current_tick-t->timeout_tick)<RT_TICK_MAX/2)
		{
			P_DBG("t %s timeout\n",t->parent.name);
			_rt_timer_remove(t);
			t->timeout_func(t->parameter);
			current_tick = rt_tick_get();
			if((t->parent.flag & RT_TIMER_FLAG_PERIODIC)&&(t->parent.flag&RT_TIMER_FLAG_ACTIVATED))
			{
				t->parent.flag &= ~ RT_TIMER_FLAG_ACTIVATED;
				rt_timer_start(t);
			}
			else
			{
				t->parent.flag &= ~ RT_TIMER_FLAG_ACTIVATED;
			}
		}
		else
		{
			break;
		}
	}
	rt_hw_interrupt_enable(level);
}

3.修改代码

3.1 修改线程初始化函数

rt_err_t rt_thread_init(struct rt_thread *thread,const char *name,
                        void (*entry)(void *parameter),
                        void             *parameter,
                        void             *stack_start,
                        rt_uint32_t       stack_size,
                        )

{

	rt_object_init((rt_object_t)thread,RT_Object_Class_Thread,name);
	rt_list_init(&(thread->tlist));

	thread->entry = (void *)entry;
	thread->parameter = parameter;

	thread->stack_addr = stack_start;
	thread->stack_size = stack_size;

	/* 初始化线程栈,并返回线程栈指针 */
	thread->sp = (void *)rt_hw_stack_init( thread->entry,
		                                   thread->parameter,
							               (void *)((char *)thread->stack_addr + thread->stack_size - 4) );
	thread->init_priority = priority;
	thread->current_priority = priority;
	thread->number_mask = 0;
	thread->error = RT_EOK;
	thread->stat = RT_THREAD_INIT;

	rt_timer_init(&(thread->thread_timer),thread->name,rt_thread_timeout,thread,0,RT_TIMER_FLAG_ONE_SHOT);

	return RT_EOK;
}

3.2 修改延时函数

rt_err_t rt_thread_delay(rt_tick_t tick)
	{


		return rt_thread_sleep(tick);


}

rt_err_t rt_thread_sleep(rt_tick_t tick)
{
	register rt_base_t temp;
	struct rt_thread *thread;
	temp = rt_hw_interrupt_disable();
	thread = rt_current_thread;
	rt_thread_suspend(thread);
	rt_timer_control(&(thread->thread_timer),RT_TIMER_CTRL_SET_TIME,&tick);
	rt_timer_start(&(thread->thread_timer));
	rt_hw_interrupt_enable(temp);
	rt_schedule();
	return RT_EOK;

}

rt_err_t rt_thread_suspend(rt_thread_t thread)
{
	register rt_base_t temp;
	if((thread->stat & RT_THREAD_STAT_MASK)!= RT_THREAD_READY)
	{
		return -RT_ERROR;
	}

	temp = rt_hw_interrupt_disable();

	thread->stat = RT_THREAD_SUSPEND;
	rt_schedule_remove_thread(thread);
	rt_timer_stop(&(thread->thread_timer));
	rt_hw_interrupt_enable(temp);
	return RT_EOK;
}

3.3 修改时基函数

void rt_tick_increase(void)
{
	++ rt_tick;

	rt_timer_check();

}

3.4 修改main函数

	rt_system_timer_init();

4 用例

void flag1_thread_entry( void *p_arg )
{
	for( ;; )
	{
		P_DBG("flag1 thread\n");

		flag2 = 1;
		P_DBG("flag1 thread will dela1\n");
		rt_thread_delay(10);
		flag2 = 0;
		P_DBG("flag1 thread will dela2\n");
		rt_thread_delay(10);

	}
}
相关推荐
XH华4 小时前
初识C语言之二维数组(下)
c语言·算法
Uu_05kkq7 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
嵌入式科普10 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
A懿轩A10 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
1 9 J11 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
仍然探索未知中12 小时前
C语言经典100例
c语言
爱吃西瓜的小菜鸡12 小时前
【C语言】矩阵乘法
c语言·学习·算法
Stark、14 小时前
【Linux】文件IO--fcntl/lseek/阻塞与非阻塞/文件偏移
linux·运维·服务器·c语言·后端
deja vu水中芭蕾14 小时前
嵌入式C面试
c语言·开发语言
stm 学习ing16 小时前
HDLBits训练3
c语言·经验分享·笔记·算法·fpga·eda·verilog hdl