51单片机最简单的多任务操作系统

合集下载

51—TinyOS51嵌入式操作系统微小内核

51—TinyOS51嵌入式操作系统微小内核
5.1.2 <setjmp.h>头文件
与中止函数about()和退出函数exit()相比,初看 起来,goto语句处理异常更可行,但是,goto语句 只能在函数内部跳转,即不能从一个函数直接跳转 到另一个函数。
为此,标准C函数库提供了setjmp()和longjmp() 函数,setjmp()函数相当于非局部标号,longjmp() 函数相当于goto的作用,从而解决了从一个函数直 接跳转到另一个函数的问题,即非局部跳转。头文 件<setjmp.h>申明了这些函数及同时所需的jmp_buf 数据类型。
如下图所示:
8
第5章 TinyOS51嵌入式操作系统 时间轮询调度为每个任务提供同份额的cpu执行
时间。由于纯粹的时间轮询调度不能满足实时性系统 要求,取而代之的是基于优先级抢占式调度扩充时间 轮询调度,即对同样优先级的任务使用时间片获得相 等的cpu分配时间,不同优先级的具有抢占权。
9
第5章 TinyOS51嵌入式操作系统
就绪状态 ;运行状态; 阻塞状态
10
第5章 TinyOS51嵌入式操作系统
就绪状态:当一个任务创立并准备运行时,内核将其放入 就绪状态。但不能运行,因为有一个更高优先级的任务在 执行,内核调度器根据优先级决定哪个任务先迁移到运行 状态,但处于就绪状态的任务不能直接迁移到阻塞状态。
运行状态:操作系统可让处于运行状态的低优先级任务暂 停运行,转而执行另一个处于就绪状态的高优先级任务, 这样正运行的任务就从运行状态迁移到了就绪状态。
SP
变化。
addr15~addr8
addr7~addr0
图 5.7
上下文信息 23
第5章 TinyOS51嵌入式操作系统

51单片机最小系统-(最新版)

51单片机最小系统-(最新版)

单片机最小系统,或者称为最小应用系统,是指用最少的元件组成的单片机可以工作的系统.对51系列单片机来说,最小系统一般应该包括:单片机、晶振电路、复位电路.下面给出一个51单片机的最小系统电路图.说明复位电路:由电容串联电阻构成,由图并结合"电容电压不能突变"的性质,可以知道,当系统一上电,RST脚将会出现高电平,并且,这个高电平持续的时间由电路的RC值来决定.典型的5 1单片机当RST脚的高电平持续两个机器周期以上就将复位,所以,适当组合RC的取值就可以保证可靠的复位.一般教科书推荐 C 取10u,R取.当然也有其他取法的,原则就是要让RC组合可以在RST脚上产生不少于2个机周期的高电平.至于如何具体定量计算,可以参考电路分析相关书籍.晶振电路:典型的晶振取(因为可以准确地得到9600波特率和19200波特率,用于有串口通讯的场合)/12MHz(产生精确的uS级时歇,方便定时操作)单片机:一片AT89S51/52或其他51系列兼容单片机特别注意:对于31脚(EA/Vpp),当接高电平时,单片机在复位后从内部ROM的0000H开始执行;当接低电平时,复位后直接从外部ROM的0000H开始执行.这一点是初学者容易忽略的.复位电路:一、复位电路的用途单片机复位电路就好比电脑的重启部分,当电脑在使用中出现死机,按下重启按钮电脑内部的程序从头开始执行。

单片机也一样,当单片机系统在运行中,受到环境干扰出现程序跑飞的时候,按下复位按钮内部的程序自动从头开始执行。

单片机复位电路如下图:二、复位电路的工作原理在书本上有介绍,51单片机要复位只需要在第9引脚接个高电平持续2US就可以实现,那这个过程是如何实现的呢?在单片机系统中,系统上电启动的时候复位一次,当按键按下的时候系统再次复位,如果释放后再按下,系统还会复位。

