一个自己写的协程系统

一、为什么要要自己写一个协程系统
1.ucos ,freertos 这些真正有线程调度能力的系统,需要的资源比较大,stc ,stm32f030 这些价格比较好资源比较少的单片机还是用不了。多线程操作系统确实实时性好,用起来方便,但是对内存的要求相对高。所以本系统是针对那些资源比较小的单片机。

2.其实我们顺序运行的程序影响实时性的主要有两个问题,
一个是,频繁代用delay函数会 阻塞程序运行,一旦调用了 delay函数,所有程序都停止。
另一个是,程序的函数没有优先级排列。
比如下图,
在这里插入图片描述
如果我按下按键的时候程序刚好运行到deal_lcd(),如果每个函数都运行20ms,那么程序就要一百多毫秒以后才运行到deal_key()去处理按键消息,再显示出来就更慢,如果while(1)里的函数更多,延时就更长。这样给人的视觉上就是实时性很差,但是在平时,mcu的使用率其实没有超过10%。如果我把每个函数排了优先级以后,把deal_key()和deal_lcd()的优先级排在最高,那么,就算按下按键的那一刻程序在运行其他的函数,但是运行完哪一个函数后,会马上deal_key()这个函数,那么如果一个函数的运行时间只是20ms的话,延时最多就20ms,人基本上感受不到。这样的延时在一般的小产品已经够用了,当然,大产品也用不了省mcu的几块钱了。

3.协程其实是个单线程任务,只是给函数排列优先级,让下一个要运行的程序是优先级最高的,也就是最急迫要运行的,这样没有给每个线程分配堆栈的概念。所以对内存的要求很小。而且复杂性低。

二,我程序的原理
其实很简单,程序中有8个waiting队列,表示8个不同优先级的等待运行队列,主函数的每一个循环都会从优先级最高的队列中从上往下查找,找到一个优先级最高的函数运行。这样就确保了优先级最好的函数可以最快运行。运行完后的函数都会被推到sleep队列中,等待下一个运行周期到了再推进waiting队列中。
另外有个1ms定时器中断函数,用来计算sleep队列中的函数哪一个到了运行时间周期,然后将其推送到相应优先级的waiting队列中。
在这里插入图片描述

三,运行测试
以下是我在stm32f030f4t6的测试结果,本os的文件只有一个,myos.c。可以观察一下运行结果
在这里插入图片描述
在这里插入图片描述
四,源代码
、、、、、、、、、、、、、、、、、、、、
myos.c
、、、、、、、、、、、、、、、、、、、、、
#include “myos.h”
#include “stdlib.h”
#include “string.h”
#include “debug.h”
#include “tim.h”
static unsigned int sys_clock=0;
typedef enum
{
false =0,
true,
}bool;
static TASK_QUEUE sleep_queue={NULL,NULL};
static TASK_QUEUE waiting_queue[8]={{NULL,NULL}};
void idle_callback(void);

static unsigned short task_cnt=0;
static void init_queue(PTASK_QUEUE pQueue)
{
pQueue->head=pQueue->tail=(PTASK_HANDLE)malloc(sizeof(TASK_HANDLE));
pQueue->head->next=NULL;
pQueue->head->name=“head”;
}
static bool IsEmptyQueue(PTASK_QUEUE pQueue)
{
if (pQueue->head == pQueue->tail)
{
return true;
}
else
{
return false;
}
}

static TASK_HANDLE* get_element_from_queue_head(PTASK_QUEUE pQueue)
{
TASK_HANDLE* tmp;
LOCK();
if(IsEmptyQueue(pQueue))
{
tmp=NULL;
}
else
{
tmp=pQueue->head->next;
pQueue->head->next=tmp->next;
if(pQueue->tail==tmp)
{
pQueue->tail=pQueue->head;
pQueue->tail->next=NULL;
}
}
UNLOCK();
return tmp;
}
static void put_element_to_queue_tail(PTASK_QUEUE pQueue,TASK_HANDLE* element)
{
LOCK();
pQueue->tail->next=element;
pQueue->tail=pQueue->tail->next;
pQueue->tail->next=NULL;
// prt(“put_element_to_queue_tail:%s\r\n”,element->name);
UNLOCK();
}

