本帖最后由 nicholasldf 于 2015-12-19 14:49 编辑
微型时间片轮转操作系统,其实只能叫做时间片轮转调度器,就是不断轮流切换任务的功能,只有LineOS.h 和 LineOS.c两个文件
核心代码就几个函数,大概2007年写的,昨晚给部门做uCOS-III培训,又翻了出来,,希望对于嵌入式操作系统初学者理解OS的概念有一点点帮助。
使用:
可以用在实际编程当中,,把功能分为多个任务模块,分而治之处理。
扩展:
可以稍微改造,可以让任务主动放弃CPU,以便CPU利用率最大化,并加入idle空闲任务。
可以针对STM32稍作移植,也很容易。
//========================================LineOS核心开始=========================================================
//-------------------------------------------------头文件------------------------------------------------------------
//这个头文件就是定义了任务结构体,还有两个宏定义,在切换任务时,pushall()用于保存CPU上下文到当前任务,popall()用于恢复下一个任务的CPU上下文
//任务结构体
typedef struct
{
unsigned char* task_stk_top;//堆栈顶部
unsigned char* task_stk_bottom;//堆栈底部
unsigned char task_stk_size;//堆栈大小
}OS_TASK_TCB;
//宏定义,将所有的CPU寄存器,压入到当前任务堆栈
#define pushall() \
__asm__ __volatile__ ("push r1" "\n\t");\
__asm__ __volatile__ ("push r0" "\n\t");\
__asm__ __volatile__ ("in r0, 0x3f" "\n\t");\
__asm__ __volatile__ ("push r0" "\n\t");\
__asm__ __volatile__ ("eor r1, r1" "\n\t");\
__asm__ __volatile__ ("push r2" "\n\t");\
__asm__ __volatile__ ("push r3" "\n\t");\
__asm__ __volatile__ ("push r4" "\n\t");\
__asm__ __volatile__ ("push r5" "\n\t");\
__asm__ __volatile__ ("push r6" "\n\t");\
__asm__ __volatile__ ("push r7" "\n\t");\
__asm__ __volatile__ ("push r8" "\n\t");\
__asm__ __volatile__ ("push r9" "\n\t");\
__asm__ __volatile__ ("push r10" "\n\t");\
__asm__ __volatile__ ("push r11" "\n\t");\
__asm__ __volatile__ ("push r12" "\n\t");\
__asm__ __volatile__ ("push r13" "\n\t");\
__asm__ __volatile__ ("push r14" "\n\t");\
__asm__ __volatile__ ("push r15" "\n\t");\
__asm__ __volatile__ ("push r16" "\n\t");\
__asm__ __volatile__ ("push r17" "\n\t");\
__asm__ __volatile__ ("push r18" "\n\t");\
__asm__ __volatile__ ("push r19" "\n\t");\
__asm__ __volatile__ ("push r20" "\n\t");\
__asm__ __volatile__ ("push r21" "\n\t");\
__asm__ __volatile__ ("push r22" "\n\t");\
__asm__ __volatile__ ("push r23" "\n\t");\
__asm__ __volatile__ ("push r24" "\n\t");\
__asm__ __volatile__ ("push r25" "\n\t");\
__asm__ __volatile__ ("push r26" "\n\t");\
__asm__ __volatile__ ("push r27" "\n\t");\
__asm__ __volatile__ ("push r28" "\n\t");\
__asm__ __volatile__ ("push r29" "\n\t");\
__asm__ __volatile__ ("push r30" "\n\t");\
__asm__ __volatile__ ("push r31" "\n\t");\
//宏定义,将下一个任务堆栈里面的所有上下文,弹出到CPU寄存器
#define popall() \
__asm__ __volatile__ ("pop r31" "\n\t");\
__asm__ __volatile__ ("pop r30" "\n\t");\
__asm__ __volatile__ ("pop r29" "\n\t");\
__asm__ __volatile__ ("pop r28" "\n\t");\
__asm__ __volatile__ ("pop r27" "\n\t");\
__asm__ __volatile__ ("pop r26" "\n\t");\
__asm__ __volatile__ ("pop r25" "\n\t");\
__asm__ __volatile__ ("pop r24" "\n\t");\
__asm__ __volatile__ ("pop r23" "\n\t");\
__asm__ __volatile__ ("pop r22" "\n\t");\
__asm__ __volatile__ ("pop r21" "\n\t");\
__asm__ __volatile__ ("pop r20" "\n\t");\
__asm__ __volatile__ ("pop r19" "\n\t");\
__asm__ __volatile__ ("pop r18" "\n\t");\
__asm__ __volatile__ ("pop r17" "\n\t");\
__asm__ __volatile__ ("pop r16" "\n\t");\
__asm__ __volatile__ ("pop r15" "\n\t");\
__asm__ __volatile__ ("pop r14" "\n\t");\
__asm__ __volatile__ ("pop r13" "\n\t");\
__asm__ __volatile__ ("pop r12" "\n\t");\
__asm__ __volatile__ ("pop r11" "\n\t");\
__asm__ __volatile__ ("pop r10" "\n\t");\
__asm__ __volatile__ ("pop r9" "\n\t");\
__asm__ __volatile__ ("pop r8" "\n\t");\
__asm__ __volatile__ ("pop r7" "\n\t");\
__asm__ __volatile__ ("pop r6" "\n\t");\
__asm__ __volatile__ ("pop r5" "\n\t");\
__asm__ __volatile__ ("pop r4" "\n\t");\
__asm__ __volatile__ ("pop r3" "\n\t");\
__asm__ __volatile__ ("pop r2" "\n\t");\
__asm__ __volatile__ ("pop r0" "\n\t");\
__asm__ __volatile__ ("out 0x3f, r0" "\n\t");\
__asm__ __volatile__ ("pop r0" "\n\t");\
__asm__ __volatile__ ("pop r1" "\n\t");\
__asm__ __volatile__ ("RETI" "\n\t");\
//-------------------------------------------------源文件------------------------------------------------------------
//头文件
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "LineOS.h"
//volatile unsigned int play =0;
volatile unsigned char next_task = 0;//指示下一个任务的变量
volatile unsigned char count = 0;
//堆栈使用情况检测函数
void task_stack_chek(unsigned char task_id,unsigned char*stkused);
/*任务堆栈初始化函数,在创建任务时调用,参数task为任务入口地址,task_id为任务ID编码*/
unsigned char* stackinit( void (*task)( void ), unsigned char task_id )
{
unsigned char* stk;
unsigned int temp;
temp = (unsigned int)task;//任务入口地址
stk = &( task_stack[task_id][99] );//指向栽顶
*stk-- = (unsigned char)(temp&0xff);//任务入口地址入栽
*stk-- = (unsigned char)(temp>>8);
//32个寄存器和CPU寄存器入栽
*stk-- = (unsigned char)0x00; /* R0 = 0x00 */
*stk-- = (unsigned char)0x00; /* R1 = 0x00 */
*stk-- = (unsigned char)0x80;/*SREG寄存器入栽,使能全局中断有效*/
*stk-- = (unsigned char)0x80; /* R2 = 0x00 */
*stk-- = (unsigned char)0x00; /* R3 = 0x00 */
*stk-- = (unsigned char)0x00; /* R4 = 0x00 */
*stk-- = (unsigned char)0x00; /* R5 = 0x00 */
*stk-- = (unsigned char)0x00; /* R6 = 0x00 */
*stk-- = (unsigned char)0x00; /* R7 = 0x00 */
*stk-- = (unsigned char)0x00; /* R8 = 0x00 */
*stk-- = (unsigned char)0x00; /* R9 = 0x00 */
*stk-- = (unsigned char)0x00; /* R10 = 0x00 */
*stk-- = (unsigned char)0x00; /* R11 = 0x00 */
*stk-- = (unsigned char)0x00; /* R12 = 0x00 */
*stk-- = (unsigned char)0x00; /* R13 = 0x00 */
*stk-- = (unsigned char)0x00; /* R14 = 0x00 */
*stk-- = (unsigned char)0x00; /* R15 = 0x00 */
*stk-- = (unsigned char)0x00; /* R16 = 0x00 */
*stk-- = (unsigned char)0x00; /* R17 = 0x00 */
*stk-- = (unsigned char)0x00; /* R18 = 0x00 */
*stk-- = (unsigned char)0x00; /* R19 = 0x00 */
*stk-- = (unsigned char)0x00; /* R20 = 0x00 */
*stk-- = (unsigned char)0x00; /* R21 = 0x00 */
*stk-- = (unsigned char)0x00; /* R22 = 0x00 */
*stk-- = (unsigned char)0x00; /* R23 = 0x00 */
*stk-- = (unsigned char)0x00; /* R24 = 0x00 */
*stk-- = (unsigned char)0x00; /* R25 = 0x00 */
*stk-- = (unsigned char)0x00; /* R26 = 0x00 */
*stk-- = (unsigned char)0x00; /* R27 = 0x00 */
*stk-- = (unsigned char)0x00; /* R28 = 0x00 */
*stk-- = (unsigned char)0x00; /* R29 = 0x00 */
*stk-- = (unsigned char)0x00; /* R30 = 0x00 */
*stk-- = (unsigned char)0x00; /* R31 = 0x00 */
return ( (unsigned char*)stk ); //返回堆栽栽顶指针
}
/*任务堆栈检查函数,也就是task_id指定任务的堆栈使用了多少,有没有溢出*/
void task_stack_chek(unsigned char task_id, unsigned char*stkused)
{
unsigned char unused=0;
unsigned char *p;
p = task_tcb[task_id].task_stk_bottom;
while( 0 == *p++ ){
unused ++;
}
*stkused = task_tcb[task_id].task_stk_size - unused;
}
/*任务堆栈清零函数,创建任务时,清零task_id指定任务的堆栈,以便做堆栈使用量检查*/
void task_stack_cLR(unsigned char task_id)
{
unsigned char *temp = task_tcb[task_id].task_stk_bottom;
for(unsigned char i=0; i<task_tcb[task_id].task_stk_size; i++){
temp = 0;
}
}
/*任务创建函数,初始化任务结构体,清零并初始化堆栈,保存堆栈指针,task是任务入口函数地址,task_id 是任务ID编码*/
void taskcreat( void (*task)( void ), unsigned char task_id )
{
unsigned char *temp;
task_tcb[task_id].task_stk_size=100;
task_tcb[task_id].task_stk_bottom = &( task_stack[ task_id ][0] );
task_stack_cLR(task_id);
temp = stackinit( task, task_id );//初始化任务堆栽
task_tcb[task_id].task_stk_top = temp;//保存栽顶指针
}
/*操作系统启动函数,运行第一个任务*/
void OS_Start( void )
{
//定时器0初始化
//TCCR0 = 0X01;
//TIMSK = 0X01;
//TCNT0 = 0x00;
//sei();
//CPU堆栈指针指向第一个任务的堆栈指针,准备运行第一个任务
SP = task_tcb[0].task_stk_top + 33;
//用中断返回指令将入口地址弹出到PC指针,运行第一个任务
asm("RETI");
}
/*操作系统定时器节拍中断,按照时间片轮转,切换任务,保存CPU上下文到当前任务堆栈,从下一个任务堆栈恢复下一个任务的CPU上下文*/
//属性设置:让中断程序不保存任何寄存器,以便通过pushall、popall保存和恢复上下文
void SIG_OVERFLOW0( void ) __attribute__ ( ( signal, naked ) );
//中断处理函数
SIGNAL( SIG_OVERFLOW0 )
{
pushall( );//保存当前任务的所有寄存器
count++;
if(count>100)
{
//注:SP是CPU的堆栈寄存器
count = 0;
task_tcb[ next_task % 8 ].task_stk_top =SP;//保存当前任务的栈顶SP指针到当前任务的控制块TCB
next_task++;
SP = task_tcb[ next_task % 8 ].task_stk_top;//指向下一个任务的栈顶SP指针
}
popall( );//恢复下一个任务的所有寄存器
}
//========================================LineOS核心结束=========================================================
//========================================下面是与OS核心无关的示例代码=========================================================
//========================================应用例子开始=========================================================
//LED灯端口定义
#define LED_PORT PORTA
#define LED_DDR DDRA
#define LED_PIN PINA
#define delay 33//时间延迟设定
#define delay_time _delay_ms(10);//时间
volatile OS_TASK_TCB task_tcb[8];//任务结构体数组
unsigned char task_stack[8][100];//任务堆栈数组
/* 主函数main,创建了8个任务,并启动操作系统 */
int main( void )
{
//LED灯控制端口设置
LED_PORT=0Xff;
LED_DDR =0Xff;
//lcd_init();
taskcreat( task1, 0 );
taskcreat( task2, 1 );
taskcreat( task3, 2 );
taskcreat( task4, 3 );
taskcreat( task5, 4 );
taskcreat( task6, 5 );
taskcreat( task7, 6 );
taskcreat( task8, 7 );
OS_Start( );//开始运行任务
while( 1 );
}
/*第一个任务,初始化LCD,定时器,定义了一个大数组,分配于堆栈,因此其堆栈使用深度大一些。在LCD显示,自身堆栈使用情况,以及从‘A’到‘Z’*/
void task1( void )
{
unsigned char temp, play ='A';
unsigned char stkused =0;
unsigned char arry[30] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30};
//LCD1602初始化
lcd_init();
//定时器初始化
TCCR0 = 0X05;
TIMSK = 0X01;
//LCD1602清屏
lcd_write_comm(0x01);
//定时器计数寄存器清零,并使能全局CPU中断
TCNT0 = 0x00;
sei();
while( 1 ) {
//任务1自身堆栈使用情况检查
task_stack_chek( next_task%8, &stkused );
//在LCD指定位置,显示大写字母'A'到'Z'的变化
if( play >'Z' ){
play ='A';
}
lcd_posion( 0, 0 );
lcd_write_data( play++ );
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(1,0,":");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
//翻转8个LED灯,达到闪烁效果
for( temp =0; temp <30; temp ++){
LED_PORT ^= 1 << ( arry[temp] % 8 );
_delay_ms(66);
_delay_ms(66);
}
//延时
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
/*第二个任务,在LCD显示,自身堆栈使用情况,以及从‘a’到‘z’*/
void task2(void)
{
unsigned char temp, play ='a';
unsigned char stkused=0;
while(1){
//任务2自身堆栈使用情况检查
task_stack_chek(next_task%8,&stkused);
//在LCD指定位置,显示小写字母'a'到'z'的变化
if( play >'z' ){
play ='a';
}
lcd_posion( 4, 0 );
lcd_write_data( play++ );
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(5,0,":");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
//延时
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
/*第三个任务,在LCD显示,自身堆栈使用情况*/
void task3(void)
{
unsigned char temp ;
unsigned char stkused=0;
while(1){
//任务3自身堆栈使用情况检查
task_stack_chek(next_task%8,&stkused);
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(8,0,"C:");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
/*第四个任务,在LCD显示,自身堆栈使用情况*/
void task4(void)
{
unsigned char temp ;
unsigned char stkused=0;
while(1){
//任务4自身堆栈使用情况检查
task_stack_chek(next_task%8,&stkused);
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(12,0,"D:");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
/*第五个任务,在LCD显示,自身堆栈使用情况*/
void task5(void)
{
unsigned char temp ;
unsigned char stkused=0;
while(1){
//任务5自身堆栈使用情况检查
task_stack_chek(next_task%8,&stkused);
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(0,1,"E:");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
/*第六个任务,在LCD显示,自身堆栈使用情况*/
void task6(void)
{
unsigned char temp ;
unsigned char stkused=0;
while(1){
//任务6自身堆栈使用情况检查
task_stack_chek(next_task%8,&stkused);
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(4,1,"F:");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
/*第七个任务,在LCD显示,自身堆栈使用情况*/
void task7(void)
{
unsigned char temp ;
unsigned char stkused=0;
while(1){
//任务7自身堆栈使用情况检查
task_stack_chek(next_task%8,&stkused);
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(8,1,"G:");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
/*第八个任务,在LCD显示,自身堆栈使用情况*/
void task8(void)
{
unsigned char temp ;
unsigned char stkused=0;
while(1){
//任务8自身堆栈使用情况检查
task_stack_chek(next_task%8,&stkused);
//在LCD指定位置显示自己的堆栈使用量
lcd_write_str(12,1,"H:");
temp = (stkused/10)%10 + 48;
lcd_write_data( temp );
temp = stkused%10 + 48;
lcd_write_data( temp );
for( unsigned char i=0; i<delay; i++)
delay_time;
}
}
//========================================LCD1602驱动=========================================================
这部分驱动就是普通的LCD1602驱动代码,,没什么特别的地方
//=========================================LCD1602驱动结束============================================================
|
|