所以可以通过按键的断开和闭合在运行的系统中控制其复位。

开机的时候为什么为复位在电路图中,电容的的大小是10uF,电阻的大小是10k。

RTX51Tiny实时内核理解

RTX51Tiny实时内核理解

RTX51 Tiny 实时内核理解声明:以下来自网络整理而来并非本人作品,觉得挺容易懂所以放入博客以便后来学习者参考RTX51 Tiny中容易混淆的问题RTX51 Tiny是 Keil uVision中自带的一个小型嵌入式RTOS,具有小巧、速度快、系统开销小、使用方便等优点。

使用RTX51 Tiny能够提高系统的稳定性,优化程序的性能;而且它是为51单片机专门定制的,所以在51单片机上的运行效率比其它一些通用的RTOS性能也要好一些。

但是,由于RTX51 Tiny的相关资料和书籍比较少,大部分只是对程序自带帮助文件的简单翻译,很少进行深入探讨。

下面就RTX51 Tiny使用中经常遇到的一些问题进行探讨。

1 关于时间片的问题RTX51 Tiny使用的是无优先级时间片轮询法,每个任务使用相同大小的时间片,但是时间片是怎样确定的呢?RTX51 Tiny的配置参数(Conf_tny.a51文件中)中有INT_CLOCK和TIMESHARING两个参数。

这两个参数决定了每个任务使用时间片的大小:INT_CLOCK是时钟中断使用的周期数,也就是基本时间片;TIMESHARING是每个任务一次使用的时间片数目。

两者决定了一个任务一次使用的最大时间片。

如假设一个系统中INT_CLOCK设置为10000,即10ms,那么TIMESHARING=1时,一个任务使用的最大时间片是 10ms;TIMESHARING=2时,任务使用最大的时间片是20ms;TIMESHARING=5时,任务使用最大的时间片是50ms;当 TIMESHARING设置为0时,系统就不会进行自动任务切换了,这时需要用os_switch_task函数进行任务切换。

这部分功能是RTX51 Tiny 2.0中新增加的。

2 关于os_wait延时的问题os_wait 是RTX51 Tiny中的基本函数之一。

它的功能是将当前任务挂起来,等待一个启动信号(K_SIG)或超时信号(K_TMO)或周期信号(K_IVL)或者是它们之间的组合。

实时多任务操作系统在MCS-51单片机中的应用

实时多任务操作系统在MCS-51单片机中的应用
面上 已经存 在 很多 嵌入 式 操作 系 统 ,如 u O 、x r、 C S V W0k
) 22 R X 5 . T 一 1任 务状态
R X 5 Leabharlann y的 用 户 任 务 有 5种 状 态 , 表 1 示 。 T 一 1Tn 如 所 某 一 时 刻 用 户 任 务 处 在 某 个 状 态 , 一 定 条 件 下 , 务 状 在 任
1 引 言
文献标 识码 : A
文章编 号 :6 4 58 (0 0 0 — 10 0 17 — 7 7 2 1 )5 0 6 — 3
义:
传统 的单 片机程 序多 为单任 务 系统 .其业 务逻 辑顺 序安排 在主 函数 中 , 函数是 整个程 序 的人 1 一般 为死 主 : 3. 循 环 , 环过 程 中通 过调用 函数 未完 成相 应 的操作 . 循 而对
于 一 些 较 短 的 实 时 任 务 则 通 过 中 断 方 式 进 行 处 理 此 种 程 序 结 构 简 单 、 观 , 于 实 现 . 对 于 较 复 杂 的 应 用 此 直 易 但
vi tsn m (od t k B m o ak a evi)_a u d s n n 是任务 号 , ul 取值 为 O 1 。t k a 一 5 a nme是任 务的名称 。 s 下
运 行 状 态
2 RX 5 T 一 1简 介
R X一 1是 德 国 K i公 司 开 发 的 适 用 于 MC 一 1 T 5 el S5 单 片 机 的 实 时 多 任 务 操 作 系 统 . T 一 1 R X 5 ul R X 5 有 T 一 1F l 和 R X 1Tn 个 版 本 本 文 以 R X 5 iy为 例 介 绍 . T 5 iy两 T 一 1Tn 它

