您的位置:首页 > 其它

51操作系统学习笔记(三):建立一个属于自己的AVR的RTOS(1)

2011-11-30 00:30 239 查看
这篇笔记虽然是“51操作系统学习笔记”,但没有找到合适的代码。用杨明记的感觉还有点难度。

因而转学《建立一个属于自己的AVR的RTOS》

这篇文章绝对是学操作系统入门经典之作。

经典之处在于非常符合大家的学习习惯。

杨明记的,邵贝贝的都对c语言的要求较高,对不熟悉c语言高级编程的人来说,还是有点云里雾里。

废话少说,如题吧。

先学《建立一个属于自己的AVR的RTOS》第一章


自从03年以来,对单片机的RTOS的学习和应用的热潮可谓一浪高过一浪.03年,在离开校园前的,非典的那几个月,在华师的后门那里买了本邵贝贝的《UCOSII》,通读了几次,没有实验器材,也不了了之。
在21IC上,大家都可以看到杨屹写的关于UCOSII在51上的移植,于是掀起了51上的RTOS的热潮。
再后来,陈明计先生推出的small rots,展示了一个用在51上的微内核,足以在52上进行任务调度。
前段时间,在ouravr上面开有专门关于AVR的Rtos的专栏,并且不少的兄弟把自己的作品拿出来,着实开了不少眼界。这时,我重新回顾了使用单片机的经历,觉得很有必要,从根本上对单片机的RTOS的知识进行整理,于是,我开始了编写一个用在AVR单片机的RTOS。

当时,我所有的知识和资源有:
Proteus6.7 可以用来模拟仿真avr系列的单片机
WinAVR v2.0.5.48 基于GCC AVR的编译环境,好处在于可以在C语言中插入asm的语句
mega8 1K的ram有8K的rom,是开发8位的RTOS的一个理想的器件,并且我对它也比较熟悉。

写UCOS的Jean J.Labrosse在他的书上有这样一句话,“渐渐地,我自然会想到,写个实时内核直有那么难吗?不就是不断地保存,恢复CPU的那些寄存器嘛。”

好了,当这一切准备好后,我们就可以开始我们的Rtos for mega8的实验之旅了。

本文列出的例子,全部完整可用。只需要一个文件就可以编译了。我相信,只要适当可用,最简单的就是最好的,这样可以排除一些不必要的干扰,让大家专注到每一个过程的学习

第一篇:函数的运行

在一般的单片机系统中,是以前后台的方式(大循环+中断)来处理数据和作出反应的。
例子如下:

makefile的设定:运行WinAvr中的Mfile,设定如下
MCU Type: mega8
Optimization level: s
Debug format :AVR-COFF
C/C++ source file: 选译要编译的C文件

#include <avr/io.h>
void fun1(void)
{
unsigned char i=0;
while(1)
{
PORTB=i++;
PORTC=0x01<<(i%8);
}
}

int main(void)
{
fun1();
}

首先,提出一个问题:如果要调用一个函数,真是只能以上面的方式进行吗?
相信学习过C语言的各位会回答,No!我们还有一种方式,就是“用函数指针变量调用函数”,如果大家都和我一样,当初的教科书是谭浩强先生的《C程序设计》的话,请找回书的第9.5节。

例子:用函数指针变量调用函数

#include <avr/io.h>
void fun1(void)
{
unsigned char i=0;
while(1)
{
PORTB=i++;
PORTC=0x01<<(i%8);
}
}
void (*pfun)(); //指向函数的指针

int main(void)
{

pfun=fun1; //
(*pfun)(); //运行指针所指向的函数
}

第二种,是“把指向函数的指针变量作函数参数”

#include <avr/io.h>
void fun1(void)
{
unsigned char i=0;
while(1)
{
PORTB=i++;
PORTC=0x01<<(i%8);
}
}

void RunFun(void (*pfun)()) //获得了要传递的函数的地址
{
(*pfun)(); //在RunFun中,运行指针所指向的函数
}

int main(void)
{
RunFun(fun1); //将函数的指针作为变量传递

}

看到上面的两种方式,很多人可能会说,“这的确不错”,但是这样与我们想要的RTOS,有什么关系呢?各位请细心向下看。

以下是GCC对上面的代码的编译的情况:

对main()中的RunFun(fun1); 的编译如下
ldi r24,lo8(pm(fun1))
ldi r25,hi8(pm(fun1))
rcall RunFun

对void RunFun(void (*pfun)())的编译如下
/*void RunFun(void (*pfun)())*/
/*(*pfun)();*/
.LM6:
movw r30,r24
icall
ret

在调用void RunFun(void (*pfun)())的时候,的确可以把fun1的地址通过r24和r25传递给RunFun()。但是,RTOS如何才能有效地利用函数的地址呢?

/*其实第一章讲一个很简单的问题,就是程序如何从一个函数的运行过程中,跳转运行另一个函数。可以如同第一种的简单函数调用;也可以用第二种方式的指针为参数进行调用函数;当然还可以第三种方式,用操作系统中常用的方式,就是把sp指向某一函数入口,然后执行reti,也就是把执行权交给了另一函数。第二章就讲的就是第三种方式。51操作系统学习笔记(二)已经掌握了这个问题,所以这里一看就明白*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: