OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7562|回复: 31

让我们来学习RTOS,自己写RTOS

[复制链接]

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
发表于 2016-8-22 14:07:03 | 显示全部楼层 |阅读模式
本帖最后由 lotoohe 于 2016-8-24 08:24 编辑

该RTOS系统命名为ZRTOS,是我在阅读了ucos后,并且借鉴了其它操作系统后实现的,完成了一些基础的工作,可以拿过来学习,也可以进行简单的应用。
笔者独自完成了内存分配算法,多任务切换,消息邮箱,信号量,互斥量等,在其中也学到了非常多的东西。
声明:仅供学习!
要自写一个操作系统,我们首先要实现的就是任务切换,再其次是任务调度(高优先级先执行,同优先级时间片分割执行),然后再是消息邮箱,信号量,互斥量等等。
下面我们来看看任务切换的实现,这部分的代码只能由汇编语言来完成,在handler.s中有任务切换的具体代码:
我们的任务板是stm32,stm32是基于cortex-m3内核的,所以在写这个系统的时候很多参照了cortex-m3内核的文档,其中包括了pendsv中断向量,与中断压栈以及堆栈指针等方面。在设计中中断任务我们用的是msp堆栈指针,而我们的任务使用的是psp指针,我们在汇编代码中开启了psp指针的使用以后就,cpu就会自动的进行切换了:
开全局与关全局中断的代码:

[mw_shl_code=asm,true]enter_int
                        export enter_int
                        CPSID I RIMASK=1 关中断
                        BX LR ;返回
exit_int
                        export exit_int
                        CPSIE I        ;开中断
                        BX LR ;返回[/mw_shl_code]
第一次启动操作系统,我们往往需要初始化psp指针,设置pendsv中断为最低的优先级,然后开始一次调度:

[mw_shl_code=asm,true];开启操作系统
start_os        proc
                        export start_os
                        CPSID   I
                        ;首先设置pendsv为最低优先级
                        ;设置pendsv的中断优先级
                        ldr r0,=0xE000ED22
                        ;最低优先级
                        ldr r1,=0xff
                        ;设置
                        strb r1,[r0]
                        ;设置psp为0,用于判断是否第一次任务调度
                        MOVS R0, #0 ;R0 = 0
                        MSR PSP, R0 SP = R0
                        ;开启pendsv中断
                        LDR R0, =0xE000ED04 ;R0 = 0xE000ED04
                        LDR R1, =0x10000000 ;R1 = 0x10000000
                        ;设置触发
                        STR.w R1, [R0] ;*(uint32_t *)NVIC_INT_CTRL = NVIC_PENDSVSET
                        ;打开中断
                        CPSIE I ;
                        ;死循环
os_start_hang
                        B os_start_hang
                        endp[/mw_shl_code]
软件开启pendsv中断的代码:
[mw_shl_code=asm,true];出发pendsv中断,以便进行中断调度
open_scheduling proc
                                export open_scheduling
                                push {r0-r4,lr}
                                LDR R0, =0xE000ED04
                                LDR R1, =0x10000000
                                ;进入pendsv中断
                                STR R1, [R0]
                                pop          {r0-r4,pc}
                                endp[/mw_shl_code]
最后就是pendsv中断中的代码:

[mw_shl_code=asm,true];pendsv中断
PendSV_Handler  PROC
                EXPORT  PendSV_Handler   
                                REQUIRE8    ; 加这两条对齐伪指令防止链接器报错
                                PRESERVE8   ; 8 字对齐        
                                ;中断调度时不能被打断,这里关闭中断
                cpsid I
                                ;获得sp指针的值
                                MRS R0, PSP ;R0 = PSP
                                       
                                ;如果第一次执行,则执行一次中断调度
                                CBZ R0, thread_change
                                ;不是第一次则保护r4-r11
                                SUBS R0, R0, #0x20 ;R0 -= 0x20
                                STM R0, {R4-R11} ;               
                                
                                ;保存本次的栈顶地址
                                ldr r1,=task_mem_
                                ldr r1,[r1]
                                str R0,[r1]
                                