Keil_C51开发系统基本知识

Keil_C51开发系统基本知识

Keil_C51开发系统基本知识Keil C51开发系统基本知识1. 第一节系统概述Keil C51是美国Keil Software公司出品的51系列兼容单片机C 语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。

用过汇编语言后再使用C 来开发,体会更加深刻。

Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。

另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。

在开发大型软件时更能体现高级语言的优势。

下面详细介绍Keil C51开发系统各部分功能和使用。

2. 第二节 Keil C51单片机软件开发系统的整体结构C51工具包的整体结构,如图(1)所示,其中uVision与Ishell分别是C51 for Windows和for Dos的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程。

开发人员可用IDE本身或其它编辑器编辑C或汇编源文件。

然后分别由C51及A51编译器编译生成目标文件(.OBJ)。

目标文件可由LIB51创建生成库文件,也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS)。

ABS文件由OH51转换成标准的Hex文件,以供调试器dScope51或tScope51使用进行源代码级调试,也可由仿真器使用直接对目标板进行调试,也可以直接写入程序存贮器如EPROM中。

图(1) C51工具包整体结构图3. 第三节 Keil C51工具包的安装1. 1. C51 for Dos在Windows下直接运行软件包中DOS\C51DOS.exe然后选择安装目录即可。

完毕后欲使系统正常工作须进行以下操作(设C:\C51为安装目录):修改Autoexec.bat,加入path=C:\C51\BinSet C51LIB=C:\C51\LIBSet C51INC=C:\C51\INC然后运行Autoexec.bat2. 2. C51 for Windows的安装及注意事项:在Windows下运行软件包中WIN\Setup.exe,最好选择安装目录与C51 for Dos相同,这样设置最简单(设安装于C:\C51目录下)。

8051单片机实时操作系统RTX51 Tiny总结

8051单片机实时操作系统RTX51 Tiny总结

RTX51 Tiny介绍μVision是德国K eil公司开发的单片机IDE软件,最初主要用于8051系列单片机,RTX51是其自带的运行于8051系列单片机上的小型多任务实时操作系统,可用来设计具有实时性要求的多任务软件。

RTx51有2个版本:RTX51 Tiny和RTX51 Full。

RTX51 Tiny是RTX51 Full的子集。

RTX51 Tiny 自身仅占用900字节左右的程序存储空间,可以很容易地运行在没有外部扩展存储器的8051单片机系统上。

它完全集成在Keil C5l编译器中,具有运行速度快、对硬件要求不高、使用方便灵活等优点,因此越来越广泛地应用到单片机的软件开发中。

它可以在单个CPU上管理几个作业(任务),同时可以在没有扩展外部存储器的单片机系统上运行。

目前在8051系列单片机上使用多任务实时操作系统,RTX51 Tiny也就成为了首选。

////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ RTX51 TINY允许同时“准并行”地执行多个任务:各个任务并非持续运行,而是在预先设定的时间片(time slice)内执行。

CPU执行时间被划分为若干时间片,RTX51 TINY为每个任务分配一个时间片,在一个时间片内允许执行某个任务,然后RTX51 TINY切换到另一个就绪的任务并允许它在其规定的时间片内执行。

由于各个时间片非常短,通常只有几ms,因此各个任务看起来似乎就是被同时执行了。

基于KeilC51嵌入式系统多任务实现技术

基于KeilC51嵌入式系统多任务实现技术

