操作系统的概念:
操作系统(Operating System, OS)是一种系统软件。它在计算机硬件与计算机应用程序之间,通过提供应用程序接口(Application Programming Interface, API),屏蔽了计算机硬件工作的一些细节,从而使应用程序的设计人员得以在一个友好的平台上进行应用程序的设计和开发,大大提高了应用程序的开发效率。
操作系统的作用:
计算机的操作系统为应用程序提供了一个界面友好,性能稳定、安全,效率高,操作方便的虚拟计算机。
操作系统的功能:
处理器的管理: 一是对中断的管理,二是对处理器的工作进行调度。
因为处理器硬件只能发现外部事件的中断申请,而不能对中断进行管理和处理,于是对中断的管理和处理只能由操作系统来承担。
现代计算机应用程序大多是多道程序结构,那么一个处理器如何来运行这多道程序就是一个较为复杂的问题。它要求操作系统应该能按照某种规则对处理器的使用进行合理的分配,这样才能使多道应用程序协调有秩序的运行,这就是操作系统所应该具有的处理器调度功能。
**存储器的管理: ** 存储器是计算机的重要资源,如何合理地分配和使用该资源当然是计算机操作系统责无旁贷的重要责任。
设备的管理: 计算机系统一般都配有外部设备,因此计算机操作系统还必须有对这些外部设备管理的功能,以便完成用户提出的I/O)请求,加快输入/输出的速度,提高I/O设备的利用率。当然,作为一个完善的计算机操作系统还要提供外部设备的驱动程序。
**文件的管理: ** 在计算机中,程序和数据通常都以文件的形式存储在外存(例如硬盘、光盘等)中,由于在这些外存中文件量极其巨大,如果对它们没有良好的管理方式,就会导致严重的后果。为此,计算机操作系统必须具备文件管理功能。
**网络和通信的管理: ** 使用网络的计算机除了需要配备连网硬件之外,其操作系统必须还要具有管理网上资源、通过网络进行通信、故障管理、安全管理、性能管理等网络功能。
提供用户接口: 计算机操作系统除了提供以上所说的各项功能之外,还要为用户提供良好使用上述功能的接口,以便用户能方便地使用操作系统的功能,从而能有效地组织作业及其工作,并使系统能高效地运行。
嵌入式系统:
嵌入式系统是对对象进行自动控制而使其具有智能化并可嵌入对象体系中的专用计算机系统。
嵌入式系统的特点:
实时操作系统的要求:
第一,实时系统的计算必须产生正确的结果,称为逻辑或功能正确(Logical or Functional Correctness);
第二,实时系统的计算必须在预定的时间内完成,称为时间正确(Timing Correctness)。
实时操作系统的条件:
嵌入式系统与嵌入式操作系统的区别与联系:
区别:
定义和范围:
FreeRTOS
、VxWorks
、μC/OS
等。功能和职责:
组成部分:
开发复杂度:
联系:
共存关系:
相互依赖:
共同目标:
优化设计:
一个函数就是一段代码,C编译器会为这段代码分配一段连续内存空间,同时把首地址作为常量值赋予以函数名定义的常量。这就是说,函数名就是该函数的指针。
函数指针的定义:
返回值类型 (* 变量名) (参数1类型,参数2类型,……);
其中,返回值类型 (*) (参数1类型,参数2类型,……); 为函数指针变量的类型
# include int function_1(int, float) { printf("%d\n", "function_1"); return 0; } int function_2(int, float) { printf("%d\n", "function_2"); return 0; } //定义函数指针pf int (* pf) (int, float); int main() { pf = function_1; pf(10, 3,14); pf = function_2; pf(100, 63.24); return 0; }
通过函数指针变量来间接调用函数,而且同一个函数指针变量还可以随时通过改变与之关联的函数名来改变它所指向的函数,因而使得同一个指针变量可以调用不同的函数,只要它们的返回类型和参数类型相同。
函数指针作为函数参数及回调函数
void function(int (* pf)(int,float)) { pf(10,8.888); }
函数的参数pf就是一个函数指针,其类型为int(*)(int,float)。即具有如下返回值及参数类型的函数的函数名(函数指针)均可以作为上述function()函数的实参,例如int usr_I(int,float)、int usr_2(int,float)、int usr_3(int,float),等等。
#include int usr_1(int, float) { printf("%s\n", "usr_1"); return 0; } int usr_2(int, float) { printf("%s\n", "usr_2"); return 0; } int usr_3(int, float) { printf("%s\n", "usr_3"); return 0; } int (* pf)(int, float); //以函数指针为参数的函数 void sys_function(int (* pf)(int, float)) { printf("这是function函数中调用用户函数:"); pf(10, 8,888); printf("本函数自己的功能\n"); } int main() { sys_function(usr_1); sys_function(usr_2); sys_function(usr_3); return 0; }
将函数指针作为函数参数,可以将一个函数传递到另一个函数内来调用。这种用法在操作系统这类系统软件中应用得相当频繁,因为操作系统的某些函数的功能需要用户配合才能实现,常需要调用用户提供的函数。目前,大致有两种方法来实现用户函数的调用:一种方法就是像上例中的sys_function()那样以函数指针来传递被调用的用户函数;另一种方法就是在系统函数中设置所谓的“钩子函数”,即在系统函数中需要调用用户功能的地方调用一个空函数,然后由用户去实现这个空函数的功能。在第一种方法中,由于是系统函数调用用户函数,与常用的用户程序调用系统函数的调用方向不同,故人们将这种调用叫做“回调”,而被系统调用的这个函数就叫做“回调函数”。
复杂的数据类型名称的简化
typedef void(* PFON)(int,int); PFON function; = void(* function)(int, int); void (* b[10])(void (*)(int,int)); //由于这个定义中的程序实体名称为b,因为其后面有一个数组符号“[]”,所以这一定是一个名称为b的数组定义。为了方便,先把数组符号“[]”去掉,那么剩下的便是如下的样子: void (* b)(void (*)(int,int)); //所以它的右边括号里的void(*)(int,int)是一个类型,并且是一个指针类型,于是先为这个指针类型定义一个别名: typedef void (* pFunParam)(int,int); //于是原来的初始定义就可以写成如下形式: void (* b)(pFunParam); //b是一个无返回值,参数类型为pFunParam的函数指针,如果在该定义前使用typedef,并用pFunx代替变量名b: typedef void (* pFunx)(pFunParam); //于是这个函数指针类型别名就是这个pFux,原来声明语句就可表示成如下语句: pFunx b[10]; //即声明的是一个其元素为函数指针的数组。
用typedef来定义与平台无关的数据类型
typedef long double RFAL; typedef double RFAL; //当跨平台时,只要修改typedef本身就行,不用对其他源码做任何修改
增强代码的可读性
避免错误
typedef struct tcb{ char * code_name; //代码名称 int p; //重要性级别 int v_number; //版本号 void (* fun)(void); //指向被管理代码的函数指针 }TCB;
代码示例:
#include #include typedef struct tcb { char * code_name; int p; int v_num; void (* fun)(); }TCB; void function_1() { int i; for(i=0;i<10;i++) { printf("111111111\n"); } } void function_2() { int i; for(i=0;i<10;i++) { printf("222222222\n"); } } void function_3() { int i; for(i=0;i<10;i++) { printf("333333333\n"); } } //创建控制块函数 TCB GreateTCB(char * name, int pp, int vnum, void (* f)()) { TCB tcb; tcb.code_name = name; tcb.p = pp; tcb.v_num = vnum; tcb.fun = f; return tcb; } int main() { char code_name[10]; int t,i; TCB tcbTbl[3]; tcbTbl[0] = GreateTCB("F1", 2, 1, function_1); tcbTbl[1] = GreateTCB("F2", 2, 4, function_2); tcbTbl[2] = GreateTCB("F3", 4, 5, function_3); printf("Input CodeNume:"); scanf("%s", code_name); t=0; for(i=0; i<3; i++) { if(strcmp(tcbTbl[i].code_name, code_name) == 0) { tcbTbl[i].fun(); t = 1; } if(i == 2 && t == 0) printf("No %s\n", code_name); } return 0; }
定义一个任务控制块(TCB)结构体,用于描述一个任务的基本属性(名字、优先级、变量数量和要执行的函数)。
GreateTCB
函数用于创建并初始化一个TCB实例,方便任务的创建与管理。
通过上述结构体和初始化函数,可以方便的创建任务:
void task_function() { // 执行一些任务 } int main() { TCB myTask = GreateTCB("Task1", 1, 10, task_function); myTask.fun(); // 执行任务函数 return 0; }
在操作系统中,链表、堆栈和位图是重要的数据结构,它们在管理内存、处理进程和任务调度等方面起着关键作用。以下是它们的具体用途:
链表
链表是一种动态数据结构,可以灵活地管理内存,常用于以下几种情况:
堆栈
堆栈是一种后进先出(LIFO)的数据结构,主要用于以下几种情况:
位图
位图是一种紧凑的表示法,使用位来表示资源的使用情况,主要用于以下几种情况:
裸机与RTOS的区别:
裸机又称为前后台系统,前台系统指的是中断服务函数,后台系统指的是大循环,即应用程序。
RTOS全称为Real Time OS,就是实时操作系统,强调的是实时性
简介:
FreeRTOS 是一个免费的嵌入式实时操作系统,具有免费开源、可裁剪、简单、优先级不限、任务不限、抢占/协程/时间调度方式等特点。
操作系统是允许多个任务“同时运行”的,操作系统的这个特性被称为多任务。然而实际上,一个CPU核心在某一时刻只能运行一个任务,而操作系统中任务调度器的责任就是决定在某一时刻CPU究竟要运行哪一个任务,任务调度器使得CPU在各个任务之间来回切换并处理任务,由于切换处理任务的速度非常快,因此就给人造成了一种同一时刻有多个任务同时运行的错觉。
特点:
FreeRTOS操作系统是一个功能强大的RTOS操作系统,并且能够根据需求进行功能裁剪,以满足各种环境的要求,具体特点如下:
调度器就是使用相关的调度算法来决定当前需要执行的哪个任务
抢占式调度:主要是针对优先级不同的任务,每个任务都有一个优先级,优先级高的任务可以抢占优先级低的任务。
时间片调度:主要针对优先级相同的任务,当多个任务的优先级相同时, 任务调度器会在每一次系统时钟节拍到的时候切换任务。
协程式调度:当前执行任务将会一直运行,同时高优先级的任务不会抢占低优先级任务FreeRTOS现在虽然还支持,但是官方已经表示不再更新协程式调度。