thread_change        ;任务调度
                                push {lr}
                                ldr.w r0,=task_sw
                                blx r0
                                pop  {lr}

                                LDM R0, {R4-R11} ;恢复新的r4-r11的值
                                ADDS R0, R0, #0x20 ;R0 += 0x20
                                MSR PSP, R0
                                ;切换到用户线程模式
                                ;lr 的第2位为1时自动切换
                                ORR LR, LR, #0x04  
                                ;开中断
                                cpsie I
                                BX         LR                        
                ENDP[/mw_shl_code]                                 
下面是最最重要的,任务调度器,任务调度器主要是找到最高优先级的任务,并且轮询调度,还要保存要运行的任务的控制块,在task.c中:
[mw_shl_code=c,true]//任务调度函数
void *task_sw(void){
        uint32 i=0;
        TASK_TCB *max_TASK_TCB=TASK_TCB_LIST[0];
        static TASK_TCB *back_task_tcb=null;
        //查找没有通优先级的
        if(back_task_tcb!=null){
                uint32 spotted=0;
                for(i=0;i<TASK_TCB_NUM;i++){
                        if(back_task_tcb==TASK_TCB_LIST){
                                spotted=1;
                                continue;
                        }
                        //确保是没有被调度过的任务
                        if(spotted==1){
                                if(TASK_TCB_LIST!=null&&
                                        back_task_tcb->level==TASK_TCB_LIST->level){
                                        max_TASK_TCB=TASK_TCB_LIST;
                                        goto step;
                                }
                        }
                }
        }
        for(i=0;i<TASK_TCB_NUM;i++){
                if(TASK_TCB_LIST!=null){
                        if(TASK_TCB_LIST->status==true&&
                                //任务没有被延时
                                        TASK_TCB_LIST->delay_count==0){
                                if(max_TASK_TCB==null){
                                        max_TASK_TCB=TASK_TCB_LIST;
                                        continue;
                                }
                                //获取优先级最高的
                                if(max_TASK_TCB->level > TASK_TCB_LIST->level){
                                        max_TASK_TCB=TASK_TCB_LIST;
                                }
                        }
                }
        }
        step:
        //运行时间+1
        max_TASK_TCB->run_count++;
        //当前的堆栈
        task_mem_=&max_TASK_TCB->mem_task;
        //保存当前运行的tcb
        TCBIng=max_TASK_TCB;
        //保存上次获得的最大优先级
        back_task_tcb=max_TASK_TCB;
        //返回堆栈的地址
        return max_TASK_TCB->mem_task;
}[/mw_shl_code]
这就是zrtos的任务切换的核心部分,看了这些对rtos也算有一定的了解。请期待下一节,zrtos中API函数的使用。



这下来看看zrtos相关的api函数吧,顺便我也将源码传上来:
(任务)task相关的api:
void start_os(void);
start_os:开始操作系统的任务调度
void open_scheduling(void);
open_scheduling:调用该函数将会立刻立刻进行任务调度,任务自己放弃cpu
void enter_int(void);
endter_int:调用该函数后全局中断屏蔽
void exit_int(void);
exit_int:调用该函数后全局中断屏蔽打开


uint32 os_create_n(void(*fun_poi)(void* prg),void *prg,uint32 level,uint32 task_num);
os_create_n:
参数说明:
fun_poi:任务指向的函数
prg:要传递的参数
level:任务的优先级
task_num:任务占用的内存大小(task_num*4 bytes)
说明:创建一个任务
void z_os_start(void);
z_os_start;内部会创建一个空间任务(最低优先级),开启systick,然后调用start_os函数开始调度
void os_task_delay(uint32 count);
os_task_delay:任务延时,将cpu交给其它的任务
void os_task_del(void );
os_task_del:删除正在运行的本任务

(msg)消息邮箱:
TCB_MSG* msg_create(void);
msg_create:创建一个消息邮箱
void msg_close(TCB_MSG* mTCB_MSG);
msg_close:关闭一个消息邮箱
uint32 msg_get(TCB_MSG* mTCB_MSG,void **msg,uint32 msg_get_delay);
msg_get:
参数说明:
mTCB_MSG:消息邮箱的控制块
msg:消息的地址
msg_get_delay:消息的等待时间
说明:获取消息邮箱内的消息
uint32 msg_put(TCB_MSG* mTCB_MSG,uint32 msg,uint32 msg_get_delay);
msg_put:
参数说明:
mTCB_MSG:消息控制块
msg_get_delay:消息获取的超时时间