就必须选择此启动程序 STARTUP.A51。
启动 文 件 STARTUP.A51 中 包 含 目 标 板 启 动 代 码 , 可 手 动
加入这个文件, 只要复位, 则该文件立即执行, 其功能包括:
1) 定义内部 RAM 大小、外部 RAM 大小、可重入堆栈位
2) 清除内部、外部或者以此页为单元的外部存储器
放到寄存器中, 可以被多个任务调用。但是如果局部变量太多,
Keil C51 在编 译 时仍 然 会 把 局 部 变 量 放 到 内 部 RAM 中 , 造 成
不同函数的局部变量覆盖。
在 Progect- >Option for Target- >C51 的 优 化 选 项 中 选 择 4
Register Variable。这样编译后的局部变量都尽量( 局部变量在 8
不同的任务不能调用同一个函数, 否则第二任务调用函数时会
修 改 第 一 个 任 务 调 用 此 函 数 后 的 局 部 变 量 。这 种 方 法 实 际 上 就
是把函数的局部变量变成了全局变量。
在 Keil C51 实现变量覆盖的方法如下:
在 Progect- >Option for Target- >BL51 Misc- >Overlay 里填入:
实例验证了其有效性和正确性。
关键词: 嵌入式操作系统; Keil C51; 局部变量; 全局变bstr act:Program based on Keil C51 embedded operation system, which divides whole program into multitask, can decrease the error
有一点不同, 放在内部 RAM 中 或 外部 RAM 中 的 局部 变 量 可 以 被 其 他 函 数 的 局 部 变 量 所 覆 盖 , 也 就 是 说 , 在 C51 下 的 所 有函数的局部变 量 都 放在 RAM 的 一 片共 同 的 区域 里 , 形 成局 部 函 数 变 量 区 。这 就 给 实 时 操 作 系 统 下 的 应 用 程 序 开 发 带 来 一

第9章多任务实时操作系统

第9章多任务实时操作系统
第9章 多任务实时操作系统 章 多任务实时操作系统RTX-51
RTX-51是Keil公司开发的一款应用于 是 公司开发的一款应用于80C51 公司开发的一款应用于 系列单片机的实时多任务操作系统。采用 系列单片机的实时多任务操作系统。采用RTX-51 可简化复杂的软件设计,缩短项目周期。RTX-51 可简化复杂的软件设计,缩短项目周期。 使得复杂的多任务程序设计变得简单, 使得复杂的多任务程序设计变得简单,因此在 80C51系列单片机嵌入式系统中应用很广泛。 系列单片机嵌入式系统中应用很广泛。 系列单片机嵌入式系统中应用很广泛
4.RTX-51实时多任务 . 实时多任务
RTX-51TINY允许“准并行”同时执行几个任务。各个任务并非持续运行, 允许“准并行”同时执行几个任务。各个任务并非持续运行, 允许 CPU执行时间被划分为若干时间片(time slice),每一个任务在预先定义 执行时间被划分为若干时间片( ),每一个任务在预先定义 执行时间被划分为若干时间片 ), 好的时间片内得以执行。时间到使正在执行的任务挂起, 好的时间片内得以执行。时间到使正在执行的任务挂起,并使另一个任务开 始执行。当使用RTX-51 TINY时,为每个任务建立独立的任务函数。 始执行。当使用 时 为每个任务建立独立的任务函数。 例如: 例如 void check_serial_io_task(void) _task_ 1
例如 void main (void){ while(1) /*永远重复 永远重复*/ 永远重复 { do_something(); /*执行 do_something“任务”*/ 任务” 执行 任务 } }
在这个例子里, 函数可以认为是一个单任务, 在这个例子里,do_something函数可以认为是一个单任务,由 函数可以认为是一个单任务 于仅有一个任务在执行, 于仅有一个任务在执行,所以没有必要进行多任务处理或使用多 任务操作系统。 任务操作系统。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

