这是在寒假里完成的基于51单片机的操作系统,能实现的功能有信号(Signal)、互斥体(Mutex)、消息(Message),当然任务的创建和暂停、无阻塞延时、统计、定时器等功能是有的,遗憾的是身边没有单片机实物,只是在KEIL里仿真。
一优先级一任务,OS_MAX_NUM_TASK定义最大任务个数,OS_TickFrequency系统滴答频率,操作系统占用最高优先级(OS_SYS_Task)和最低优先级(TaskIdle),定时器和统计任务就是通过OS_SYS_Task实现的。
我会用UCOS-III(运行在STM32F407),但是看不懂它是怎么编的,用起来感觉别扭。刚好上一学期学了51单片机汇编语言,所以决定自己编一个能在51上运行的操作系统。
感觉比较难的是上下文切换,这里用到很多汇编语句。系统每次切换任务时,首先会保存上文(CPU寄存器组+堆栈),而后获取下一就绪任务,恢复下文。基本都是这样。
具体代码如下:
PUBLIC OS_TaskSwitch
.......
OS_TaskSwitch:
USING 0
DISABLE_ALL_INT ;屏蔽中断
PUSH_ALL_REG ;压栈保存
LCALL TaskSwitch_HOOK ;调用钩子函数
LCALL FIND_NEXT_TASK ;寻找下一优先级任务
MOV A,OS_CurTaskNum ;判断是否需要任务切换
CJNE A,OS_NexTaskNum,TASK_SWITCH_1 ;下一就绪任务不是当前任务,需切换
LJMP TASK_BACK_1 ;下一就绪任务是当前任务,不用切换
TASK_SWITCH_1: ;开始任务切换
SAVE_CONTEXT ;保存上文
LOAD_NEXT_PRIO ;优先级保存
RESTORE_CONTEXT ;恢复下文
TASK_BACK_1: ;任务不用切换直接返回
POP_ALL_REG ;弹栈恢复
ENABLE_ALL_INT ;打开中断
RET
我把挂起任务的堆栈和寄存器保存在XDATA,不会占用DATA(正在运行的任务的堆栈就在DATA)
完成了这个功能(最基本的),再配合一些“表”,其他的功能不是问题。
第二难的就是中断管理了,我做的不好,外部中断0代码如下:
CSEG AT 00003H
LJMP Extern_0_Int_
RSEG ?PR?Extern_0_Int_?OS_ASM
Extern_0_Int_:
USING 0
DISABLE_ALL_INT
PUSH_ALL_REG
LCALL Extern_0_Int
LCALL FIND_NEXT_TASK ;寻找下一优先级任务
MOV A,OS_CurTaskNum ;判断是否需要任务切换
CJNE A,OS_NexTaskNum,TASK_SWITCH_3 ;下一就绪任务不是当前任务,需切换
LJMP TASK_BACK_3 ;下一就绪任务是当前任务,不用切换
TASK_SWITCH_3: ;开始任务切换
SAVE_CONTEXT ;保存上文
LOAD_NEXT_PRIO ;优先级保存
RESTORE_CONTEXT ;恢复下文
TASK_BACK_3: ;任务不用切换直接返回
POP_ALL_REG ;弹栈恢复
ENABLE_ALL_INT ;打开中断
RETI
其实就是任务切换函数+LCALL Extern_0_Int,5个中断源都是这样处理的,幸亏只有5个,否则我肯定不会这么做。
第三难的就是函数的参数以及可重入问题了,查阅了相关资料,看着挺费劲的,算了,函数参数和局部变量尽量少,返回值也不加了。
还有就是中断安全的问题了,在操作重要数据(比如就续表)的时候,一定不能被中断。
编写完成,感觉自己对操作系统的了解深入了很多。现拿出来分享,希望能帮到那些有需要的人。
顺便向各位经验丰富的网友咨询一个问题,我是一个大三的学生(东北电力大学-自动化),现面临考研,我的兴趣就是嵌入式这些东西,
因此我希望我以后能在此方向发展,毕竟兴趣和职业相结合是最好不过的,那我考研应该考什么方向的呢?我想听一下各位的建议,谢谢。
时间急促,附件就给个链接吧,抱歉
http://bbs.armfly.com/read.php?tid=7137