static void task_switch_deal(unsigned char priority)
{
// prt(“enter task_switch_deal\r\n”);
if(true==IsEmptyQueue(&waiting_queue[priority]))return;
TASK_HANDLE* tmp=get_element_from_queue_head(&waiting_queue[priority]);
if(tmp->taskFun!=NULL)
{
// prt(“run task :%s \n\r”,tmp->name);
tmp->taskFun((void*)tmp);
}
put_element_to_queue_tail(&sleep_queue,tmp);
}
void init_os()
{
prt(“OS init\r\n”);
init_queue(&sleep_queue);
init_queue(&waiting_queue[0]);
init_queue(&waiting_queue[1]);
init_queue(&waiting_queue[2]);
init_queue(&waiting_queue[3]);
init_queue(&waiting_queue[4]);
init_queue(&waiting_queue[5]);
init_queue(&waiting_queue[6]);
init_queue(&waiting_queue[7]);

}
void os_loop()
{
prt(“OS start\r\n”);
START_OS_TEMER;
while(1)
{

	if(false==IsEmptyQueue(&waiting_queue[PRIORITY7]))
	{			
		task_switch_deal(PRIORITY7);
		
	}
	else if(false==IsEmptyQueue(&waiting_queue[PRIORITY6]))
	{			
		task_switch_deal(PRIORITY6);
		
	}
	else if(false==IsEmptyQueue(&waiting_queue[PRIORITY5]))
	{			
		task_switch_deal(PRIORITY5);
		
	}
	else if(false==IsEmptyQueue(&waiting_queue[PRIORITY4]))
	{			
		task_switch_deal(PRIORITY4);
		
	}
	else if(false==IsEmptyQueue(&waiting_queue[PRIORITY3]))
	{			
		task_switch_deal(PRIORITY3);
		
	}
	else if(false==IsEmptyQueue(&waiting_queue[PRIORITY2]))
	{			
		task_switch_deal(PRIORITY2);
		
	}
	else if(false==IsEmptyQueue(&waiting_queue[PRIORITY1]))
	{			
		task_switch_deal(PRIORITY1);
		
	}
	else if(false==IsEmptyQueue(&waiting_queue[PRIORITY0]))
	{			
		task_switch_deal(PRIORITY0);
		
	}
	else 
	{
		 idle_callback();
	}
}

}

void timer_1ms_interrupt()
{
sys_clock++;
TASK_HANDLE *tmp_sleep_element;
TASK_HANDLE *tmp_sleep_element_last=sleep_queue.head;
// TASK_HANDLE *tmp_sleep_element_next=NULL;

while(sleep_queue.head!=sleep_queue.tail&&tmp_sleep_element_last->next!=NULL)
{
	tmp_sleep_element=tmp_sleep_element_last->next;
//	prt("timer_1ms_interrupt tmp_sleep_element name :%s\r\n",tmp_sleep_element->name);
	if(tmp_sleep_element->next_call_time<=sys_clock)
	{
		tmp_sleep_element->next_call_time=sys_clock+tmp_sleep_element->recycle_period;
		if(tmp_sleep_element==sleep_queue.tail)
		{
				sleep_queue.tail=tmp_sleep_element_last;
				sleep_queue.tail->next=NULL;
			//	break;
		}
		else
		{
				tmp_sleep_element_last->next=tmp_sleep_element->next;
		}
		put_element_to_queue_tail(&waiting_queue[tmp_sleep_element->priority],tmp_sleep_element);
	//	prt("put element %s to waiting queue\r\n",tmp_sleep_element->name);
	}
	else
	{
			tmp_sleep_element_last=tmp_sleep_element_last->next;
	}
}

}

TASK_HANDLE * add_task(char* name,FUN taskfun,void* parameter,unsigned short recycle_period,unsigned char priority)
{
LOCK();
TASK_HANDLE* task=(TASK_HANDLE*)malloc(sizeof(TASK_HANDLE));
if(task==NULL) return NULL;
memset(task,0,sizeof(TASK_HANDLE));
task->next=NULL;
task->name=name;
task->taskFun=taskfun;
task->parameter=parameter;
task->recycle_period=recycle_period;
task->priority=priority;
put_element_to_queue_tail(&sleep_queue,task);
task_cnt++;
UNLOCK();
return task;
}

void task_resume(TASK_HANDLE *task)
{
task->next_call_time=0;
}

void delete_task()//ÒѾ­ÔÚwaitingµÄº¯Êý²»ÄÜɾ³ý
{

}

void idle_callback()
{
//prt(".");

}

define timer
#ifdef USE_TIMER
static TIMER timer_handle[TIMER_CNT_MAX]={0};
void add_timer(unsigned char timer_number,char* timer_name,unsigned int x100ms_delay,unsigned char is_static,TIMER_FUN fun )
{
timer_handle[timer_number].delay_x100ms=x100ms_delay;
timer_handle[timer_number].fun=fun;
timer_handle[timer_number].is_static=is_static;
strcpy(timer_handle[timer_number].name,timer_name);
timer_handle[timer_number].be_used=1;
}

void delete_timer(unsigned char task_number)
{

memset(&timer_handle[task_number],0,sizeof(TIMER));

}
char get_empty_timer_number(unsigned char *timer_number)
{
unsigned char i=0;
for(;i<TIMER_CNT_MAX;i++)
{
if(timer_handle[i].is_static1) continue;
if(timer_handle[i].be_used
1)continue;
*timer_number=i;
return 1;
}
return 0;
}