/*
51单片机最简单的多任务操作系统
其实只有个任务调度切换,把说它是OS有点牵强,但它对于一些简单的开发应用来说,简单也许就是最好的.尽情的扩展它吧.别忘了把你的成果分享给大家.
这是一个最简单的OS,一切以运行效率为重,经测试,切换一次任务仅个机器周期,也就是在标准(工作于M晶振)上uS.
而为速度作出的牺牲是,为了给每个任务都分配一个私有堆栈,而占用了较多的内存.作为补偿,多任务更容易安排程序逻辑,从而可以节省一些用于控制的变量.
任务槽越多,占用内存越多,但任务也越好安排,以实际需求合理安排任务数目.一般来说,4个已足够.况且可以拿一个槽出来作为活动槽,换入换入一些临时任务.
task_load(函数名,任务槽号)
装载任务
os_start(任务槽号)
启动任务表.参数必须指向一个装载了的任务,否则系统会崩溃.
task_switch()
切换到其它任务
.编写任务函数注意事项:
KEIL C编译器是假定用户使用单任务环境,所以在变量的使用上都未对多任务进行处理,编写任务时应注意变量覆盖和代码重入问题.
1.覆盖:编译器为了节省内存,会给两个没用调用关系的函数分配同一内存地址作为变量空间.这在单任务下是很合理的,但对于多任务来说,两个进程会互相干扰对方.
解决的方法是:凡作用域内会跨越task_switch()的变量,都使用static前辍,保证其地址空间分配时的唯一性.
2.重入:重入并不是多任务下独有的问题,在单任务时,函数递归同样会导致重入,即,一个函数的不同实例(或者叫作"复本")之间的变量覆盖问题.
解决的方法是:使用reentrant函数后辍(例如:void function1() reentrant{...}).当然,根本的办法还是避免重入,因为重入会带来巨大的目标代码量,并极大降低运行效率.
3.额外提醒一句,在本例中,任务函数必须为一个死循环.退出函数会导致系统崩溃.
.任务函数如果是用汇编写成或内嵌汇编,切换任务时应该注意什么问题?
由于KEIL C编译器在处理函数调用时的约定规则为"子函数有可能修改任务寄存器",因此编译器在调用前已释放所有寄存器,子函数无需考虑保护任何寄存器.
这对于写惯汇编的人来说有点不习惯: 汇编习惯于在子程序中保护寄存器.
请注意一条原则:凡是需要跨越task_switch()的寄存器,全部需要保护(例如入栈).根本解决办法还是,不要让寄存器跨越任务切换函数task_switch()
事实上这里要补充一下,正如前所说,由于编译器存在变量地址覆盖优化,因此凡是非静态变量都不得跨越
task_switch().
任务函数的书写:
void 函数名(void){//任务函数必须定义为无参数型
while(1){//任务函数不得返回,必须为死循环
//....这里写任务处理代码
task_switch();//每执行一段时间任务,就释放CPU一下,让别的任务有机会运行.
}
}
任务装载:
task_load(函数名,任务槽号)
装载函数的动作可发生在任意时候,但通常是在main()中.要注意的是,在本例中由于没考虑任务换出,
所以在执行os_start()前必须将所有任务槽装满.之后可以随意更换任务槽中的任务.
启动任务调度器:
os_start(任务槽号)
调用该宏后,将从参数指定的任务槽开始执行任务调度.本例为每切换一次任务需额外开销个机器周期,用于迁移堆栈.
*/
#include<reg51.h>
/*============================以下为任务管理器代码============================*/
#define MAX_TASKS 3//任务槽个数.在本例中并未考虑任务换入换出,所以实际运行的任务有多少个,就定义多少个任务槽,不可多定义或少定义
//任务的栈指针
unsigned char idata task_sp[MAX_TASKS];
#define MAX_TASK_DEP 12 //最大栈深.最低不得少于个,保守值为.
//预估方法:以为基数,每增加一层函数调用,加字节.如果其间可能发生中断,则还要再加上中断需要的栈深.
//减小栈深的方法:1.尽量少嵌套子程序2.调子程序前关中断.
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];//任务堆栈.
unsigned char task_id;//当前活动任务号
//任务切换函数(任务调度器)
void task_switch(){
task_sp[task_id] = SP;
if(++task_id == MAX_TASKS)
task_id = 0;
SP = task_sp[task_id];
}
//任务装入函数.将指定的函数(参数)装入指定(参数)的任务槽中.如果该槽中原来就有任务,则原任务丢失,但
系统本身不会发生错误.
void task_load(unsigned int fn, unsigned char tid){
task_sp[tid] = task_stack[tid] + 1;
task_stack[tid][0] = (unsigned int)fn & 0xff;
task_stack[tid][1] = (unsigned int)fn >> 8;
}
//从指定的任务开始运行任务调度.调用该宏后,将永不返回.
#define os_start(tid) {task_id = tid,SP = task_sp[tid];return;}
/*============================以下为测试代码============================*/
unsigned char stra[3], strb[3];//用于内存块复制测试的数组.
//测试任务:复制内存块.每复制一个字节释放CPU一次
void task1(){
//每复制一个字节释放CPU一次,控制循环的变量必须考虑覆盖
static unsigned char i;//如果将这个变量前的static去掉,会发生什么事?
i = 0;
while(1){//任务必须为死循环,不得退出函数,否则系统会崩溃
stra[i] = strb[i];
if(++i == sizeof(stra))
i = 0;
//变量i在这里跨越了task_switch(),因此它必须定义为静态(static),否则它将会被其它进程修改,因为在另一个进程里也会用到该变量所占用的地址.
task_switch();//释放CPU一会儿,让其它进程有机会运行.如果去掉该行,则别的进程永远不会被调用到
}
}
//测试任务:复制内存块.每复制一个字节释放CPU一次.
void task2(){
//每复制一个字节释放CPU一次,控制循环的变量必须考虑覆盖
static unsigned char i;//如果将这个变量前的static去掉,将会发生覆盖问题.task1()和task2()会被编译器分配到同一个内存地址上,当两个任务同时运行时,i的值就会被两个任务改来改去
i = 0;
while(1){//任务必须为死循环,不得退出函数,否则系统会崩溃
stra[i] = strb[i];
if(++i == sizeof(stra))
i = 0;
//变量i在这里跨越了task_switch(),因此它必须定义为静态(static),否则它将会被其它进程修改,因为在另一个进程里也会用到该变量所占用的地址.
task_switch();//释放CPU一会儿,让其它进程有机会运行.如果去掉该行,则别的进程永远不会被调
用到
}
}
//测试任务:复制内存块.复制完所有字节后释放CPU一次.
void task3(){
//复制全部字节后才释放CPU,控制循环的变量不须考虑覆盖
unsigned char i;//这个变量前不需要加static,因为在它的作用域内并没有释放过CPU
while(1){//任务必须为死循环,不得退出函数,否则系统会崩溃
i = sizeof(stra);
do{
stra[i-1] = strb[i-1];
}while(--i);
//变量i在这里已完成它的使命,所以无需定义为静态.你甚至可以定义为寄存器型(regiter)
task_switch();//释放CPU一会儿,让其它进程有机会运行.如果去掉该行,则别的进程永远不会被调用到
}
}
void main(){
//在这个示例里并没有考虑任务的换入换出,所以任务槽必须全部用完,否则系统会崩溃.
//这里装载了三个任务,因此在定义MAX_TASKS时也必须定义为
task_load(task1, 0);//将task1函数装入号槽
task_load(task2, 1);//将task2函数装入号槽
task_load(task3, 2);//将task3函数装入号槽
os_start(0);//启动任务调度,并从号槽开始运行.参数改为,则首先运行号槽.
//调用该宏后,程序流将永不再返回main(),也就是说,该语句行之后的所有语句都不被执行到.
}。

相关文档
最新文档