zhyscout 发表于 2011-10-3 17:58:02

学习rtos,小小的成果

哈哈,各位师傅们好,最近看到了论坛里面的rtos,我很是激动,也有编写一个的冲动,不过我没有什么软件基础,而且是用的iccavr编译器,和其他的编译器有些不一样。但是经过不断地摸索,参考了那个教程《 建立一个属于自己的AVR的RTOS》
,终于编出了这个小东西,这也只能说是十分之一个rtos,不过虽然简单,但是对于我来说,却是一大步。
这其实就是两个任务不断地切换.这两个任务都是led灯的不断闪烁,然后通过定时器进行切换。
(编译器是iccavr)
(12M晶振)
(mega16)
(这个工程包括只有三个c文件)
第一个c文件,放着两个任务
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <ioM16v.h>
#include <macros.h>
#define uchar        unsigned char
#define uint        unsigned int

void delay()               //一个延时函数
{
long i=10000;
while(i--);
}

//////////////////////////////////////////
void task1()               //任务一:PORTC口连接着一个LED,可以不断的闪烁
{
DDRC=0xff;
while(1)
{
   PORTC=~PORTC;
   NOP();
   NOP();
   delay();
   delay();
}
}
////////////////////////////////
void task2()                //任务二:PORTD口连接着一个LED,可以不断的闪烁
{
DDRD=0xff;
while(1)
{
   PORTD=~PORTD;
   NOP();
   NOP();
   delay();
   delay();
}
}


第二个c文件,放着定时器的初始化函数,
使用定时器一,并且20ms产生一次中断。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <ioM16v.h>
#include <macros.h>
#define uchar        unsigned char
#define uint        unsigned int

void timer1_init(void)
{
TCCR1B = 0x00;//停止定时器
TIMSK |= 0x04;//中断允许
TCNT1H = 0xF1;
TCNT1L = 0x5A;//初始值
OCR1AH = 0xF0;
OCR1AL = 0xFF;//匹配A值
OCR1BH = 0xF0;
OCR1BL = 0xFF;//匹配B值
ICR1H= 0xFF;
ICR1L= 0xFF;//输入捕捉匹配值
TCCR1A = 0x00;
TCCR1B = 0x03;//启动定时器
}

void init_devices(void)
{
CLI(); //禁止所有中断
MCUCR= 0x00;
MCUCSR = 0x80;//禁止JTAG
GICR   = 0x00;
timer1_init();
SEI();//开全局中断
}




第三个c文件,这里是主文件
/////////////////////////////////////////////////////////////////////////////////
#include <ioM16v.h>
#include <macros.h>
#define uchar        unsigned char
#define uint        unsigned int
uchara;                     

unsigned char Stack;   //堆栈

struct TaskCtr                //任务控制块
{
uint OSTaskStackTop;       //放着硬件堆栈指针
uint OSTaskStackY;         //放着软件堆栈指针,也就是Y指针
}TCB;                     //这里定义了三个,本来是想写三个人物的,可是后来就写了两个,所以实际就用到了两个



/////////////////////////////////////////////////////////////////////////////////////////////////
void OSTaskCreate(uint Task,uchar *Stack,uchar TaskID)         //建立任务 ,uint Task传入的是任务函数的入口地址,不过
{                                                                //iccave获得的地址好像不对,于是就用avrstudio看任务                                                                        
uchar i=0;                                                      //函数的汇编直接获得了地址,然后再填写进去;uchar *Stack是堆栈的
for(i=0;i<30;i++)                                             //地址;uchar TaskID是任务号。
{
   *Stack--=0xaa;
}
*Stack--=Task;
*Stack--=((uint)Task)>>8;
TCB.OSTaskStackTop=(uint)Stack;    //将人工堆栈的栈顶,保存到堆栈的数组中
TCB.OSTaskStackY=(uint)Stack-50;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
void OSStartTask( )                                       //任务开始调度
{
a=1;
SP=TCB.OSTaskStackY;                                  //这里借用SP寄存器,先把任务一的Y指针赋值到SP,然后切入汇编
asm("IN r28,0x3d");                                    //把SP的值(也就是任务一的Y指针)加载到Y寄存器中
asm("IN r29,0x3e");                                       
SP=TCB.OSTaskStackTop;                              //最后把任务一的Sp指针加载到SP寄存器中
asm("reti");                                             //这个没有也可以,其实编译器已经悄悄地加过了
}

///////////////////////////////////////////////////////////
#pragma interrupt_handler timer0_comp_isr:9            //中断函数,其实就是任务切换函数,a,b两个变量没什么用,就是用来记住上次运行的
void timer0_comp_isr(void)                              //任务,这样可以方便的任务切换
{
uchar b;
b=3-a;
TCB.OSTaskStackTop=SP;                               //保存上次任务的信息
asm("out 0x3d,r28");
asm("out 0x3e,r29");
TCB.OSTaskStackY=SP;


   
SP=TCB.OSTaskStackY;                           //加载这次任务的信息
asm("IN r28,0x3d");
asm("IN r29,0x3e");
SP=TCB.OSTaskStackTop;
a=b;
TCNT1H = 0xF1; //重装值高位                      //定时器的计数器赋初值,保证是20ms
TCNT1L = 0x5A; //重装值低位
}
/////////////////////////////////////////////////////////////

void task1();                                       //函数声明
void task2();
void task3();
void main()
{
OSTaskCreate(0x014f,&Stack,1);                        //建立任务一                                                   
OSTaskCreate(0x015b,&Stack,2);                     //建立任务二
init_devices();                                        //中断初始化
OSStartTask();                                           //开始调度



}




嘿嘿,就这么结束了。其实也没有什么,但是我真的很高兴的,学到了新东西。

zd305 发表于 2012-2-15 15:46:14

mark!!!!!!!!!!!!!!

Guoyy 发表于 2012-2-16 20:56:42

实践出真知啊!!

cos 发表于 2012-6-15 18:53:23

马克帕克。

电子小生 发表于 2012-6-15 18:54:57

学习了!

trochili 发表于 2012-6-16 13:09:00

mark 一下,想学习好rtos,真得好好研究一下

liuruoshui 发表于 2012-6-16 13:39:46

楼主的实践精神很好!
页: [1]
查看完整版本: 学习rtos,小小的成果