void deal_timer(void *peram)
{
unsigned char index=0;
for(;index<TIMER_CNT_MAX;index++)
{
if(timer_handle[index].be_used1)
{
if(timer_handle[index].delay_x100ms>0)
{
timer_handle[index].delay_x100ms–;
}
else
{
timer_handle[index].be_used=0;
if(timer_handle[index].fun!=NULL)
{
timer_handle[index].fun();
}
if(timer_handle[index].is_static
0)
{
memset(&timer_handle[index],0,sizeof(TIMER));
}
}
}
}
}
void init_timer()
{
TASK_HANDLE *timer_task_handle = add_task(“timer task”,deal_timer,NULL,100,PRIORITY2);
}

#endif
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
myos.h
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
#ifndef MYOS_H
#define MYOS_H
//#define USE_TIMER
typedef void (*FUN)(void *this_task_handle);
#ifndef NULL
#define NULL (void )0
#endif
typedef struct Node
{
char
name;
FUN taskFun;
void *parameter;
unsigned int next_call_time;//
int recycle_period:14;//16x1024ms
int task_state:1;//sleep,waitingrun
int task_stop:1;
int priority:3;//0 is low, 3 is high
struct Node *next;
}TASK_HANDLE,*PTASK_HANDLE;
#define TASK_WAITING 1
#define TASK_SLEEP 0
typedef struct QNode{
PTASK_HANDLE head;
PTASK_HANDLE tail;
}TASK_QUEUE,*PTASK_QUEUE;

#define PRIORITY0 0
#define PRIORITY1 1
#define PRIORITY2 2
#define PRIORITY3 3
#define PRIORITY4 4
#define PRIORITY5 5
#define PRIORITY6 6
#define PRIORITY7 7

extern void os_loop(void);//add to main
extern void timer_1ms_interrupt(void);//add to 1ms timer interrupt
extern TASK_HANDLE * add_task(char* name,FUN taskfun,void* parameter,unsigned short recycle_period,unsigned char priority);
extern void task_resume(TASK_HANDLE *task);
extern void task_delete(TASK_HANDLE *task);
define timer /
#ifdef USE_TIMER
#define TIMER_CNT_MAX 16
typedef void (*TIMER_FUN)(void);
typedef struct
{
char *name;
TIMER_FUN fun;
unsigned short delay_x100ms:14;//max 6553 s
unsigned char be_used:1;
unsigned char is_static:1;//if the plan is static ,it can be cover

}TIMER;
void init_timer(void);
char get_empty_timer_number(unsigned char timer_number);
void add_timer(unsigned char timer_number,char
timer_name,unsigned int x100ms_delay,unsigned char is_static,TIMER_FUN fun );
#endif

#define LOCK() LL_TIM_DisableIT_UPDATE(TIM1)
#define UNLOCK() LL_TIM_EnableIT_UPDATE(TIM1)
#define START_OS_TEMER do{LL_TIM_EnableIT_UPDATE(TIM1);LL_TIM_EnableCounter(TIM1);}while(0)//for os
#endif
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
test.c
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
#include “myos.h”
#include “tim.h”
#include “debug.h”
void task1_fun(void * parma)
{
TASK_HANDLE* this_task=parma;
prt(“This is %s\r\n”,this_task->name);
}
void task2_fun(void * parma)
{
TASK_HANDLE* this_task=parma;
prt(“This is %s\r\n”,this_task->name);
}
void task3_fun(void * parma)
{
TASK_HANDLE* this_task=parma;
prt(“This is %s\r\n”,this_task->name);
}
void task4_fun(void * parma)
{
TASK_HANDLE* this_task=parma;
prt(“This is %s\r\n”,this_task->name);
}
void task5_fun(void * parma)
{
TASK_HANDLE* this_task=parma;
prt(“This is %s\r\n”,this_task->name);
}

void test()
{
LL_TIM_ClearFlag_UPDATE(TIM1);
LL_TIM_DisableIT_UPDATE(TIM1);
LL_TIM_DisableCounter(TIM1);

//prt(“sfsdfasdfsda\r\n”);
init_os();

TASK_HANDLE *task_h1=add_task("task1 ",task1_fun,NULL,5000,7);
TASK_HANDLE *task_h2=add_task("task2 ",task2_fun,NULL,4000,6);
TASK_HANDLE *task_h3=add_task("task3 ",task3_fun,NULL,3000,5);
TASK_HANDLE *task_h4=add_task("task4 ",task4_fun,NULL,2000,4);
TASK_HANDLE *task_h5=add_task("task5 ",task5_fun,NULL,1000,3);
os_loop();

}

五,源代码及测试程序
这是我的源代码及测试程序,在stm32f030f4p6上实现的,移植起来会非常简单,当然代码还没有完善,但是后续会不断改进,也会跟进在微博上,在stc上的版本或者优化的版本, 有需求和问题的请留言
链接:https://pan.baidu.com/s/1ltJgToZAknALL6EM4N4pJw
提取码:or0s
如果百度云找不到可以去我的csdn微博上下载。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值