第一篇:嵌入式操作系统实验报告
实验一 嵌入式开发环境的建立
一、实验目的
通过此实验系统,读者可以了解嵌入式实时操作系统 uC/OS-II 的内核机制和运行原理。本实验系统展示了 uC/OS-II 各方面的管理功能,包括信号量、队列、内存、时钟等。在各个实验中具体介绍了 uC/OS-II 的相关函数。读者在做实验的同时能够结合理论知识加以分析,了解各个函数的作用和嵌入式应用程序的设计方法,最终对整个 uC/OS-II 和嵌入式操作系统的应用有较为清楚的认识。
二、实验步骤
1.安装集成开发环境LambdaEDU 集成开发环境LambdaEDU 的安装文件夹为 LambdaEDU,其中有一个名为“Setup.exe” 的文件,直接双击该文件便可启动安装过程。具体的安装指导请看“LambdaEDU 安装手 册.doc”文件。
当 LambdaEDU 安装完毕之后,我们看到的是一个空的界面,现在就开始一步一步地将 我们的实验项目建立并运行起来。
2.建立项目
为了我们的实验运行起来,需要建立1 个项目基于x86 虚拟机的标准应用项目。通过点 击“文件”、“新建”、“项目”开始根据向导创建一个项目。
在随后出现的对话框中选择“Tool/标准应用项目”,点击下一步,开始创建一个标准的 可执行的应用程序项目。
在随后出现的对话框中填入项目名称“ucos_x86_demo”。点击“下一步”。
选择“pc386 uC/OS-II 应用(x86)”作为该项目的应用框架。点击“下一步”
选择“pc386_elf_tra_debug”作为该项目的基本配置。点击“完成”。
新创建的项目“ucos_x86_demo”将会被添加到项目列表。src 文件夹下保存了该项目中 包含的源文件。ucos2 文件夹中包含了移植到x86 虚拟机的全部代码。init.c 文件是基于ucos2 和本虚拟机的一个应用程序。在进行ucos2 内核实验中,只需要替换init.c 文件,即可。文
件名不限,但是文件名中最好不要使用英文符号和数字以外的其他字符,3.构建项目
到这里,项目配置全部完成。接下来就可以进行构建项目了。
第一次构建本项目,在此项目上点击右键,选择“重建BSP 及项目”。即可开始构建。
之后弹出的对话框显示了构建的进度。可以点击“在后台运行”,以隐藏该对话框
在构建的同时,在右下角的“构建信息”视图输出构建过程中的详细信息:
注:“重新构建”将本项目中的全部源代码进行一次完全的编译和连接,花费时间较多。“构建项目”则仅仅将新修改过的源代码进行编译和连接,花费时间最少。“重建BSP及项 目”,不但要完成“重新构建”的全部工作,另外还要编译与该项目有关的的LambdaEDU 中内置的部分代码,花费时间最多。但是在项目刚建立后,第一次构建时需要选择“重建 BSP 及项目”。以后的构建中选择“重新构建”或“构建项目”即可。另外,在替换了源代 码中的文件后,需要选择“重新构建”来完成该项目的构建。
4.配置虚拟机和目标机代理
(1)制作X86启动盘
在 LambdaEDU 中依次点击“工具”、“Bochs”、“制作虚拟机启动映象”。对启动盘进行一些参数设置后(如下图所示),系统将自动为你生成一个PC 虚拟机的 启动盘映像。
(2)配置虚拟机 选择使用的网络适配器(网卡)后,点击“确定”完成配置。
注意:如果计算机上有多网卡,请将其他网卡停用(包括 VMware 虚拟机添加的虚拟 网卡)。
(3)创建目标机代理
配置好虚拟机后,创建目标机代理:点击LambdaEDU 左下方窗口中绿色的十字符号,在弹出的窗口中选择“基于TA 的连接方式”,并点击“下一步”。
在弹出的“新目标机连接配置中”的这些参数,应该与之前制作启动盘时设置的参数一致。
注意:
名字:输入目标机的名字(缺省是 default),注意如果和现有目标机重名的话,改个名 字。
连接类型:默认选择 UDP IP地址:这里输入目标机(在本实验系统中是虚拟机)的 IP地址;
最后点击“确定”,在目标机管理窗口中,可以看到新增加了一个名为default 的目标机 节点
(4)调试应用 启动虚拟机。
虚拟机启动后的画面如下(其中显示的IP 地址创建虚拟机启动盘时填入的IP 地址)中设置的IP 地址):
在成功完成构建的项目ucos_x86_demo 中的“pc386_elf_tra_debug”上点击鼠标右键,在弹出的菜单中选择“调试”,启动调试器调试生成的程序:
第一次进行调试/运行,需要选择目标机,如下图,选择“Default”,点击“确定”,开 始向目标机(虚拟机)下载应用程序。程序下载完成后,会弹出一个“确认透视图切换”对话框,选择“是”,切换到调试透 视图。
调试的界面如下:
点击绿色的按钮,全速运行。
注意:全速运行后,程序不能够被暂停和停止。
三、实验过程中遇到的问题及体会
在设置IP地址时,要求该IP地址与本计算机在同一个子网中,同时要求该 IP地址没有被网络上其他计算机使用。此外,通过构建开发环境,处次体验到了嵌入式开发工作的乐趣。
实验二 任务的基本管理
一、实验目的
1.理解任务管理的基本原理,了解任务的各个基本状态及其变迁过程; 2.掌握 uC/OS-II 中任务管理的基本方法(创建、启动、挂起、解挂任务); 3.熟练使用 uC/OS-II 任务管理的基本系统调用。
二、实验原理及程序结构
1.实验设计
为了展现任务的各种基本状态及其变迁过程,本实验设计了 Task0、Task1 两个任务: 任务 Task0 不断地挂起自己,再被任务 Task1 解挂,两个任务不断地切换执行。通过本实验,读者可以清晰地了解到任务在各个时刻的状态以及状态变迁的原因。2.运行流程 描述如下:
(1)系统经历一系列的初始化过程后进入 boot_card()函数,在其中调用 ucBsp_init()进 行板级初始化后,调用 main()函数;
(2)main()函数调用 OSInit()函数对 uC/OS-II 内核进行初始化,调用 OSTaskCreate 创 建起始任务 TaskStart;
(3)main()函数调用函数 OSStart()启动 uC/OS-II 内核的运行,开始多任务的调度,执 行当前优先级最高的就绪任务 TaskStart;(4)TaskStart 完成如下工作:
a、安装时钟中断并初始化时钟,创建 2 个应用任务;
b、挂起自己(不再被其它任务唤醒),系统切换到当前优先级最高的就绪任务Task0。之后整个系统的运行流程如下:
t1 时刻,Task0 开始执行,它运行到 t2 时刻挂起自己;
t2 时刻,系统调度处于就绪状态的优先级最高任务 Task1 执行,它在 t3 时刻唤醒Task0,后者由于优先级较高而抢占 CPU;
Task0 执行到 t4 时刻又挂起自己,内核调度 Task1 执行; Task1 运行至 t5 时刻再度唤醒 Task0; ……
3.µC/OS-Ⅱ中的任务描述
一个任务通常是一个无限的循环,由于任务的执行是由操作系统内核调度的,因此任务是绝不会返回的,其返回参数必须定义成 void。在μC/OS-Ⅱ中,当一个运行着的任务使一个比它优先级高的任务进入了就绪态,当前任务的 CPU 使用权就会被抢占,高优先级任务会立刻得到 CPU 的控制权(在系统允许调度和任务切换的前提下)。μC/OS-Ⅱ可以管理多达 64 个任务,但目前版本的μC/OS-Ⅱ有两个任务已经被系统占用了(即空闲任务和统计任务)。必须给每个任务赋以不同的优先级,任务的优先级号就是任务编号(ID),优先级可以从 0 到 OS_LOWEST_PR10-2。优先级号越低,任务的优先级越高。μC/OS-Ⅱ总是运行进入就绪态的优先级最高的任务。4.源程序说明(1)TaskStart任务
TaskStart 任务负责安装操作系统的时钟中断服务例程、初始化操作系统时钟,并创建所 有的应用任务:
UCOS_CPU_INIT();/* Install uC/OS-II's clock tick ISR */ UCOS_TIMER_START();/*Timer 初始化*/ TaskStartCreateTasks();/* Create all the application tasks */ OSTaskSuspend(OS_PRIO_SELF);
具体负责应用任务创建的 TaskStartCreateTasks 函数代码如下,它创建了两个应用任务 Task0 和 Task1:
void TaskStartCreateTasks(void){
INT8U i;
for(i = 0;i < N_TASKS;i++)// Create tasks {
TaskData[i] = i;// Each task will display itsown information }
OSTaskCreate(Task0,(void *)&TaskData[0], &TaskStk[0][TASK_STK_SIZE1], 6);}
TaskStart 任务完成上述操作后将自己挂起,操作系统将调度当前优先级最高的应用任务Task0 运行。(2)应用任务
应用任务 Task0 运行后将自己挂起,之后操作系统就会调度处于就绪状态的优先级最高的任务,具体代码如下: void Task0(void *pdata){
INT8U i;INT8U err;i=*(int *)pdata;for(;;){
printf(“Application tasks switched %d times!nr”,++count);
printf(“TASK_0 IS RUNNING..............................................................nr”);printf(“task_1 is suspended!nr”);
printf(“**************************************************nr”);err=OSTaskSuspend(5);// suspend itself } }
应用任务 Task1 运行后将 Task0 唤醒,使其进入到就绪队列中: void Task1(void *pdata){
INT8U i;INT8U err;i=*(int *)pdata;for(;;){
OSTimeDly(150);
printf(“Application tasks switched %d times!nr”,++count);printf(“task_0 is suspended!nr”);printf(“TASK_1 IS RUNNING..............................................................nr”);printf(“**************************************************nr”);OSTimeDly(150);
err=OSTaskResume(5);/* resume task0 */ } }
三、运行及观察应用输出信息
按照本实验手册第一部分所描述的方法建立应用项目并完成构建,当我们在 LambdaEDU 调试器的控制下运行构建好的程序后,将看到在μC/OS-Ⅱ内核的调度管理下,两个应用任务不断切换执行的情形:
四、本实验中用到的µC/OS-Ⅱ相关函数
4.1 OSTaskCreate()
OSTaskCreate()建立一个新任务。任务的建立可以在多任务环境启动之前,也可以在 正在运行的任务中建立。中断处理程序中不能建立任务。一个任务必须为无限循环结构,且 不能有返回点。
OSTaskCreate()是为与先前的μC/OS 版本保持兼容,新增的特性在 OSTaskCreateExt()函数中。
无论用户程序中是否产生中断,在初始化任务堆栈时,堆栈的结构必须与 CPU 中断后 寄存器入栈的顺序结构相同。详细说明请参考所用处理器的手册。函数原型:
INT8U OSTaskCreate(void(*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio);
参数说明:
task 是指向任务代码首地址的指针。
pdata 指向一个数据结构,该结构用来在建立任务时向任务传递参数。
ptos 为指向任务堆栈栈顶的指针。任务堆栈用来保存局部变量,函数参数,返回地址 以及任务被中断时的 CPU 寄存器内容。任务堆栈的大小决定于任务的需要及预计的中断嵌 套层数。计算堆栈的大小,需要知道任务的局部变量所占的空间,可能产生嵌套调用的函数,及中断嵌套所需空间。如果初始化常量 OS_STK_GROWTH 设为 1,堆栈被设为从内存高地址 向 低 地 址 增 长,此时 ptos 应 该 指 向任 务堆 栈 空 间 的 最 高 地 址。反 之,如 果OS_STK_GROWTH 设为 0,堆栈将从内存的低地址向高地址增长。prio 为任务的优先级。每个任务必须有一个唯一的优先级作为标识。数字越小,优先级越高。返回值:
OSTaskCreate()的返回值为下述之一: OS_NO_ERR:函数调用成功。
OS_PRIO_EXIST:具有该优先级的任务已经存在。
OS_PRIO_INVALID:参数指定的优先级大于 OS_LOWEST_PRIO。 OS_NO_MORE_TCB:系统中没有 OS_TCB 可以分配给任务了。注意:
任务堆栈必须声明为 OS_STK 类型。
在任务中必须调用μC/OS 提供的下述过程之一:延时等待、任务挂起、等待事件发生(等待信号量,消息邮箱、消息队列),以使其他任务得到 CPU。用 户 程 序 中 不 能 使 用 优 先 级 0,1,2,3,以 及 OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, OS_LOWEST_PRIO-1, OS_LOWEST_PRIO。这些优先级μC/OS 系统
保留,其余的 56 个优先级提供给应用程序。4.2 OSTaskSuspend()
OSTaskSuspend()无条件挂起一个任务。调用此函数的任务也可以传递参数
OS_PRIO_SELF,挂起调用任务本身。当前任务挂起后,只有其他任务才能唤醒。任务挂起 后,系统会重新进行任务调度,运行下一个优先级最高的就绪任务。唤醒挂起任务需要调用 函数 OSTaskResume()。
任务的挂起是可以叠加到其他操作上的。例如,任务被挂起时正在进行延时操作,那么 任务的唤醒就需要两个条件:延时的结束以及其他任务的唤醒操作。又如,任务被挂起时正 在等待信号量,当任务从信号量的等待对列中清除后也不能立即运行,而必须等到被唤醒后。函数原型:
INT8U OSTaskSuspend(INT8U prio);参数说明:
prio 为指定要获取挂起的任务优先级,也可以指定参数 OS_PRIO_SELF,挂起任务本 身。此时,下一个优先级最高的就绪任务将运行。返回值:
OSTaskSuspend()的返回值为下述之一: OS_NO_ERR:函数调用成功。
OS_TASK_ SUSPEND_IDLE:试图挂起 µC/OS-II 中的空闲任务(Idle task)。此为非法操作。
OS_PRIO_INVALID :参数指定的优先级大于 OS_LOWEST_PRIO 或没有设定 OS_PRIO_SELF 的值。
OS_TASK_ SUSPEND _PRIO:要挂起的任务不存在。注意:
在程序中 OSTaskSuspend()和 OSTaskResume()应该成对使用。用 OSTaskSuspend()挂起的任务只能用 OSTaskResume()唤醒。4.3 OSTaskResume()
OSTaskResume()唤醒一个用 OSTaskSuspend()函数挂起的任务。OSTaskResume()也是唯一能“解挂”挂起任务的函数。函数原型:
INT8UOSTaskResume(INT8U prio);参数说明:
prio 指定要唤醒任务的优先级。返回值:
OSTaskResume()的返回值为下述之一: OS_NO_ERR:函数调用成功。
OS_TASK_RESUME_PRIO:要唤醒的任务不存在。
OS_TASK_NOT_SUSPENDED:要唤醒的任务不在挂起状态。
OS_PRIO_INVALID:参数指定的优先级大于或等于 OS_LOWEST_PRIO。
五、实验过程中遇到的问题及体会
实验过程中体会到了嵌入式开发的乐趣,对上课老师所讲的内容有了进一步的认识与理解。17 实验三 信号量:哲学家就餐问题的实现
一、实验目的
掌握在基于嵌入式实时操作系统 uC/OS-II 的应用中,任务使用信号量的一般原理。通 过经典的哲学家就餐实验,了解如何利用信号量来对共享资源进行互斥访问。
二、实验原理及程序结构
1.实验设计
掌握在基于嵌入式实时操作系统 uC/OS-II 的应用中,任务使用信号量的一般原理。通 过经典的哲学家就餐实验,了解如何利用信号量来对共享资源进行互斥访问。2.源程序说明
五个哲学家任务(ph1、ph2、ph3、ph4、ph5)主要有两种过程:思考(即睡眠一段时
间)和就餐。每个哲学家任务在就餐前必须申请并获得一左一右两支筷子,就餐完毕后释放 这两支筷子。五个哲学家围成一圈,每两人之间有一支筷子。一共有五支筷子,在该实验中 用了五个互斥信号量来代表。每个任务的代码都一样,如下所示: void Task(void *pdata){
INT8U err;INT8U i;INT8U j;
i=*(int *)pdata;j=(i+1)% 5;
uC/OS-II 实验指导书 for(;;){
TaskThinking2Hungry(i);OSSemPend(fork[i], 0, &err);
OSSemPend(fork[j], 0, &err);/* Acquire semaphores to eat */ TaskEat(i);
OSSemPost(fork[j]);
OSSemPost(fork[i]);/* Release semaphore */ OSTimeDly(200);/* Delay 10 clock tick */ } }
操作系统配置
修改 uC_OS-II/OS_CFG.h: :: :
#define OS_MAX_EVENTS 10 /*最多可以有 10 个事件*/ #define OS_MAX_FLAGS 5 /*最多可以有 5 个事件标志*/
#define OS_MAX_MEM_PART 5 /*最多可以划分 5 个内存块*/ #define OS_MAX_QS 2 /*最多可以使用 2 个队列*/ #define OS_MAX_TASKS 8 /*最多可以创建 8 个任务*/
#define OS_LOWEST_PRIO 14 /*任务优先级不可以大于 14*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空闲任务堆栈大小*/ #define OS_TASK_STAT_EN 1 /*是否允许使用统计任务*/ #define OS_TASK_STAT_STK_SIZE 1024 /*统计任务堆栈大小*/ #define OS_FLAG_EN 1 /*是否允许使用事件标志功能*/
#define OS_FLAG_WAIT_CLR_EN 1 /*是否允许等待清除事件标志*/ #define OS_FLAG_ACCEPT_EN 1 /*是否允许使用 OSFlagAccept()*/ #define OS_FLAG_DEL_EN 1 /*是否允许使用 OSFlagDel()*/
#define OS_FLAG_QUERY_EN 1 /*是否允许使用 OSFlagQuery()*/ #define OS_MBOX_EN 0 /*是否允许使用邮箱功能*/
#define OS_MEM_EN 0 /*是否允许使用内存管理的功能*/
#define OS_MUTEX_EN 0 /*是否允许使用互斥信号量的功能*/ #define OS_Q_EN 0 /*是否允许使用队列功能*/ #define OS_SEM_EN 1 /*是否允许使用信号量功能*/
#define OS_SEM_ACCEPT_EN 1 /*是否允许使用 OSSemAccept()*/ #define OS_SEM_DEL_EN 1 /*是否允许使用OSSemDel()*/
#define OS_SEM_QUERY_EN 1 /*是否允许使用OSSemQuery()*/ #define OS_TASK_CHANGE_PRIO_EN 1 /* 是 否 允 许 使 用 OSTaskChangePrio()*/
#define OS_TASK_CREATE_EN 1 /*是否允许使用 OSTaskCreate()*/
#define OS_TASK_CREATE_EXT_EN 1 /*是否允许使用 OSTaskCreateExt()*/ #define OS_TASK_DEL_EN 1 /*是否允许使用 OSTaskDel()*/
#define OS_TASK_SUSPEND_EN 1 /* 是 否 允 许 使 用 OSTaskSuspend()and OSTaskResume()*/
#define OS_TASK_QUERY_EN 1 /*是否允许使用 OSTaskQuery()*/ #define OS_TIME_DLY_HMSM_EN 1 /* 是 否 允 许 使 用 OSTimeDlyHMSM()*/
#define OS_TIME_DLY_RESUME_EN 1 /* 是 否 允 许 使 用 OSTimeDlyResume()*/
#define OS_TIME_GET_SET_EN 1 /* 是否允许使用 OSTimeGet()和 OSTimeSet()*/
#define OS_SCHED_LOCK_EN 1 /* 是 否 允 许 使 用 OSSchedLock()和 OSSchedUnlock()*/
#define OS_TICKS_PER_SEC 200 /*设置每秒之内的时钟节拍数目*/
三、运行及观察应用输出信息
开始,所有的哲学家先处于 thinking 状态,然后都进入 hungry 状态:
后首先获得两个信号量的 1、3 号哲学家开始 eating,待他们释放相关信号量之后,哲
学家 2、5、4 获得所需的信号量并 eating: 应用如此这般地循环执行程序下去„„
四、本实验中用到的µC/OS-Ⅱ相关函数
4.1 OSSemCreate()
OSSemCreate()函数建立并初始化一个信号量。信号量的作用如下: 允许一个任务和其他任务或者中断同步 取得设备的使用权 标志事件的发生
函数原型:
OS_EVENT *OSSemCreate((((WORD value))))参数说明:
value 参数是所建立的信号量的初始值,可以取 0 到 65535 之间的任何值。返回值:
OSSemCreate()函数返回指向分配给所建立的信号量的控制块的指针。如果没有可用的 控制块,OSSemCreate()函数返回空指针。注意:
必须先建立信号量,然后使用。4.2 OSSemPend()
OSSemPend()函数用于任务试图取得设备的使用权,任务需要和其他任务或中断同
步,任务需要等待特定事件的发生的场合。如果任务调用 OSSemPend()函数时,信号量 的值大于零,OSSemPend()函数递减该值并返回该值。如果调用时信号量等于零,OSSemPend()函数函数将任务加入该信号量的等待队列。OSSemPend()函数挂起当前 任务直到其他的任务或中断置起信号量或超出等待的预期时间。如果在预期的时钟节拍内信 号量被置起,μC/OS-Ⅱ默认最高优先级的任务取得信号量恢复执行。一个被 OSTaskSuspend()函数挂起的任务也可以接受信号量,但这个任务将一直保持挂起状态直到通过调用 OSTaskResume()函数恢复任务的运行。函数原型: :: :
Void OSSemPend(OS_EVNNT *pevent, INT16U timeout, int8u *err);参数说明: :: :
pevent
是指向信号量的指针。该指针的值在建立该信号量时可以得到。(参考 OSSemCreate()函数)。
Timeout
允许一个任务在经过了指定数目的时钟节拍后还没有得到需要的信号量时 恢复就绪状态。如果该值为零表示任务将持续地等待信号量,最大的等待时间为 65535 个时
钟节拍。这个时间长度并不是非常严格的,可能存在一个时钟节拍的误差。
Err 是指向包含错误码的变量的指针。OSSemPend()函数返回的错误码可能为下述几 种:
OS_NO_ERR :信号量不为零。
OS_TIMEOUT :信号量没有在指定数目的时钟周期内被设置。
OS_ERR_PEND_ISR :从中断调用该函数。虽然规定了不允许从中断调用该函数,但 µC/OS-Ⅱ仍然包含了检测这种情况的功能。
OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针。返回值: 无 注意:
必须先建立信号量,然后使用。不允许从中断调用该函数。
4.3 OSSemPost()
OSSemPost()函数置起指定的信号量。如果指定的信号量是零或大于零,OSSemPost()函数递增该信号量并返回。如果有任何任务在等待信号量,最高优先级的任务将得到信
号量并进入就绪状态。任务调度函数将进行任务调度,决定当前运行的任务是否仍然为最高 优先级的就绪状态的任务。函数原型:
INT8U OSSemPost(OS_EVENT *pevent);参数说明:
pevent
是指向信号量的指针。该指针的值在建立该信号量时可以得到。(参考 OSSemCreate()函数)。返回值:
OSSemPost()函数的返回值为下述之一:
OS_NO_ERR :信号量被成功地设置
OS_SEM_OVF :信号量的值溢出
OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针 注意:
必须先建立信号量,然后使用。4.4 OSTimeDly()
OSTimeDly()将一个任务延时若干个时钟节拍。如果延时时间大于 0,系统将立即进 行任务调度。延时时间的长度可从 0 到 65535 个时钟节拍。延时时间 0 表示不进行延时,函
数将立即返回调用者。延时的具体时间依赖于系统每秒钟有多少时钟节拍(由文件 SO_CFG.H 中的常量 OS_TICKS_PER_SEC 设定)。函数原型:
void OSTimeDly(INT16U ticks);参数说明:
ticks 为要延时的时钟节拍数。返回值:
无
注意:
注意到延时时间 0 表示不进行延时操作,而立即返回调用者。为了确保设定的延时时间,建议用户设定的时钟节拍数加 1。例如,希望延时 10 个时钟节拍,可设定参数为 11。
五、实验过程中遇到的问题及体会
在实验前要对该问题进行深入的理解,即五个哲学家任务(ph1、ph2、ph3、ph4、ph5)主要有两种过程:思考(即睡眠一段时间)和就餐。每个哲学家任务在就餐前必须申请并获得一左一右两支筷子,就餐完毕后释放这两支筷子。五个哲学家围成一圈,每两人之间有一支筷子。只有理解了,才能更好的进行实验。
第二篇:操作系统实验报告
实验二
进程调度
1.目的和要求
通过这次实验,理解进程调度的过程,进一步掌握进程状态的转变、进程调度的策略,进一步体会多道程序并发执行的特点,并分析具体的调度算法的特点,掌握对系统性能的评价方法。
2.实验内容
阅读教材《计算机操作系统》第二章和第三章,掌握进程管理及调度相关概念和原理。
编写程序模拟实现进程的轮转法调度过程,模拟程序只对PCB进行相应的调度模拟操作,不需要实际程序。假设初始状态为:有n个进程处于就绪状态,有m个进程处于阻塞状态。采用轮转法进程调度算法进行调度(调度过程中,假设处于执行状态的进程不会阻塞),且每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程。
程序要求如下:
1)输出系统中进程的调度次序; 2)计算CPU利用率。
3.实验环境
Windows操作系统、VC++6.0 C语言
4设计思想:
(1)
程序中进程可用PCB表示,其类型描述如下:
struct PCB_type
{
int pid;
//进程名 int
state;
//进程状态
2——表示“执行”状态
1——表示“就绪”状态
0——表示“阻塞”状态
int cpu_time;//运行需要的CPU时间(需运行的时间片个数)
} 用PCB来模拟进程;
(2)设置两个队列,将处于“就绪”状态的进程PCB挂在队列ready中;将处于“阻塞”状态的进程PCB挂在队列blocked中。队列类型描述如下:
struct QueueNode{
struct PCB_type
PCB;
Struct QueueNode *next;} 并设全程量:
struct QueueNode *ready_head=NULL,//ready队列队首指针
*ready_tail=NULL , //ready队列队尾指针
*blocked_head=NULL,//blocked队列队首指针 *blocked_tail=NULL;//blocked队列队尾指针(3)设计子程序:
start_state();
读入假设的数据,设置系统初始状态,即初始化就绪队列和阻塞队列。
dispath();
模拟调度,当就绪队列的队首进程运行一个时间片后,放到就绪队列末尾,每次都是队首进程进行调度,一个进程运行结束就从就绪队列中删除,当到t个时间片后,唤醒阻塞队列队首进程。
calculate();
就绪进程运行一次,usecpu加1,当就绪队列为空时unusecpu加1,CPU利用率为use_cpu/(use_cpu+unuse_cpu)。
5源代码:
#include
struct PCB_type {
int pid;
//进程名
int
state;
//进程状态
//2--表示“执行”状态
//1--表示“就绪”状态
//0--表示“阻塞”状态
int cpu_time;//运行需要的CPU时间(需运行的时间片个数)};struct QueueNode{
struct PCB_type
PCB;
struct QueueNode *next;};struct QueueNode *ready_head=NULL,//ready队列队首指针
*ready_tail=NULL,//ready队列队尾指针
*block_head=NULL,//blocked队列队首指针
*block_tail=NULL;
//blocked队列队尾指针
int use_cpu,unuse_cpu;
void start_state()//读入假设的数据,设置系统初始状态 {
int n,m;
int i;
struct QueueNode *p,*q;
printf(“输入就绪节点个数n:”);
scanf(“%d”,&n);
printf(“输入阻塞节点个数m:”);
scanf(“%d”,&m);
p=(struct QueueNode *)malloc(sizeof(struct QueueNode));
p->next =NULL;
ready_head=ready_tail=p;
for(i=0;i { p=(struct QueueNode *)malloc(sizeof(struct QueueNode)); p->next =NULL; p->PCB.state=1; printf(“输入就绪进程%d的pid和cpu_time:”,i+1); scanf(“%d%d”,&p->PCB.pid,&p->PCB.cpu_time); ready_tail->next=p; ready_tail=p; } q=(struct QueueNode *)malloc(sizeof(struct QueueNode)); q->next =NULL; block_head=block_tail=q; for(i=0;i { q=(struct QueueNode *)malloc(sizeof(struct QueueNode)); q->next=NULL; q->PCB.state=0; printf(“输入阻塞进程%d的pid和cpu_time:”,i+1); scanf(“%d%d”,&q->PCB.pid,&q->PCB.cpu_time); block_tail->next=q; block_tail=q; } printf(“n处于就绪状态的进程有:n”); p=ready_head->next; i=1; while(p) {printf(“进程%d的pid和cpu_time:%5d%5d%5dn“,i,p->PCB.pid,p->PCB.state,p->PCB.cpu_time); p=p->next; i++; } } void dispath() //模拟调度 { int x=0,t; use_cpu=0; unuse_cpu=0; printf(”输入t:“); scanf(”%d“,&t); printf(”开始调度n“); while(ready_head!=ready_tail||block_head!=block_tail) { struct QueueNode *p,*q; if(ready_head!=ready_tail) { p=ready_head->next; ready_head->next=p->next; p->next=NULL; if(ready_head->next==NULL) { ready_tail=ready_head; } p->PCB.state=2; printf(”进程%d调度t“,p->PCB.pid); state和 use_cpu++; x++; p->PCB.cpu_time--; if(p->PCB.cpu_time) { ready_tail->next=p; ready_tail=p; } else { printf(”进程%d完成t“,p->PCB.pid); free(p); } } else { unuse_cpu++; x++; printf(”空闲一个时间片t“); } if(x==t&&block_head!=block_tail) { q=block_head->next; block_head->next=q->next; q->next=NULL; if(block_head->next==NULL) { block_tail=block_head; } ready_tail->next=q; ready_tail=q; x=0; } } } void calculate() //计算CPU利用率 { printf(”ncpu的利用率%.2fn“,(float)use_cpu/(use_cpu+unuse_cpu)); } void main(){start_state(); dispath(); calculate();} 6运行结果: 7实验总结: 实验帮我复习了数据结构和C语言,且巩固课本知识,知道了如何定义结构体,如何在链接队列中增删节点。模拟进程调度帮我们巩固了进程三状态之间的变迁。懂得调式的重要性。总之,我们明白了理论联系实际。多看书,多上机。 实验三 可变分区存储管理 1.目的和要求 通过这次实验,加深对内存管理的认识,进一步掌握内存的分配、回收算法的思想。 2.实验内容 阅读教材《计算机操作系统》第四章,掌握存储器管理相关概念和原理。编写程序模拟实现内存的动态分区法存储管理。内存空闲区使用自由链管理,采用最坏适应算法从自由链中寻找空闲区进行分配,内存回收时假定不做与相邻空闲区的合并。 假定系统的内存共640K,初始状态为操作系统本身占用64K。在t1时间之后,有作业A、B、C、D分别请求8K、16K、64K、124K的内存空间;在t2时间之后,作业C完成;在t3时间之后,作业E请求50K的内存空间;在t4时间之后,作业D完成。要求编程序分别输出t1、t2、t3、t4时刻内存的空闲区的状态。 3.实验环境 Windows操作系统、VC++6.0 C语言 4.设计思想 模拟内存分配和回收,要设置两个链队列,一个空闲区链和一个占用区链,空闲区链节点有起始地址,大小和指向下一节点的指针等数据域,占用区链节点有起始地址,大小,作业名和指向下一节点的指针等数据域,本实验用最坏适应算法,每次作业申请内存都是从空闲链队头节点分配,如果相等,就删除空闲头结点,如果小于申请的,就不分配,否则就划分内存给作业,剩下的内存大小,重新插入空闲链队,按从大到小,接着把作业占用的内存放到占用区链节点的末尾。每次作业运行完,就要回收其占用的内存大小,把作业节点按从大到小插入到空闲链队中。5.源代码: #include struct freelinkNode *next;};struct busylinkNode{ char name; int len;int address;struct busylinkNode *next;};struct freelinkNode *free_head=NULL; //自由链队列(带头结点)队首指针 struct busylinkNode *busy_head=NULL; //占用区队列队(带头结点)首指针 struct busylinkNode *busy_tail=NULL; //占用区队列队尾指针 void start(void)/* 设置系统初始状态*/ { struct freelinkNode *p; struct busylinkNode *q; free_head=(struct freelinkNode*)malloc(sizeof(struct freelinkNode)); free_head->next=NULL;// 创建自由链头结点 busy_head=busy_tail=(struct busylinkNode*)malloc(sizeof(struct busylinkNode)); busy_head->next=NULL;// 创建占用链头结点 p=(struct freelinkNode *)malloc(sizeof(struct freelinkNode)); p->address=64; p->len=640-64;//OS占用了64K p->next=NULL; free_head->next=p; q=(struct busylinkNode *)malloc(sizeof(struct busylinkNode)); q->name='S';/* S表示操作系统占用 */ q->len=64;q->address=0;q->next=NULL; busy_head->next=q;busy_tail=q;} void requireMemo(char name, int require)/*模拟内存分配*/ { freelinkNode *w,*u,*v;busylinkNode *p;if(free_head->next->len>=require){ p=(struct busylinkNode*)malloc(sizeof(struct busylinkNode)); p->name=name; p->address=free_head->next->address; p->len=require; p->next=NULL; busy_tail->next=p; busy_tail=p;} else printf(”Can't allocate“); w=free_head->next; free_head->next=w->next; if(w->len==require) { free(w);} else { w->address=w->address+require; w->len=w->len-require;} u=free_head; v=free_head->next; while((v!=NULL)&&(v->len>w->len)){ u=v; v=v->next;} u->next=w; w->next=v;} void freeMemo(char name)/* 模拟内存回收*/ { int len; int address;busylinkNode *q,*p;freelinkNode *w,*u,*v;q=busy_head; p=busy_head->next; while((p!=NULL)&&(p->name!=name)) { q=p; p=p->next;} if(p==NULL){ printf(”%c is not exist“,name);} else { if(p==busy_tail) { busy_tail=q; } else { q->next=p->next; len=p->len; address=p->address; free(p); w=(struct freelinkNode*)malloc(sizeof(struct freelinkNode)); w->len=len; w->address=address; u=free_head; v=free_head->next; while((v!=NULL)&&(v->len>len)) { u=v;v=v->next; } u->next=w; w->next=v; } } } void past(int time)/* 模拟系统过了time 时间*/ { printf(”过了时间%d后:n“,time);} void printlink()/* 输出内存空闲情况(自由链的结点)*/ { freelinkNode *p; printf(”内存的空闲情况为:n“); p=(struct freelinkNode *)malloc(sizeof(struct freelinkNode)); p=free_head->next; while(p!=NULL) { printf(”内存的起始地址和内存的大小%5dt%5d:n",p->address,p->len); p=p->next; } } void main(){ int t1=1,t2=2,t3=3,t4=4; start(); past(t1); requireMemo('A',8); requireMemo('B',16); requireMemo('C',64); requireMemo('D',124); printlink(); past(t2); freeMemo('C'); printlink(); past(t3); requireMemo('E',50); printlink(); past(t4); freeMemo('D'); printlink();} 6.运行结果: 7.实验总结: 巩固编程能力,和调式能力,复习课本知识,明白理论联系实际的重要性,动手能力非常重要,多看书,多独立思考,品味痛苦的过程,享受成功的喜悦。 操作系统实验报告 院系:数计学院 班级:大类6班 学号:100511624 姓名:明章辉 指导教师:徐军利 许昌学院 《操作系统》实验报告书 学号:姓名:闫金科班级:成绩: 5006140057 14物联网工程 2016年02月实验一 Linux的安装与配置 一、实验目的 1.熟悉Linux系统的基本概念,比如Linux发行版、宏内核、微内核等。2.掌握Linux系统的安装和配置过程,初步掌握Linux系统的启动和退出方法。3.熟悉Linux系统的文件系统结构,了解Linux常用文件夹的作用。 二、实验内容 1.从网络上下载VMware软件和两个不同Linux发行版镜像文件。2.安装VMware虚拟机软件。 3.在VMware中利用第一个镜像文件完成第一个Linux的安装,期间完成网络信息、用户信息、文件系统和硬盘分区等配置。 4.在VMware中利用第二个镜像文件完成第二个Linux的安装,并通过LILO或者GRUB解决两个操作系统选择启动的问题。 5.启动Linux系统,打开文件浏览器查看Linux系统的文件结构,并列举出Linux常用目录的作用。 三、实验过程及结果 1、启动VMware,点击新建Linux虚拟机,如图所示: 2、点击下一步,选择经典型,点击下一步在选择客户机页面选择Linux,版本选择Red Hat Enterprise Linux 5,如图所示: 3、点击下一步创建虚拟机名称以及所要安装的位置,如图所示: 4、点击下一步,磁盘容量填一个合适大小,此处选择默认值大小10GB,如图所示: 5、点击完成,点击编辑虚拟机设置,选择硬件选项中的CD-ROM(IDE...)选项,在右侧连接中选择“使用ISO镜像(I)”选项,点击“浏览”,找到Linux的镜像文件,如图所示: 6点击确定按钮后,点击启动虚拟机按钮,来到Linux的安装界面,如图所示: 7、到此页面之后,等待自动检测安装,如图所示: 8、等到出现如图所示页面后点击“skip”按钮,跳过检测,直接进入安装设置界面,如图所示: 9、安装设计界面如图所示: 10、点击Next按钮进入设置语言界面,设置语言为“简体中文”,如图所示: 11、点击Nest按钮进入系统键盘设置按钮,设置系统键盘为“美国英语式”,如图所示: 12、点击下一步按钮,弹出“安装号码”对话框,选择跳过输入安装号码,如图所示: 13、按照提示,一直点击下一步按钮,如图所示: 14、到设置最后一步,点击下一步按钮进入开始安装Red Hat Enterprise Linux Sever界面,如图所示: 15、安装完成后,进入欢迎界面,按照提示点击前进按钮知道进入Linux桌面,如图所示: 16、安装成功的Linux系统桌面如图所示,桌面包含五个图标,分别为:计算机、jk’s Home、回收站、RHEL/5.3 i386DVD。 四、实验总结 通过安装虚拟机等操作让我认识到Linux这系统一些基本特点,本次试验学会了安装虚拟机并且使用虚拟机安装操作系统,掌握了红帽Linux系统的安装和配置过程,以及对镜像ISO文件的使用,有别于我们机器上使用的系统,通过虚拟机这个软件还可以在已有系统的基础上使用其他操作系统。安装过程中一定要注意选择版本的时候要选择Red Hat Enterprise Linux 5版本,否则安装不能成功。自己动手成功的安装了Linux系统,自己对Linux的学习产生更大的兴趣。 实验二 Linux操作系统的运行模式 一、实验目的 1.熟悉Linux系统终端工作环境的使用,了解Linux命令的格式,使用学会利用常用的Linux命令来完成系统的管理和维护。 2.了解X-Windows的特点,熟悉Linux图形用户接口的使用,掌握GNOME桌面环境的基本操作。 3.了解和掌握在Linux环境下安装软件包的方法,如QQ for Linux等用软件的安装方法。 二、实验内容 1.启动Linux系统打开虚拟终端界面,使用Linux的在线帮助指令man或help获得ls、uname、date、cal、mkdir、cp等Linux命令的帮助手册,了解这些命令的具体使用方法。同时,也可以通过执行“命令名 –help”来显示该命令的帮助信息,如“ls –help”,试用这些命令。 2.通过uname命令的执行,查看并给出相关系统信息:操作系统的名称、系统域名、系统CPU名称等。 3.在主目录下创建一个名为myetc的子目录,将/etc目录下与网络相关的文件和子目录拷贝到该目录,并将这些文件的执行权限设置为可执行。 4.在主目录/home下创建目录program、music 和temp,然后在program下建立目录java和C,列出完成该过程的所有命令。 5.在图形界面环境中,查看GNOME桌面的面板和桌面,设置GNOME,包括屏幕保护程序、更改背景和指定关联程序等。6.实现对光盘的加载和访问,然后卸载。 三、实验过程及结果 1、打开终端,输入 【ls –help】来查看【ls】指令的使用方法,同理查看uname、date、cal、mkdir、cp的使用方法。 2、在终端中输入【uname –a】显示操作系统名系统cpu名和系统域名 3、重启系统,用【root】用户名进入系统,以获得权限。在终端中输入【mkdir myetc】,在主目录下创建【myrtc】的目录,【ls】查看是否创建。输入【cd..】返回至【/】文件,输入【cp –r etc root/myetc】讲etc中内容复制到myetc中,进入myetc文件【ls】查看。输入 【chmod u+x etc】赋予文件可执行的权限,输入【ll】查看。 4、在home下,输入【mkdir {program,music,temp}】,可在home下创立这三个目录,输入【ls】查看。在program下输入【mkdir{java,C}】,可创立java和C两个目录,【ls】查看。 5、在桌面上方选择【系统】-【首选项】,即可设置屏幕保护程序和更改背景和指定关联程序 5、在桌面上可见看到有CD光盘,双击浏览,右键【弹出】即卸载。 四、实验总结和体会 Linux的指令系统是学习Linux操作系统很重要的一部分,指令系统相当于在Windows操作系统下的doc,可以省去图形化界面。通过这次的实验让我了解了Linux的强大功能,了解到Linux有许多方便快捷的设置基本配置的方法,这使我更喜欢上Linux的使用。在使用指令的过程中,有时候对文件的操作需要一定的权限,这时需要在登陆时用户名使用【root】,而不是我们在安装时使用的用户名,这样就获得了管理员权限,可以对一些系统文件进行操作。 实验三 Linux应用软件与系统管理 一、实验目的 1.了解OpenOffice.Org集成办公软件,掌握利用OpenOffice.Org的套件来完成文档和图片的处理。 2.了解Linux网络管理的知识,熟悉Linux网络配置的方法,掌握在Linux环境下配置Web服务器和ftp服务的方法。 二、实验内容 1.配置Linux系统的网络环境,安装FTP和Web服务器,并配置相关的属性,利用FTP实现WINDOWS和Linux之间的数据交换。 2.利用FTP程序上传自己的照片到FTP服务器,利用OpenOffice的文字处理工具OpenOffice Writer制作一份表格形式的个人简历。个人简历中至少包含学号、姓名、性别、专业、照片和学习经历等内容,并保存为网页格式(html格式)。3.将个人简历网页设置为WEB服务器的首页,然后在客户端利用浏览器访问WEB服务器,查看效果。 4.通过读取proc文件系统,获取系统各种信息(如主机名、系统启动时间、运行时间、版本号、所有进程信息、CPU使用率等),并以比较容易的方式显示。 三、实验过程及结果 1.配置网络环境:在(服务.cmd).里面进行以下操作:在服务里选择3按回车 完成后,可在本地连接看到VMware已连接上网络 在虚拟机设置中设置以太网网络连接方式为 网关地址填虚拟机的网管,IP地址设为虚拟机的一个子网: 四、总结: 在linux系统下,make是我们经常用到的编译命令,所以关于make代码和他的操作指令一定要记清楚。所以,熟练掌握了make和makefile工具之后,源码安装软件就变的像windows下安装软件一样简单。 实验四 进程控制与管理 一、实验目的 1.掌握GCC编译器的用法,学会利用GCC编辑器来编辑C语言程序,学会利用GDB调试器来调试C语言程序。 2.理解进程和程序的区别和联系,3.掌握在Linux环境下观察进程运行情况和CPU工作情况的命令。4.了解fork()系统调用,掌握利用fork()创建进程的方法。 5.了解Linux系统其他与进程相关的系统调用,如exec、wait和exit等。6.了解Linux常用的进程通信机制。 二、实验内容 1.利用Linux的进程管理命令ps、top来监视和跟踪进程,体会进程和程序的关系。2.利用Linux的文字编辑器编写文件复制的C语言程序,并用gcc编译该程序,然后运行该程序。 3.编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。试观察记录屏幕上的显示结果,并分析原因。 4.修改上述程序,每一个进程循环显示一句话。子进程显示'daughter „'及'son „„',父进程显示 'parent „„',观察结果,分析原因。5.用fork()创建一个进程,再调用exec()用新的程序替换该子进程的内容。 三、实验过程及结果 1、利用Linux的进程管理命令ps、top来监视和跟踪进程,体会进程和程序的关系。<1>从用户身份切换到ROOT身份 <2>输入命令 ps 查看进程 <2>输入命令 top 跟踪进程 2、利用Linux的文字编辑器编写一个计算机100个自然数和的C语言程序,并用gcc编译该程序,然后运行该程序。 <1>创建一个.C文件 并进入进行编辑 <2>用GCC 进行编译,再查看文件,发现产生执行文件 a.out <3>执行这个可执行文件得到结果5050 1、编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。试观察记录屏幕上的显示结果,并分析原因。 <1>穿件一个.C文件 并进行编写程序代码 <2>反复执行2次该程序 <3>可以看出两次执行的结果 a b c 出现的顺序不同,原因是,3个进程的输出次序是随机的,并不会按规定的顺序出现,所以会出现上述结果。 4、修改上述程序,每一个进程循环显示一句话。子进程显示'daughter „'及'son „„',父进程显示 'parent „„',观察结果,分析原因。<1>重新修改代码 <3>执行这段程序 <4>原分析: 因和之前一样,可以看出执行的结果 3个单词出现的顺序不同,原因是,3个进程的输出次序是随机的,并不会按规定的顺序出现,所以会出现上述结果。 5、用fork()创建一个进程,再调用exec()用新的程序替换该子进程的内容。<1> 编写代码 <2> 执行的结果 结果表明 execl 替代了son的内容 四、实验总结和体会 这个实验考察的是进程之间存在很多可能性以及对编辑器的使用。本次实验学习了在linux环境下用gcc编译器运行c语言程序,在linux环境下编写程序用到了vi编辑器,知道了该编辑器也需要各种命令来操作。编写C语言程序时用到了fork()函数,再调用execl()用新的程序替换该子进程的内容。 实验五 进程调度模拟程序的设计与实现 一、实验目的 1.了解进程调度的概念,掌握常用进程调度算法的原理。2.掌握Linux程序设计编辑、编译和调试的技巧。 二、实验内容 1.编写程序实现进程调度调度算法先来先服务、优先级高优先和时间片轮转调度算法。(编程语言不限) 2.输入数据,输出运行结果。 三、实验过程及结果 1先来先服务 #i nclude struct { int id; float ArriveTime;float RequestTime;float StartTime;float EndTime;float RunTime;float DQRunTime;int Status;}arrayTask[4];GetTask(){ int i;float a; for(i=0;i<4;i++){arrayTask[i].id=i+1;printf(“input the number”); printf(“input the the ArriveTime of arrayTask[%d]:”,i);scanf(“%f”,&a); arrayTask[i].ArriveTime=a; printf(“input the RequestTime of arrayTask[%d]:”,i);scanf(“%f”,&a); arrayTask[i].RequestTime=a;arrayTask[i].StartTime=0;arrayTask[i].EndTime=0;arrayTask[i].RunTime=0;arrayTask[i].Status=0; } } int fcfs() { int i,j,w=0; for(i=0;i<4;i++) { if(arrayTask[i].Status==0) { t=arrayTask[i].ArriveTime; w=1; } if(w==1) break; } for(i=0;i<4;i++) { if(arrayTask[i].ArriveTime t=arrayTask[i].ArriveTime; } for(i=0;i<4;i++) { if(arrayTask[i].ArriveTime==t) return i; } } int sjf(){ int i,x=0,a=0,b=0;float g; for(i=0;i<4;i++){ if(arrayTask[i].Status==1){g=arrayTask[i].EndTime;x=1;} } if(x==0){ t=arrayTask[0].ArriveTime; for(i=0;i<4;i++){ if(arrayTask[i].ArriveTime t=arrayTask[i].ArriveTime;a=i;} } return a;} else { for(i=0;i<4;i++){ if(arrayTask[i].EndTime>g)g=arrayTask[i].EndTime;} for(i=0;i<4;i++){ if(arrayTask[i].Status==0&& arrayTask[i].ArriveTime<=g){ t=arrayTask[i].RequestTime;a=i;b=1;} /*判断有没有进程在前个进程完成前到达*/ } if(b!=0)/*有进程到达则按SJF*/ { for(i=0;i<4;i++){ if(arrayTask[i].Status==0&&arrayTask[i].ArriveTime<=g&&arrayTask[i].RequestTime return a;} else{ /*否则按FCFS*/ for(i=0;i<4;i++) {if(arrayTask[i].Status==0)t=arrayTask[i].ArriveTime;} for(i=0;i<4;i++){ if(arrayTask[i].Status==0&&arrayTask[i].ArriveTime return a;} } } new(int s)/*定义执行进程后相关数据的修改*/ { int i,g=0;for(i=0;i<4;i++){ if(arrayTask[i].Status==0)continue;else { g=1;break;} } if(g==0)/*当处理的是第一个未执行的进程时执行*/ { arrayTask[s].StartTime=arrayTask[s].ArriveTime; arrayTask[s].EndTime=arrayTask[s].RequestTime+arrayTask[s].ArriveTime;arrayTask[s].RunTime=arrayTask[s].RequestTime;arrayTask[s].Status=1;g=2;} if(g==1)/*当处理的不是第一个未执行的进程时执行*/ { arrayTask[s].Status=1;for(i=0;i<4;i++){ if(arrayTask[i].Status==1)d=arrayTask[i].EndTime;} for(i=0;i<4;i++)/*查找最后执行的进程的完成时间*/ { if(arrayTask[i].EndTime>d&&arrayTask[i].Status==1)d=arrayTask[i].EndTime;} if(arrayTask[s].ArriveTime arrayTask[s].StartTime=arrayTask[s].ArriveTime; arrayTask[s].EndTime=arrayTask[s].StartTime+arrayTask[s].RequestTime;arrayTask[s].RunTime=arrayTask[s].EndTime-arrayTask[s].ArriveTime;} arrayTask[s].DQRunTime=arrayTask[s].RunTime/arrayTask[s].RequestTime;} Printresult(int j)/*定义打印函数*/ { printf(“%dt”,arrayTask[j].id); printf(“%5.2ft”,arrayTask[j].ArriveTime);printf(“%5.2ft”,arrayTask[j].RequestTime);printf(“%5.2ft”,arrayTask[j].StartTime);printf(“%5.2ft”,arrayTask[j].EndTime);printf(“%5.2ft”,arrayTask[j].RunTime);printf(“%5.2fn”,arrayTask[j].DQRunTime);} main(){ int i,b,k,a,c=0;int d[4];clrscr(); printf(“t F.FCFS n”);printf(“t S.SFJ n”);printf(“t Q.EXIT n”);for(i=0;;i++){ if(c)break; printf(“please input the number a:n”);scanf(“%d”,&a);switch(a){ case Q: c=1;break; case F:printf(“please input the different-ArriveTime of arrayTasksn”);GetTask(); printf(“*****************************the result of fcfsn”);printf(“NumbertArrivetServertStarttFinishtTurnovetTake power turnover timen”); for(b=0;b<4;b++)/*调用两个函数改变结构体数的值*/ { k=fcfs();d[b]=k;new(k);} for(b=0;b<4;b++) Printresult(d[b]);/*调用打印函数打出结果*/ continue; case S: printf(“please input the different-RequestTime of array Tasksn”);GetTask(); printf(“******************************the result of sjfn”);printf(“NumbertArrivetRequesttStarttEndtRuntDQRun timen”);for(b=0;b<4;b++){ k=sjf();d[b]=k;new(k);} for(b=0;b<4;b++)Printresult(d[b]);continue; default:printf(“the number Error.please input another number!n”);} } } 四、实验总结和体会 通过做本实验,让我对进程或作业先来先服务、高优先权、按时间片轮转调度算法以及进程调度的概念和算法,有了更深入的认识!理解进程的状态及变化,动态显示每个进程的当前状态及进程的调度情况。进程调度是处理机管理的核心内容。优先级高优先是根据作业的优先级,总是选择优先级最高者进入队列。轮转调度算法是调度程序每次把CPU分配给就绪队列首进程/线程使用规定的时间间隔,就绪队列中都路保留巡行一个时间片。 目录 实验一 跑马灯实验.........................................................................1 实验二 按键输入实验.....................................................................3 实验三 串口实验.............................................................................5 实验四 外部中断实验.....................................................................8 实验五 独立看门狗实验................................................................11 实验七 定时器中断实验................................................................13 实验十三 ADC实验........................................................................15 实验十五 DMA实验........................................................................17 实验十六 I2C实验........................................................................21 实验十七 SPI实验........................................................................24 实验二十一 红外遥控实验............................................................27 实验二十二 DS18B20实验.............................................................30 实验一 跑马灯实验 一.实验简介 我的第一个实验,跑马灯实验。 二.实验目的 掌握STM32开发环境,掌握从无到有的构建工程。 三.实验内容 熟悉MDK KEIL开发环境,构建基于固件库的工程,编写代码实现跑马灯工程。通过ISP下载代码到实验板,查看运行结果。使用JLINK下载代码到目标板,查看运行结果,使用JLINK在线调试。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件。 五.实验步骤 1.熟悉MDK KEIL开发环境 2.熟悉串口编程软件ISP 3.查看固件库结构和文件 4.建立工程目录,复制库文件 5.建立和配置工程 6.编写代码 7.编译代码 8.使用ISP下载到实验板 9.测试运行结果 10.使用JLINK下载到实验板 11.单步调试 12.记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 两个灯LED0与LED1实现交替闪烁的类跑马灯效果,每300ms闪烁一次。 七.实验总结 通过本次次实验我了解了STM32开发板的基本使用,初次接触这个开发板和MDK KEILC软件,对软件操作不太了解,通过这次实验了解并熟练地使用MDK KEIL软件,用这个软件来编程和完成一些功能的实现。作为 STM32 的入门第一个例子,详细介绍了STM32 的IO口操作,同时巩固了前面的学习,并进一步介绍了MDK的软件仿真功能。 实验二 按键输入实验 一.实验简介 在实验一的基础上,使用按键控制流水灯速度,及使用按键控制流水灯流水方向。 二.实验目的 熟练使用库函数操作GPIO,掌握中断配置和中断服务程序编写方法,掌握通过全局变量在中断服务程序和主程序间通信的方法。 三.实验内容 实现初始化GPIO,并配置中断,在中断服务程序中通过修改全局变量,达到控制流水灯速度及方向。 使用JLINK下载代码到目标板,查看运行结果,使用JLINK在线调试。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK、示波器。软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件。 五.实验步骤 1在实验1代码的基础上,编写中断初始化代码 2在主程序中声明全局变量,用于和中断服务程序通信,编写完成主程序 3编写中断服务程序 4编译代码,使用JLINK下载到实验板 5.单步调试 6记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 我们将通过MiniSTM32 板上载有的3个按钮,来控制板上的2个LED,其中KEY0控制LED0,按一次亮,再按一次,就灭。KEY1 控制LED1,效果同KEY0。KEY_2(KEY_UP),同时控制LED0 和LED1,按一次,他们的状态就翻转一次。 七.实验总结 通过本次实验,我学会了如何使用STM32 的IO 口作为输入用。TM32 的IO 口做输入使用的时候,是通过读取IDR 的内容来读取IO 口的状态的。这里需要注意的是 KEY0 和KEY1 是低电平有效的,而WK_UP 是高电平有效的,而且要确认WK_UP 按钮与DS18B20 的连接是否已经断开,要先断开,否则DS18B20 会干扰WK_UP按键!并且KEY0 和KEY1 连接在与JTAG 相关的IO 口上,所以在软件编写的时候要先禁用JTAG 功能,才能把这两个IO 口当成普通IO 口使用。 实验三 串口实验 一.实验简介 编写代码实现串口发送和接收,将通过串口发送来的数据回送回去。 二.实验目的 掌握STM32基本串口编程,进一步学习中断处理。 三.实验内容 编写主程序,初始化串口1,设置波特率为9600,无校验,数据位8位,停止位1位。编写中断服务程序代码实现将发送过来的数据回送。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK、示波器。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1编写串口初始化代码 2编写中断服务程序代码 3编译代码,使用JLINK或ISP下载到实验板 4记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 把代码下载到 MiniSTM32 开发板,可以看到板子上的LED0 开始闪烁,说明程序已经在跑了。接着我们打开串口调试助手,看到如下信息: 证明串口数据发送没问题。接着,我们在发送区输入上面的文字,输入完后按回车键。然后单击发送,可以得到如下结果: 七.实验总结 通过本次实验,我进一步了解了串口的使用,学会了通过串口发送和接收数据,将通过串口发送来的数据回送回去。该实验的硬件配置不同于前两个实验,串口 1 与USB 串口默认是分开的,并没有在PCB上连接在一起,需要通过跳线帽来连接一下。这里我们把P4 的RXD 和TXD 用跳线帽与P3 的PA9 和PA10 连接起来。 实验四 外部中断实验 一.实验简介 STM32 的 IO 口在本章第一节有详细介绍,而外部中断在第二章也有详细的阐述。这里我们将介绍如何将这两者结合起来,实现外部中断输入。 二.实验目的 进一步掌握串口编程,进一步学习外部中断编程,提高编程能力。 三.实验内容 初始化IO口的输入,开启复用时钟,设置IO与中断的映射关系,从而开启与IO口相对应的线上中断事件,设置触发条件。配置中断分组(NVIC),并使能中断,编写中断服务函数。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK、示波器。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1.2.3.4.编写中断服务程序代码 使用ISP下载到实验板 测试运行结果 记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 打开串口助手。 七.实验总结 首先需要将IO设置为中断输入口: 1)初始化 IO 口为输入。 2)开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。 3)开启与该 IO口相对的线上中断/事件,设置触发条件。 4)配置中断分组(NVIC),并使能中断。 5)编写中断服务函数。 这一节,使用的是中断来检测按键,通过 WK_UP 按键实现按一次 LED0 和 LED 1 同时翻转,按 KEY0 翻转 LED0,按 KEY1 翻转 LED1。 试验中外部中断函数不能进入的原因分析 : 1)GPIO或者AFIO的时钟没有开启。2)GPIO和配置的中断线路不匹配。3)中断触发方式和实际不相符合。 4)中断处理函数用库函数时,写错,经常可能出现数字和字母之间没有下划线。5)外部中断是沿触发,有可能不能检测到沿,比如 中断线是低电平(浮空输入),触发是下降沿触发,可能会出现一直是低电平,高电平的时候是一样的情况,电平持续为高电平。 6)没有用软件中断来触发外部中断,调用函数EXTI_GenerateSWInterrupt;,因为软件中断先于边沿中断处理。 实验五 独立看门狗实验 一. 实验简介 独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。 二.实验目的 通过编程,编写一个独立看门狗驱动程序 三.实验内容 启动 STM32 的独立看门狗,从而使能看门狗,在程序里面必须间隔一定时间喂狗,否则将导致程序复位。利用这一点,我们本章将通过一个 LED 灯来指示程序是否重启,来验证 STM32 的独立看门狗。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1.2.3.4.参考教材独立看门狗部分,编写独立看门狗驱动程序。建立和配置工程 编写代码 使用ISP下载到实验板 记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 在配置看门狗后,看到LED0 不停的闪烁,如果WK_UP 按键按下,就喂狗,只要WK_UP 不停的按,看门狗就一直不会产生复位,保持LED0 的常亮,一旦超过看门狗定溢出时间(Tout)还没按,那么将会导致程序重启,这将导致LED0 熄灭一次。 七.实验总结 通过本次实验,我掌握了启动独立看门狗的步骤: 1)向 IWDG_KR 写入 0X5555。2)向 IWDG_KR 写入 0XAAAA。3)向 IWDG_KR 写入 0XCCCC。 通过上面 3个步骤,启动 STM32 的看门狗,从而使能看门狗,在程序里面就必须间隔一定时间喂狗,否则将导致程序复位。利用这一点,本章通过一个LED 灯来指示程序是否重启,来验证 STM32 的独立看门狗。在配置看门狗后,LED0 将常亮,如果 WK_UP 按键按下,就喂狗,只要 WK_UP 不停的按,看门狗就一直不会产生复位,保持 LED 0 的常亮,一旦超过看门狗溢出时间(Tout)还没按,那么将会导致程序重启,这将导致 LED 0 熄灭一次。 实验七 定时器中断实验 一. 实验简介 STM32 的定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几微秒到几毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。 二.实验目的 熟练掌握定时器中断,学会对定时器中断的编程操作。 三.实验内容 使用定时器产生中断,然后在中断服务函数里面翻转 LED1 上的电平,来指示定时器中断的产生,修改中断时间。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1.参考教材定时器中断部分,编写定时器中断的驱动程序。2.编写主程序 3.编译代码,使用JLINK或ISP下载到实验板 4.记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 七.实验总结 通过本次实验,认识到时间中断来控制LED灯的闪烁,同时也可以将时间中断应用到控制其他的程序块。 以TIME3为例产生中断的步骤为 1)TIM3 时钟使能。 2)设置 TIM3_ARR 和 TIM3_PSC 的值。 3)设置 TIM3_DIER 允许更新中断。 4)允许 TIM3 工作。 5)TIM3 中断分组设置。6)编写中断服务函数。 在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志。 实验十三 ADC实验 一.实验简介 通过DAC将STM32系统的数字量转换为模拟量。使用ADC将模拟量转换为数字量。 二.实验目的 掌握DAC和ADC编程。 三.实验内容 编写代码实现简单的DAC单次发送 编写代码实现ADC采集DAC发送的数据,并发送到串口 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1编写主程序 2编译代码,使用JLINK或ISP下载到实验板,使用串口调试助手观察数据 3记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 七.实验总结 本节将利用 STM32的 ADC1 通道 0 来采样外部电压值,并在串口调试助手中显示出来。步骤如下: 1)开启 PA 口时钟,设置 PA0 为模拟输入。 2)使能 ADC1 时钟,并设置分频因子。 3)设置 ADC1 的工作模式。 4)设置 ADC1 规则序列的相关信息。 5)开启 AD 转换器,并校准。 6)读取 ADC 值。 在上面的校准完成之后,ADC 就算准备好了。接下来我们要做的就是设置规则序列 0 里面的通道,然后启动 ADC 转换。在转换结束后,读取 ADC1_DR 里面的值。 通过以上几个步骤的设置,可以正常的使用 STM32 的 ADC1 来执行 AD 转换操作。 通过本次实验的学习,我们了解了STM32 ADC的使用,但这仅仅是STM32强大的ADC 功能的一小点应用。STM32 的ADC 在很多地方都可以用到,其ADC 的DMA 功能是很不错的,实验十五 DMA实验 一. 实验简介 直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。 二.实验目的 熟练掌握DMA编程,学会对EPC02的读写操作,学习双缓冲兵乓操作,理解互斥资源。提高编程能力。 三.实验内容 利用外部按键KEY0 来控制DMA 的传送,每按一次KEY0,DMA 就传送一次数据 到USART1,然后在串口调试助手观察进度等信息。LED0 还是用来做为程序运行的指示灯。 这里我们使用到的硬件资源如下: 1)按键KEY0。2)指示灯LED0。 3)使用串口调试助手观察数据 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、网络调试助手。 五.实验步骤 1编写主程序 2编译代码,使用JLINK或ISP下载到实验板,使用串口调试助手观察数据 3记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 伴随 LED0 的不停闪烁,提示程序在运行。我们打开串口调试助手,然后按KEY0,可以看到串口显示如下内容: 七.实验总结 本节利用 STM32 的 DMA 来实现串口数据传送,DMA通道的配置需要: 1)设置外设地址。 2)设置存储器地址。 3)设置传输数据量。 4)设置通道 4 的配置信息。 5)使能 DMA1 通道 4,启动传输。 通过以上 5 步设置,我们就可以启动一次 USART1 的 DMA 传输了。 DMA控制器对DMA请求判别优先级及屏蔽,向总线裁决逻辑提出总线请求。当CPU执行完当前总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知I/O接口开始DMA传输。 DMA控制器获得总线控制权后,CPU即刻挂起或只执行内部操作,由DMA控制器输出读写命令,直接控制RAM与I/O接口进行DMA传输。 在DMA控制器的控制下,在存储器和外部设备之间直接进行数据传送,在传送过中不需要中央处理器的参与。开始时需提供要传送的数据的起始位置和数据长度。 当完成规定的成批数据传送后,DMA控制器即释放总线控制权,并向I/O接口发出结束信号。当I/O接口收到结束信号后,一方面停 止I/O设备的工作,另一方面向CPU提出中断请求,使CPU从不介入的状态解脱,并执行一段检查本次DMA传输操作正确性的代码。最后,带着本次操作结果及状态继续执行原来的程序。 由此可见,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,使CPU的效率大为提高。 实验十六 I2C实验 一.实验简介 编程实现对使用I2C接口的EPC02芯片进行写和读操作。 二.实验目的 熟练掌握I2C编程,学会对EPC02的读写操作。 三.实验内容 编写I2C驱动程序,使用驱动程序初始化EPC02,判断设备正确性。 写256个0x5A到EPC02,读出并发送给串口,通过串口调试助手判别是否读到的都是0x5A.四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1参考教材I2C部分,编写I2C驱动程序。2编写主程序 3编译代码,使用JLINK或ISP下载到实验板 4记录实验过程,撰写实验报告 六.实验结果及测试 伴随 LED0 的不停闪烁,提示程序在运行。我们先按下KEY0,可以看到如下所示的内容,证明数据已经被写入到24C02了。 接着我们按KEY2,可以看我们刚刚写入的数据被显示出来了,如下图所示: 源代码: 七.实验总结 IIC是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。 IIC总线在传送数据过程中共有三种类型信号,它们分别是:开始信号、结束信号和应答信号。这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。程序在开机的时候会检测 24C02 是否存在,如果不存在则会在TFTLCD 模块上显示错误信息,同时LED0 慢闪。大家可以通过跳线帽把PC11 和PC12 短接就可以看到报错了。通过本次实验,我掌握了如何使用IIC写入与读出数据,学习了编写I2C驱动程序,使用驱动程序初始化EPC02,判断设备正确性,以及如何在助手上显示。 实验十七 SPI实验 一.实验简介 编程实现对SPI接口的W25Q64进行读写操作。 二.实验目的 熟练掌握SPI编程,学会对的W25Q64读写操作。 三.实验内容 1.2.3.4.5.编写SPI驱动程序 初始化SPI接口 读取SPIFLASH的ID,如果正确继续,否则报错 向SPIFALSH地址0x12AB00开始写一串字符,再读出比较判断是否与写入的一致 向SPIFALSH地址0x12AB00开始写连续256个字节的0x5A,然后读出并发送给串口,通过串口调试助手判别是否读到的都是0x5A.四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1参考SPI及SPI FLASH部分,编写SPI及SPI FLASH驱动程序(可参考书上代码)。2编写主程序 3编译代码,使用JLINK或ISP下载到实验板 4记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 伴随 LED0 的不停闪烁,提示程序在运行。我们先按下KEY0,可以看到如图13.17.4.2 所示的内容,证明数据已经被写入到W25X16了。 接着我们按KEY2,可以看我们刚刚写入的数据被显示出来了,如下图所示: 七.实验总结 SPI 接口主要应用在EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32 也有 SPI 接口。 SPI 的设置步骤: 1)配置相关引脚的复用功能,使能 SPI时钟。 2)设置 SPI 工作模式。 3)使能 SPI。 程序在开机的时候会检测 W25X16 是否存在,如果不存在则会在TFTLCD 模块上显示错误信息,同时LED0 慢闪。大家可以通过跳线帽把PA5 和PA6 短接就可以看到报错了。通过本实验,我掌握了编写SPI程序写入和读取FLASH的方法,掌握了对学会对的W25Q64读写操作。对STM32开发板有了进一步的了解。 实验二十一 红外遥控实验 一. 实验简介 编程实现通过在 ALIENTEK MiniSTM32 开发板上实现红外遥控器的控制。 二.实验目的 掌握编程实现红外遥控控制开发板的方法。 三.实验内容 1.编写红外遥控驱动程序 2.编写红外遥控程序代码 3.使用红外遥控控制开发板 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件。 五.实验步骤 4.编写红外遥控驱动程序 5.编写红外遥控程序代码 6.编译代码,使用JLINK或ISP下载到实验板 7.记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 使用串口调试助手观察数据 七.实验总结 红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。 通过本节实验,我学习到了如何编程使用红外遥控控制,在本程序中只是简单地输出一个数值,在以后的应用中可以实现更强大的功能,比如用红外远程输入控制开发板进行一些操作。对STM32有了进一步的认识。 实验二十二 DS18B20实验 一. 实验简介 一. 在ALIENTEK MiniSTM32 开发板上,通过 DS18B20 来读取环境温度值。 二.实验目的 巩固SPI编程。掌握使用感应器获取环境温度的方法。 三.实验内容 1.复位脉冲和应答脉冲 2.写时序 3.读时序 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件。 五.实验步骤 1.2.3.4.参考教材DS18B20编程部分,编写DS18B20驱动程序 编写主程序 编译代码,使用JLINK或ISP下载到实验板 记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 使用串口调试助手观察数据: 七.实验总结 DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器。 通过本次实验,我认识到STM32的强大,在开发板上可以添加其他感应器从而实现更强大的功能。添加了DS18B20后的开发板可以感应外界的温度,通过公式计算显示出来。 嵌入式系统及应用课 程设计报告 姓名:陈宥祎 班级:14级计算机01班 学号:1255010116 指导老师:黄卫红 按键输入实验 一.实验简介 在实验一的基础上,使用按键控制流水灯速度,及使用按键控制流水灯流水方向。 二.实验目的 熟练使用库函数操作GPIO,掌握中断配置和中断服务程序编写方法,掌握通过全局变量在中断服务程序和主程序间通信的方法。 三.实验内容 实现初始化GPIO,并配置中断,在中断服务程序中通过修改全局变量,达到控制流水灯速度及方向。 使用JLINK下载代码到目标板,查看运行结果,使用JLINK在线调试。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK、示波器。软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件。 五.实验步骤 1在实验1代码的基础上,编写中断初始化代码 2在主程序中声明全局变量,用于和中断服务程序通信,编写完成主程序 3编写中断服务程序 4编译代码,使用JLINK下载到实验板 5.单步调试 6记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 我们将通过MiniSTM32 板上载有的3个按钮,来控制板上的2个LED,其中KEY0控制LED0,按一次亮,再按一次,就灭。KEY1 控制LED1,效果同KEY0。KEY_2(KEY_UP),同时控制LED0 和LED1,按一次,他们的状态就翻转一次。 七.实验总结 通过本次实验,我学会了如何使用STM32 的IO 口作为输入用。TM32 的IO 口做输入使用的时候,是通过读取IDR 的内容来读取IO 口的状态的。这里需要注意的是 KEY0 和KEY1 是低电平有效的,而WK_UP 是高电平有效的,而且要确认WK_UP 按钮与DS18B20 的连接是否已经断开,要先断开,否则DS18B20 会干扰WK_UP按键!并且KEY0 和KEY1 连接在与JTAG 相关的IO 口上,所以在软件编写的时候要先禁用JTAG 功能,才能把这两个IO 口当成普通IO 口使用。 串口通信 一.实验简介 编写代码实现串口发送和接收,将通过串口发送来的数据回送回去。 二.实验目的 掌握STM32基本串口编程,进一步学习中断处理。 三.实验内容 编写主程序,初始化串口1,设置波特率为9600,无校验,数据位8位,停止位1位。编写中断服务程序代码实现将发送过来的数据回送。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK、示波器。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1编写串口初始化代码 2编写中断服务程序代码 3编译代码,使用JLINK或ISP下载到实验板 4记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 把代码下载到 MiniSTM32 开发板,可以看到板子上的LED0 开始闪烁,说明程序已经在跑了。接着我们打开串口调试助手,看到如下信息: 证明串口数据发送没问题。接着,我们在发送区输入上面的文字,输入完后按回车键。然后单击发送,可以得到如下结果: 七.实验总结 通过本次实验,我进一步了解了串口的使用,学会了通过串口发送和接收数据,将通过串 口发送来的数据回送回去。该实验的硬件配置不同于前两个实验,串口 1 与USB 串口默认是分开的,并没有在PCB上连接在一起,需要通过跳线帽来连接一下。这里我们把P4 的RXD 和TXD 用跳线帽与P3 的PA9 和PA10 连接起来。 外部中断 一.实验简介 STM32 的 IO 口在本章第一节有详细介绍,而外部中断在第二章也有详细的阐述。这里我们将介绍如何将这两者结合起来,实现外部中断输入。 二.实验目的 进一步掌握串口编程,进一步学习外部中断编程,提高编程能力。 三.实验内容 初始化IO口的输入,开启复用时钟,设置IO与中断的映射关系,从而开启与IO口相对应的线上中断事件,设置触发条件。配置中断分组(NVIC),并使能中断,编写中断服务函数。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK、示波器。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1.2.3.4.编写中断服务程序代码 使用ISP下载到实验板 测试运行结果 记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 打开串口助手。 七.实验总结 首先需要将IO设置为中断输入口: 1)初始化 IO 口为输入。 2)开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。 3)开启与该 IO口相对的线上中断/事件,设置触发条件。 4)配置中断分组(NVIC),并使能中断。 5)编写中断服务函数。 这一节,使用的是中断来检测按键,通过 WK_UP 按键实现按一次 LED0 和 LED 1 同时翻转,按 KEY0 翻转 LED0,按 KEY1 翻转 LED1。试验中外部中断函数不能进入的原因分析 : 1)GPIO或者AFIO的时钟没有开启。2)GPIO和配置的中断线路不匹配。3)中断触发方式和实际不相符合。 4)中断处理函数用库函数时,写错,经常可能出现数字和字母之间没有下划线。5)外部中断是沿触发,有可能不能检测到沿,比如 中断线是低电平(浮空输入),触发是下降沿触发,可能会出现一直是低电平,高电平的时候是一样的情况,电平持续为高电平。 6)没有用软件中断来触发外部中断,调用函数EXTI_GenerateSWInterrupt;,因为软件中断先于边沿中断处理。 独立看门狗实验 一. 实验简介 独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。 二.实验目的 通过编程,编写一个独立看门狗驱动程序 三.实验内容 启动 STM32 的独立看门狗,从而使能看门狗,在程序里面必须间隔一定时间喂狗,否则将导致程序复位。利用这一点,我们本章将通过一个 LED 灯来指示程序是否重启,来验证 STM32 的独立看门狗。 四.实验设备 硬件部分:PC计算机(宿主机)、亮点STM32实验板、JLINK。 软件部分:PC机WINDOWS系统、MDK KEIL软件、ISP软件、串口调试助手。 五.实验步骤 1.2.3.4.参考教材独立看门狗部分,编写独立看门狗驱动程序。建立和配置工程 编写代码 使用ISP下载到实验板 记录实验过程,撰写实验报告 六.实验结果及测试 源代码: 在配置看门狗后,看到LED0 不停的闪烁,如果WK_UP 按键按下,就喂狗,只要WK_UP 不停的按,看门狗就一直不会产生复位,保持LED0 的常亮,一旦超过看门狗定溢出时间(Tout)还没按,那么将会导致程序重启,这将导致LED0 熄灭一次。 七.实验总结 通过本次实验,我掌握了启动独立看门狗的步骤: 1)向 IWDG_KR 写入 0X5555。2)向 IWDG_KR 写入 0XAAAA。3)向 IWDG_KR 写入 0XCCCC。 通过上面 3个步骤,启动 STM32 的看门狗,从而使能看门狗,在程序里面就必须间隔一定时间喂狗,否则将导致程序复位。利用这一点,本章通过一个LED 灯来指示程序是否重启,来验证 STM32 的独立看门狗。在配置看门狗后,LED0 将常亮,如果 WK_UP 按键按下,就喂狗,只要 WK_UP 不停的按,看门狗就一直不会产生复位,保持 LED 0 的常亮,一旦超过看门狗溢出时间(Tout)还没按,那么将会导致程序重启,这将导致 LED 0 熄灭一次。第三篇:操作系统实验报告
第四篇:嵌入式实验报告
第五篇:嵌入式实验报告