一,先了解一些基本概念
1,什么是操作系统?
操作系统是为了解决计算机资源争抢而编写的一个程序
2,什么是资源争抢?
多个任务在执行的过程中需要共享有限的资源
3,什么是任务?
计算机需要完成的某一项工作
4,顺序执行?
任务一个接一个的执行
5,多任务并行:
同时运行多个任务
6,任务优先级:
根据任务的重要性和使用频度决定工作的优先级
7,进程:
正在进行的任务
8,类比现实生活来理解:
①系统资源:在学校的操场上,有很多资源供学生玩耍,比如篮球场,足球场,篮球,足球。这相当于计算机中的系统资源
②任务:每个学生都有自己喜欢玩的项目,比如跳绳,踢足球,玩沙子。这些需求相当于计算机里的任务
③进程:当一个小朋友在玩耍。例如玩皮球,那么这个正在进行的活动就是一个进程
④顺序执行:如果操场上只有一个足球,那么小朋友需要一个接一个的踢足球,小明踢完,小红踢。相当于计算机里面的顺序执行。任务一个接一个的执行
⑤多任务并行:在这个情况下,操场上有非常多的资源供所有的小朋友玩。
例如:小明可以踢皮球,小红可以玩跳绳,小浩可以玩沙子,他们都在同时玩各自的游戏。这就相当于计算机里面的多任务并行,各个任务可以同时进行。
在学校里面,老师(操作系统)负责管理操场上的资源(系统资源),确保每个小朋友都能有序的玩耍(任务)。老师可以按实际情况选择让同学按顺序玩耍或同时玩耍,以便更好的利用操场上的资源。
9,高级操作系统特性:
高级操作系统具有任务切换、多任务并行和任务优先级设置的功能。
①任务切换:假设有两个任务:一个是小明想喝水,另一个是小红想画画。老师先满足了小明的需求,然后满足小红的需求,在这个过程中,老师从小明的需求切换到小红的需求。
②多任务并行:如果学校的资源足够丰富,大家可以同时玩耍。小明可以踢皮球,小红可以玩跳绳,小浩可以玩沙子,他们都在同时玩各自的游戏。这就相当于计算机里面的多任务并行,各个任务可以同时进行。
③任务优先级:小明和小红都想玩足球,此时发生了资源的争抢。但是小红的爸爸是校长,小红说我想先玩这个,老师就先让小红先玩了,这就是任务的优先级。计算机优先执行高优先级任务。
10,时间片轮转和上下文切换
假设老师需要在一段时间内满足多个小朋友的需求,例如小明想玩积木,小红想画画,小刚想听故事,并且只有一位老师,他们想得到老师的帮助。这时,老师会用“时间片”来分配自己的时间。
①时间片: 老师为每个小朋友分配固定时间,例如5分钟。这段时间被称为“时间片”。在这个时间片内,老师会专注于帮助一个小朋友。例如,老师先花5分钟陪小明玩积木,然后花5分钟陪小红画画,最后花5分钟给小刚讲故事。
②上下文切换:每当一个时间片结束,老师需要从当前任务(陪小明玩积木)切换到下一个任务(陪小红画画)。在这个过程中,老师需要记住前一个任务的状态(小明已经搭好了几个积木),以便在下一个时间片回到这个任务时可以继续帮助小明。这种在任务间进行状态切换的过程为“上下文切换”。
通过合理的分配时间片和进行上下文切换,老师能够高效的管理多个任务。计算机使用这个机制来确保计算资源得到合理的分配。
假设时间片非常短,5ms。先花10ms陪小明搭积木,然后花10ms陪小红画画,最后花10ms给小刚讲故事。因为小朋友的反应没那么快,感觉老师一直在跟自己玩。
11,操作系统和资源调度
在学校中,也可能会出现资源争抢的问题。例如,如果只有一套画笔和颜料,两个小朋友(小明,小红)同时想画画,那他们就发生了争抢,而老师(操作系统)需要采取措施来解决这个问题。
①优先级分配,可以先把画笔和颜料分给优先级比较高的任务。例如,如果小明需要完成画画作业,而小红只是想随手画个小老鼠,那老师就会把画笔和颜料优先分配给小明。
②时间片轮转:老师可以分配时间片来保证两个人都能使用资源。例如,小明和小红轮流使用画笔和颜料,每次5分钟。防止某个小朋友长时间独占资源。
12,中断系统
在学校中,我们可以将中断理解为突发事件,需要老师(操作系统)立即处理,暂停正在进行的活动。
情景:假设老师正在帮助小明绘画调色,此时小红摔倒了,受了伤。这个突发事件好比是一个“中断”。
在这种情况下,老师需要立刻暂停正在进行的绘画活动,处理突发事件。老师取查看小红的伤势,处理伤口。处理完之后,老师会重新回到绘画活动中,继续之前的工作,帮小明调色。
在计算机系统中,中断是类似的,当一个突发事件(外设发的信号、计时器到期或紧急报错)发生,CPU会停止正在执行的任务,转而处理这个事件,处理完之后,CPU会返回到原来的任务,从中断前的位置继续执行。
在计算机系统中,中断使得CPU能够在执行任务的同时,及时响应和处理紧急事件,提高系统的实时性和灵活性。
13,实时操作系统和非实时操作系统
实时操作系统:假设有一天,学校要举办一个晚会,需要老师(操作系统)来调度表演节目以及处理突发状况。在这个场景中,老师需要在特定的时间完成特定的任务。以确保晚会的顺利举办。;例如,老师需要在晚会开始前确保所有的节目都准备好,还需要在特定的时间开始和结束某个节目。如果某个节目没有按时开始或者结束,可能会影响整个晚会的进程。这种在特定时间内完成任务的操作系统就是实时操作系统。
非实时操作系统:我们来看另一个场景。假设在普通的上课日,老师需要安排各种活动,比如上课,吃饭,午休。在这种情况下,老师需要确保每个活动都安排,但没有严格的时间限制。例如,吃饭早一点,午休晚一点,不会产生严重影响。这种就是非实时操作系统。
实时操作系统分为硬实时和软实时:
硬实时:在晚会中,假如有一个节目需要在特定的时间点精确开始,例如在晚会开始后5min内。如果这个节目没有在这个时间点内准时开始,可能会导致晚会的失败,或产生严重的后果。在这种情况下,老师必须确保这个节目在特定的时间内开始,这就是硬实时,意味着任务必须在严格的时间限制内完成,否则会导致严重后果。
软实时:在晚会中,如果有一个节目希望在晚会10min内开始,但是如果晚一点也没关系。这种情况下,老师还是会尽力保证节目暗示开始,但即使稍微晚一点,给晚会影响也不大。这就是软实时。任务有时间限制,但即使没有完全满足时间要求,也不会导致系统失效或产生严重后果。
基于时间片切换的操作系统属于软实时操作系统。
14,操作系统概念总结一把
操作系统概念 | 学校场景 |
系统资源 | 玩具、游戏场地、定时器、秒表 |
任务 | 小朋友喜欢做的事情(画画,踢球) |
进程 | 小朋友正在进行的活动(画画,踢球) |
顺序执行 | 老师依次满足每个小朋友的需求 |
多任务并行 | 老师同时满足多个小朋友的需求 |
任务优先级 | 根据小朋友的需求紧急程度安排先后顺序 |
任务切换 | 老师在不同小朋友的需求之间切换 |
时间片 | 老师给每个小朋友分配一段时间 |
上下文切换 | 老师满足一个小朋友需求之后,快速切换满足另一个小朋友需求 |
上下文保存 | 老师在切换前记住第一个小朋友的状态,方便一会切回来继续满足他的需求 |
中断 | 突发事件导致老师暂停当前活动,处理紧急问题 |
资源争抢与解决办法 | 多个小朋友争抢玩具,老师协调和安排轮流使用或分享 |
实时操作系统 | 老师能够满足小朋友的需求,并按时完成时间要求 |
非实时操作系统 | 老师满足小朋友的要求,但不能保证完成任务的时间 |
硬实时 | 老师必须在规定时间内完成任务,否则会产生能够产生严重后果 |
软实时 | 老师尽量在规定时间内完成任务,但延迟不会产生严重后果 |
二,单片机的内存结构
寄存器组:地址范围0x00-0x1f。包含4组8位寄存器,分别R0-R7,对应的寄存器组选择由PSW中的RS0和RS1控制。
位寻址区:地址范围0x20-0x2f,包含了128位,可以直接使用位操作指令进行访问
字节寻址区:地址0x30-0x7f,用于一般数据存储
特殊功能寄存器(SFR):地址范围0x80-0xff,包含了所有特殊功能寄存器,如P0,P1,P2,P3等端口寄存器,ACC累加器,B寄存器,SP栈指针等。
0x0000到0xffff,这是程序存储器的地址范围,用于存储程序代码。这些数据是存在FLASH中的。
Flash存储器用于存储程序代码,RAM用于存储临时数据、变量、堆栈。程序代码冲FLASH存储器加载到RAM中,然后由CPU执行。
三,程序执行顺序切换的原理
计算机系统,通过修改PC的值可以修改下一行要执行程序的汇编代码的位置,但实际上stc单片机是没有汇编语言修改pc值的。因为程序计数器通常是由硬件自动递增的,用于指向将要执行的下一条指令的地址。
但我们可以通过其他手段来简介修改PC值,汇编语言有JUMP,和CALL,他们的区别就是有木有修改SP(堆栈指针)的内容。
四,show code
1,定义操作系统的loadtask函数
#include <stc8h.h>
#define MAX_TASKS 2 //任务的堆栈指针,简化方便我们当前操作系统只有2个task
#define MAX_TASK_DEP 32 //堆栈的深度
unsigned char task_sp[MAX_TASKS];
unsigned char task_stack[MAX_TASKS][MAX_TASK_DEP]; //每一个task任务的堆栈
2,写两个执行的task:task0, task1
unsigned char task_id;//当前任务号,从0 开始
void task0()
{
//第0号任务,代表第0个小朋友做的事情
unsigned int a = 3;
while (1)
{
a += 3;
}
}
void task1()
{
//第1号任务,代表第一个小朋友做的事情
unsigned int b = 5;
while (1)
{
b += 5;
}
}
3,通过修改sp来修改调用的函数
void main()
{
task_load(task0, 0);//把task0装载到内存中
task_id = 0;
SP = task_sp[0];//特殊功能寄存器
}
4,定义一个任务调度器
//定义一个任务切换的函数
//任务调度器
void task_switch() {
task_sp[task_id] = SP;//把当前系统的堆栈指针存入到某个小朋友的task_sp里面
task_id = (task_id + 1);//任务加1
if (task_id == MAX_TASKS) {
task_id = 0;
}
SP = task_sp[task_id];//SP存的是上下文信息
}
最终代码:
#include <stc8h.h>
#define MAX_TASKS 2 //任务的堆栈指针,简化方便我们当前操作系统只有2个task
#define MAX_TASK_DEP 32 //堆栈的深度
unsigned char idata task_sp[MAX_TASKS];
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP]; //每一个task任务的堆栈
//iadata 访问最快的那一层空间
unsigned char task_id;//当前任务号,从0 开始
//定义一个任务切换的函数
//任务调度器
void task_switch() {
task_sp[task_id] = SP;//把当前系统的堆栈指针存入到某个小朋友的task_sp里面
task_id = (task_id + 1);//任务加1
if (task_id == MAX_TASKS) {
task_id = 0;
}
SP = task_sp[task_id];//SP存的是上下文信息
}
void task0()
{
//第0号任务,代表第0个小朋友做的事情
static unsigned int a = 3;
while (1)
{
a += 3;
task_switch();
}
}
void task1()
{
//第1号任务,代表第一个小朋友做的事情
static unsigned int b = 5;
while (1)
{
b += 5;
task_switch();
}
}
//幼儿园老师,加载任务
//fn是一个函数的指针,注意数据类型是int
//tid task id,是8位的 0,1
//把一个task的函数指针放入对应的堆栈空间
void task_load(unsigned int fn, unsigned chat tid)
{
task_sp[tid] = task_stack[tid] + 1;//把任务的指针往下一个空间挪一格,两个char
task_stack[tid][0] = fn & 0xff;
task_stack[tid][1] = fn >> 8;
}
void main()
{
task_load(task0, 0);//把task0装载到内存中
task_load(task1, 1);//把task1装载到内存
task_id = 0;
SP = task_sp[0];//特殊功能寄存器
}
一个小的操作系统就是这样的,复杂一点的哥们还没学,继续加油兄弟们!