(SEM)信号量:
TCB_SEM* sem_create(void);
sem_create:创建一个信号量
void sem_free(TCB_SEM *mSEM);
sem_free:信号量释放
uint32 sem_post(TCB_SEM *mSEM);
sem_post:
参数说明:
mSEM:信号量控制块
说明:发送一个信号量
uint32 sem_pend(TCB_SEM *mSEM,uint32 sem_wait_delay);
sem_pend:
参数说明:
mSEM:信号量控制块
sem_wait_delay:信号量等待超时时间

互斥量:不讲了,和信号量的使用大同小异

工程的代码:
工程中创建到了3个任务,两个同优先级的,一个高优先级的。
工程是stm32的,连接上串口1,即可看到串口500ms打印一个a,1000ms打印一个字符b,1500ms打印一个字符c
zrtos操作系统.zip (2.56 MB, 下载次数: 754)
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
10
金钱
10
注册时间
2016-8-22
在线时间
0 小时
发表于 2016-8-22 14:21:44 | 显示全部楼层
支持楼主,支持国产,希望楼主越做越好,这个我收藏了,看看能不能用的到。。
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
10
金钱
10
注册时间
2016-8-22
在线时间
0 小时
发表于 2016-8-22 14:22:59 | 显示全部楼层
刚刚看了楼主的源码,真的写的太精简了,用了少量的代码,实现的功能还是不错了,例子演示的非常的不错,就是不知道稳定性怎么样,内存分配的代码也简单,比原子哥的还要简单。
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-22 14:26:40 | 显示全部楼层
zspace 发表于 2016-8-22 14:22
刚刚看了楼主的源码,真的写的太精简了,用了少量的代码,实现的功能还是不错了,例子演示的非常的不错,就 ...

的确代码还是比较简单,结构很清晰,有几个模块用到了c语言面向对象的编程的思想。稳定性我也没有大量测试过,平时使用还是没有一点问题,任务管理用的是数组,最大任务量都是可以修改了,任务优先级的最大值也是可以修改的。
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-22 16:41:21 来自手机 | 显示全部楼层
顶。。。。。。。。。。
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-22 21:48:08 来自手机 | 显示全部楼层
顶。。。论坛人气太小了
回复 支持 反对

使用道具 举报

3

主题

548

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1383
金钱
1383
注册时间
2015-2-3
在线时间
197 小时
发表于 2016-8-22 23:13:21 | 显示全部楼层
都是大神!应该向原子申请置酷
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-23 07:55:37 来自手机 | 显示全部楼层
yyx112358 发表于 2016-8-22 23:13
都是大神!应该向原子申请置酷

我去申请下
回复 支持 反对

使用道具 举报

4

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
126
金钱
126
注册时间
2016-6-18
在线时间
26 小时
发表于 2016-8-23 08:18:47 | 显示全部楼层
好好好
回复 支持 反对

使用道具 举报

19

主题

176

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1106
金钱
1106
注册时间
2015-10-27
在线时间
206 小时
发表于 2016-8-23 09:01:25 | 显示全部楼层
mark...
回复 支持 反对

使用道具 举报

头像被屏蔽

65

主题

277

帖子

0

精华

高级会员

Rank: 4

积分
674
金钱
674
注册时间
2013-8-11
在线时间
29 小时
发表于 2016-8-23 09:07:56 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
10
金钱
10
注册时间
2016-8-22
在线时间
0 小时
发表于 2016-8-23 22:07:34 | 显示全部楼层
楼主,你的内存分配算法我收藏了。
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-23 22:08:17 | 显示全部楼层
zspace 发表于 2016-8-23 22:07
楼主,你的内存分配算法我收藏了。

随便用
回复 支持 反对

使用道具 举报

2

主题

13

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
212
金钱
212
注册时间
2014-2-19
在线时间
18 小时
发表于 2016-8-24 10:05:17 | 显示全部楼层
下载拜读了,多谢楼主分享!
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-24 16:26:56 | 显示全部楼层
ciaolemeng 发表于 2016-8-24 10:05
下载拜读了,多谢楼主分享!

