打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
自己动手写一个简易操作系统(基于51单片机)

背景介绍

大一学了51单片机,对于单片机的一些常用外设有了一定的了解。之后,大家都在说当前最流行的单片机是stm32,所以我抽出了暑假的时间的时间学习了stm32单片机,刚开始学的时候真的很痛苦,在坚持了一个星期之后,我慢慢找到了自信,stm32单片机实际上和51是一样的,只是需要配置的寄存器多了一点。在刚开始学的时候,经常在配置的时候无法配置完全,导致无法得到预期的实验效果,但是实际上,大家没必要过分纠结于配置,完全可以直接参考别人使用该功能的配置方式。我们应该将心思放在功能的开发上,而不是纠结于前期简单的配置。在熟悉使用stm32之后,开始接触操作系统ucos,过程中一直觉得自己似懂非懂,所以我在想为什么我自己不利用51写一个简易操作系统,来加深自己的理解。初期写出的操作系统不用考虑通信等高级功能,只需要写出可以调度多个任务的操作系统即可,下面给大家介绍一下我自己写的操作系统(写的不太好,仅供大家参考)。

系统实现

实现简易操作系统,主要需要实现三个函数:

  1. 创建任务函数(将定义的任务的执行入口保存起来,供调度使用)
  2. 任务延时函数(每一个任务执行后,都需要加入延时函数,否则低优先级的任务没有机会执行)
  3. 中断调度函数(提供时间片调度)

1 创建任务函数介绍

int OSTaskCreate(unsigned int Task, unsigned char* pStack, unsigned char TaskID)

{

unsigned char i = 0, j = 0;

*pStack++ = Task & 0xFF; //低八位地址(51单片机入栈向上,出栈向下)

*pStack = Task >> 8; //高八位地址

os_enter_critical();

TaskCB[TaskID].OSTaskStackButtom = (unsigned char)pStack + 13;

TaskCB[TaskID].OSWaitTick = 0;

TASK_READY(TaskID); //将该优先级的任务在全局变量中标记为就绪

os_exit_critical();

return 0;

}

入口参数:

unsigned int Task ---- 任务函数的入口地址

unsigned char* pStack ---- 任务函数的堆栈,主要用来保存现场参数

unsigned char TaskID ----- 任务优先级

2 任务延时函数

void OSTimeDly(unsigned int time)

{

TaskCB[CurrentTaskID].OSWaitTick = time; //将任务的延时时间赋值给任务控制块

task_sw(); //任务调度

}

static void task_sw()

{

os_enter_critical();

TASK_BLOCK(CurrentTaskID); //将当前任务的就绪状态取消

#pragma asm //将现场的关键参数存入堆栈

PUSH ACC

PUSH B

PUSH DPH

PUSH DPL

PUSH PSW

MOV PSW,#00H

PUSH AR0

PUSH AR1

PUSH AR2

PUSH AR3

PUSH AR4

PUSH AR5

PUSH AR6

PUSH AR7

#pragma endasm

TaskCB[CurrentTaskID].OSTaskStackButtom = SP ; //将当前任务的堆栈位置保存,用于下次恢复该任务

CurrentTaskID = Task_High(); //找出处于就绪态的最高优先级的任务

SP = TaskCB[CurrentTaskID].OSTaskStackButtom;

#pragma asm

POP AR7

POP AR6

POP AR5

POP AR4

POP AR3

POP AR2

POP AR1

POP AR0

POP PSW

POP DPL

POP DPH

POP B

POP ACC

#pragma endasm

os_exit_critical(); //离开时会把SP的当前位置的值送入PC指针,所以最高优先级的任务得以运行

}

3 中断调度函数

void TF0_isr() interrupt 1

{

TH0 = 56320/256;

TL0 = 56320%256;

TaskCB[CurrentTaskID].OSTaskStackButtom = SP; //被中断的任务的现场已经压入堆栈,所以只需保存SP

CurrentTaskID = Task_Ready_High(); //取出就绪中优先级最高的任务

SP = TaskCB[CurrentTaskID].OSTaskStackButtom;

#pragma asm

POP AR7

POP AR6

POP AR5

POP AR4

POP AR3

POP AR2

POP AR1

POP AR0

POP PSW

POP DPL

POP DPH

POP B

POP ACC

RETI

#pragma endasm

}

总结:

以上三个函数就是一个简易操作系统的关键函数,大家可以自己动手实现一下。这对大家学习ucos有很大的帮助,同时也为学习linux系统打下基础。

后续我会继续完善这个简易操作系统,添加通信等功能,希望大家可以关注我,共同进步。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
QueueForMcu | 用于单片机的队列功能模块
51单片机移植操作系统
一个简单的51单片机操作系统的实现
递归到非递归的转换
51单片机通用汇编延时子程序
uCOS-Ⅱ C51移植笔记
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服