搜索
bottom↓
回复: 6

学习rtos,小小的成果

[复制链接]

出0入0汤圆

发表于 2011-10-3 17:58:02 | 显示全部楼层 |阅读模式
哈哈,各位师傅们好,最近看到了论坛里面的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
uchar  a;                     

unsigned char Stack[360];     //堆栈

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



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

//////////////////////////////////////////////////////////////////////////////////////////////////
void OSStartTask( )                                       //任务开始调度
{
  a=1;
  SP=TCB[1].OSTaskStackY;                                  //这里借用SP寄存器,先把任务一的Y指针赋值到SP,然后切入汇编
  asm("IN r28,0x3d");                                      //把SP的值(也就是任务一的Y指针)加载到Y寄存器中
  asm("IN r29,0x3e");                                         
  SP=TCB[1].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[a].OSTaskStackTop=SP;                               //保存上次任务的信息
  asm("out 0x3d,r28");
  asm("out 0x3e,r29");
  TCB[a].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[99],1);                        //建立任务一                                                     
OSTaskCreate(0x015b,&Stack[199],2);                       //建立任务二
init_devices();                                        //中断初始化
OSStartTask();                                           //开始调度



}




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

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2012-2-15 15:46:14 | 显示全部楼层
mark!!!!!!!!!!!!!!

出0入0汤圆

发表于 2012-2-16 20:56:42 | 显示全部楼层
实践出真知啊!!

出0入0汤圆

发表于 2012-6-15 18:53:23 | 显示全部楼层
马克帕克。

出0入0汤圆

发表于 2012-6-15 18:54:57 | 显示全部楼层
学习了!

出0入0汤圆

发表于 2012-6-16 13:09:00 | 显示全部楼层
mark 一下,想学习好rtos,真得好好研究一下

出0入16汤圆

发表于 2012-6-16 13:39:46 | 显示全部楼层
楼主的实践精神很好!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 11:21

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表