不知道你们注册阿mo电子没有
回复 支持 反对

使用道具 举报

8

主题

136

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
428
金钱
428
注册时间
2015-4-24
在线时间
85 小时
发表于 2016-8-24 16:44:40 | 显示全部楼层
路过,给楼主顶下贴
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-25 10:04:08 | 显示全部楼层
bruellyyang 发表于 2016-8-24 16:44
路过,给楼主顶下贴

多谢。。。。。。。。。。。。。。
回复 支持 反对

使用道具 举报

9

主题

108

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1136
金钱
1136
注册时间
2013-7-16
在线时间
80 小时
发表于 2016-8-25 11:31:02 | 显示全部楼层
这个可以有!
回复 支持 反对

使用道具 举报

24

主题

695

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1666
金钱
1666
注册时间
2016-4-29
在线时间
266 小时
发表于 2016-8-25 12:21:33 | 显示全部楼层
虽然暂时看不太懂,不过收藏以后研究
回复 支持 反对

使用道具 举报

2

主题

194

帖子

0

精华

高级会员

Rank: 4

积分
981
金钱
981
注册时间
2015-9-20
在线时间
148 小时
发表于 2016-8-25 16:30:22 | 显示全部楼层
这个绝对要顶起来。。。。
回复 支持 反对

使用道具 举报

4

主题

290

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1130
金钱
1130
注册时间
2015-8-4
在线时间
107 小时
发表于 2016-8-25 16:47:14 | 显示全部楼层
顶起,阿mo论坛ID被封了。楼主这个可以有。
活到老,学到老。
回复 支持 反对

使用道具 举报

2

主题

194

帖子

0

精华

高级会员

Rank: 4

积分
981
金钱
981
注册时间
2015-9-20
在线时间
148 小时
发表于 2016-8-25 17:43:51 | 显示全部楼层
哇,楼主用的这固件库有点老啊,我看到了#include "stm32f10x_conf.h"...........
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-26 19:55:08 来自手机 | 显示全部楼层
d1z1y2 发表于 2016-8-25 12:21
虽然暂时看不太懂,不过收藏以后研究

可以拿来学习,代码简单
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-26 19:56:15 来自手机 | 显示全部楼层
杏帘在望 发表于 2016-8-25 17:43
哇,楼主用的这固件库有点老啊,我看到了#include "stm32f10x_conf.h"...........

不老吧,都一样的用,写操作系统开发板都可以不用,软件仿真就能写简单的
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-8-26 19:58:20 来自手机 | 显示全部楼层
cookles 发表于 2016-8-25 11:31
这个可以有!

我又更新了,实现了timer 后面发上来
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
发表于 2016-8-27 15:39:14 | 显示全部楼层
支持一个.....
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

2

主题

194

帖子

0

精华

高级会员

Rank: 4

积分
981
金钱
981
注册时间
2015-9-20
在线时间
148 小时
发表于 2016-8-29 19:26:24 | 显示全部楼层
顶....
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2016-8-29 21:49:09 | 显示全部楼层
顶一个,论坛写OS的人越来越多了
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

22

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2014-5-25
在线时间
67 小时
 楼主| 发表于 2016-9-1 11:11:46 来自手机 | 显示全部楼层
ianhom 发表于 2016-8-29 21:49
顶一个,论坛写OS的人越来越多了

我这也就写来学习下
回复 支持 反对

使用道具 举报

6

主题

110

帖子

0

精华

高级会员

Rank: 4

积分
553
金钱
553
注册时间
2014-10-23
在线时间
195 小时
发表于 2016-9-2 11:03:55 | 显示全部楼层
mark,
回复 支持 反对

使用道具 举报

6

主题

68

帖子

0

精华

高级会员

Rank: 4

积分
513
金钱
513
注册时间
2016-3-16
在线时间
166 小时
发表于 2016-9-2 15:02:13 | 显示全部楼层
留待学习,mark~
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2019-6-28
在线时间
4 小时
发表于 2019-6-28 15:06:38 | 显示全部楼层
支持楼主,学习一下,前辈多指教
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-9 15:14

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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