




已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
51单片机操作系统开发中的问题与技巧附代码Top of FormBottom of Form引 言51系列单片机是美国Intel公司在1980年推出的高性能8位单片机,在我国的应用非常广泛。目前,在软件设计中需要软件工程师从底层做起,在系统软件设计方面需要做大量的重复性劳动。如果开发一套基于51系列单片机的操作系统,那么用户只需要编写各个任务的程序,不必同时将所有任务运行的各种情况记在心中,不但大大减少了程序编写的工作量,而且减少了出错的可能性。1 开发平台的选择和论证开发平台的选择至关重要,因为有时它不光影响进度、产品质量、可维护性等一般问题,还涉及到方案的可实现性。在本系统中,选择51系列单片机作为操作系统的运行平台有以下原因。首先,51系列单片机应用非常广泛,一大批性能优越的51兼容单片机相继推出。这里包括:低功耗、高速度和增强型的Philips公司的系列产品;完美地将Flash(非易失闪存技术)EEPROM与80C51内核结合起来的Atmel公司的系列产品;在抗干扰性能,电磁兼容和通信控制总线功能上独树一帜,其产品常用于工作环境恶劣场合的Siemens公司的系列产品以及一些其它公司的产品。既然产品如此丰富,性能如此优越,那么在处理多任务并且对实时性要求严格的系统设计中,为了充分挖掘单片机的潜能(尤其是在实时性方面),也是为了简化开发的过程,基于51系列单片机的实时操作系统的需求就十分强烈了。Keil公司的RTX51 Full就是一个基于51系列单片机的有实用价值的实时操作系统,但该操作系统是一个源码不公开的收费软件。其次,借助于Keil C51的集成开发环境,完全可以开发出适用于51系列单片机的操作系统代码。Keil C51软件提供丰富的库函数和功能强大的Windows界面集成开发调试工具。另外重要的一点,Keil C51生成的目标代码效率非常高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时,更能体现高级语言的优势。C编译器能产生可重入代码,而且用C语言可以打开和关闭中断。2 开发51单片机操作系统应注意的问题(1)操作系统软件的代码不能太长因为51系列单片机的系统硬件资源相对匮乏,如果操作系统的代码比应用程序的代码还大,甚至使得用户的应用程序要考虑给操作系统让出资源,这样的操作系统即使功能再完善,也不实用。现在流行的嵌入式操作系统就不能应用于51系列单片机,原因是代码太大。开发一个5000行的基于裸机的应用程序也就是占用78KB ROM空间,一个操作系统用掉了几十KB,占空间不算,实时性的优势恐怕也没了(执行这么多的指令要时间)。所以,COS的作者也不支持将他的代码移植到51系列单片机上,这也就不奇怪了。(2)操作系统不能占用太多的片内RAM空间51系列单片机只有128个或者256个字节的片内RAM空间,稍微不注意就用完了。如果操作系统把片内的RAM使用得所剩无几,那用户的应用程序用什么? 如果说用户的程序可以把变量定义在片外RAM中的话,那么系统的硬件堆栈放在哪? 众所周知,51系列单片机的硬件堆栈不能放在片外,所以要在51系列单片机上开发操作系统的话就要少用它的片内RAM。但是不用片内RAM是办不到的,因为操作系统也要传递参数,也要使用堆栈。C51单片机的C函数传递参数是通过寄存器和存储器的,不能通过堆栈。但是可以通过一些措施使得操作系统代码少用片内RAM。(3)解决好函数的重入问题开发实时占先式的操作系统,可重入函数是非用不可的。可重入函数可以被一个以上的任务调用,而不必担心数据被破坏。可重入函数任何时候都可以被中断,一段时间后又可以运行,而应用数据不会丢失。使得函数具有可重入性必须使得函数能够满足下列三个条件之一: 不使用共享资源; 在使用共享资源时关中断,使用完毕后再开中断; 在使用共享资源时申请信号量,使用完后释放信号量。这些条件在标准C中编程很容易实现,但是在Keil C51中就比较麻烦。因为标准C是把局部变量分配到用户堆栈中(动态分配),而Keil C51将局部变量分配到寄存器或内存固定地址(静态分配),并通过变量覆盖分析的方法,使多个函数的局部变量使用相同的内存地址以减少内存占用。在Keil C51中,如果局部变量分配在寄存器中还好些,如果局部变量分配在内存中就比较麻烦。(4)堆栈的分配问题占先式操作系统的主要任务就是进行任务的调度,通过对任务的实时调度来完成系统的功能。任务调度过程中,不可避免的发生任务对系统资源的抢占问题,因为系统中CPU只有一个,而每个任务都认为自己是CPU的绝对占用者,每一个任务都是一个死循环。任务间进行切换的依据就是各自的优先级,一个高优先级的任务可以通过任务调度函数或者中断退出函数等来中止正在运行的任务。被中断的任务只有自己的优先级在当前就绪任务表中最高时,才能从被中断处继续运行。这就需要为每个任务分配任务堆栈,来保存任务的环境变量。由于每个任务在不同时刻被中断时需要保存的环境变量数目不同,所以任务堆栈空间的分配问题也是一门学问。3 一些解决问题的技巧(1)片内RAM占用问题的解决任务堆栈最好不要放在片内,如果把任务堆栈放在片内的话,用户应用程序可使用的资源就非常有限,应用程序的功能也会受到限制。这就是为什么某些把任务堆栈放在片内的基于51系列单片机的实时操作系统只能用来做些演示实验,但并不实用。一个有实用价值的基于51系列单片机的实时操作系统必须在512字节以上的RAM环境中运行。随着集成技术的发展,现在已经出现了很多带有辅助RAM的51系列单片机,这类单片机把片外的RAM集成到芯片内,使用MOVX指令来访问这些RAM。如果用户不想通过三总线来扩展片外RAM的话,可以选用这种带有辅助RAM的单片机。此外,因为操作系统要用到一些全局变量,鉴于处理的速度问题又不想把它们全部的放在片外,那就可以根据这些全局变量应用的频繁程度来决定把哪些移到片外,哪些留在片内。别小看这几个字节的节约,在51系列单片机上效果会很明显。笔者认为在这种资源相对匮乏的单片机上,开发操作系统的最高境界应该是开发一个绿色的操作系统,用户在应用操作系统时可以用的系统资源应该和基于裸机编程差不多。(2)重入问题的解决应该尽量使有重入性要求的函数的参数传递通过寄存器来完成,这样可以用一般的方法来编写函数,使得函数具有重入性。如果实在是寄存器不够用的话,可以动用硬件堆栈来保存这些局部变量。(3)堆栈分配问题的解决鉴于各个任务对于任务堆栈大小的要求不同,即使同一个任务在不同的时刻被中断,它对堆栈大小的要求也不相同的情况,可以将任务堆栈多分配出一个字节,用来统计任务堆栈中有效数据的个数。单片机的片内RAM中,堆栈的栈底也做一个标志,当任务切换时,把当前任务放在堆栈中的环境变量从栈底到栈顶全部拷贝到任务的堆栈中,然后把将要运行任务的任务堆栈中的所有数据恢复到栈底标志开始的地方。任务堆栈和硬件堆栈之间的数据拷贝如图1所示。其中,Stack(i)和Stack(j)都是指针数组Stackmax_tasks中的元素,NUM=SP-StkStart,图1中所要进行的操作步骤是:将系统硬件堆栈中的内容放到当前任务的堆栈中;把将要运行的任务的堆栈内容移到系统的硬件堆栈中,并将硬件堆栈中的内容弹出到各个寄存器。这个过程就完成了任务的切换。#include #define MAX_TASKS 5typedef struct os_task_control_table unsigned char os_task_wait_tick; unsigned char os_task_stack_top; TCB;volatile unsigned char int_count;volatile unsigned char os_en_cr_count;#define enter_int() EA=0;int_count+;#define os_enter_critical() EA=0;os_en_cr_count+;#define os_exit_critical() if(os_en_cr_count=1)os_en_cr_count-;if(os_en_cr_count=0)EA=1;unsigned char code os_map_tbl = 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80;volatile unsigned char os_task_int_tbl;idata volatile TCB os_tcbMAX_TASKS;volatile unsigned char os_task_running_id;volatile unsigned char os_task_rdy_tbl;unsigned char idata os_task_stackMAX_TASKS20;void os_init(void);void os_task_create(unsigned char task_id ,unsigned int task_point,unsigned char stack_point);void os_delay(unsigned char ticks);void os_start(void);void os_task_switch(void);void exit_int(void);void os_init(void) EA = 0; ET2 = 1; T2CON = 0X00; T2MOD = 0X00; RCAP2H = 0x0D8; RCAP2L = 0x0F0; os_task_rdy_tbl = 0; os_task_int_tbl = 0xff; int_count = 0; os_en_cr_count = 0;void os_task_create(unsigned char task_id ,unsigned int task_point,unsigned char stack_point) os_enter_critical(); (unsigned char idata *)stack_point)0 = task_point; (unsigned char idata *)stack_point)1 = task_point8; os_tcbtask_id.os_task_stack_top = stack_point+14; os_task_rdy_tbl |= os_map_tbltask_id; os_tcbtask_id.os_task_wait_tick = 0; os_exit_critical();void os_delay(unsigned char ticks) os_enter_critical(); os_tcbos_task_running_id.os_task_wait_tick = ticks; os_task_rdy_tbl &= os_map_tblos_task_running_id; os_exit_critical(); os_task_switch();void os_start(void) os_task_running_id = 0; os_tcbos_task_running_id.os_task_stack_top -= 13; EA = 1; SP = os_tcbos_task_running_id.os_task_stack_top; TR2 = 1;void os_task_switch(void) unsigned char i; EA = 0; os_tcbos_task_running_id.os_task_stack_top = SP; os_task_int_tbl &= os_map_tblos_task_running_id; for(i=0; iMAX_TASKS; i+) if(os_task_rdy_tbl&os_map_tbli) break; os_task_running_id = i; SP = os_tcbos_task_running_id.os_task_stack_top; if(os_task_int_tbl&os_map_tblos_task_running_id) _asm POP 7 _asm POP 6 /恢复任务寄存器 _asm POP 5 _asm POP 4 _asm POP 3 _asm POP 2 _asm POP 1 _asm POP 0 _asm POP PSW _asm POP DPL _asm POP DPH _asm POP B _asm POP ACC EA = 1; _asm RETIvoid exit_int(void) unsigned char i; SP -= 2; if(-int_count = 0) os_tcbos_task_running_id.os_task_stack_top = SP; os_task_int_tbl |= os_map_tblos_task_running_id; for(i=0; iMAX_TASKS; i+) if(os_task_rdy_tbl&os_map_tbli) break; os_task_running_id = i; SP = os_tcbos_task_running_id.os_task_stack_top; if(os_task_int_tbl&os_map_tblos_task_running_id) _asm POP 7 _asm POP 6 /恢复任务寄存器 _asm POP 5 _asm POP 4 _asm POP 3 _asm POP 2 _asm POP 1 _asm POP 0 _asm POP PSW _asm POP DPL _asm POP DPH _asm POP B _asm POP ACC EA = 1; _asm RETI _asm POP 7 _asm POP 6 /恢复任务寄存器 _asm POP 5 _asm POP 4 _asm POP 3 _asm POP 2 _asm POP 1 _asm POP 0 _asm POP PSW _asm POP DPL _asm POP DPH _asm POP B _asm POP ACC EA=1; _asm RETIvoid timer2_isr(void) interrupt 5 unsigned char i; TF2=0; enter_int(); for(i=0; i0; x-) for(y=248; y0; y-);unsigned char code table= 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0;void task_1(void) unsigned char gw,sw,bw; while(1) bw = os_tcb2.os_task_wait_tick/100; sw = os_tcb2.os_task_wait_tick%100/10; gw = os_tcb2.os_task_wait_tick%10; P0 = tablebw; seg2=0; delay_ms(3); seg2=1;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年临沂郯城县教育系统部分事业单位公开招聘教师(13名)考前自测高频考点模拟试题及答案详解(名师系列)
- 疏水系统课件
- 2025江西南昌市都市城际公交有限公司招聘2名劳务派遣人员模拟试卷参考答案详解
- 畲族课件教学课件
- 2025河南郑州工商学院招聘67人模拟试卷及完整答案详解一套
- 2025年河北雄安新区新建片区学校公开选聘教职人员102名模拟试卷及答案详解(典优)
- 2025年甘肃陇南事业单位预计将于5月中旬发布模拟试卷含答案详解
- 硬笔书法考级宣传课件
- 文库发布:彩虹的课件
- 溺水安全急救知识培训课件
- 基于《中国高考评价体系》下的2023年高考物理命题趋势及复习备考策略
- LY/T 1145-1993松香包装桶
- GB/T 9114-2000突面带颈螺纹钢制管法兰
- 领导干部要学点哲学
- GB/T 17245-1998成年人人体质心
- 华为公司校园招聘个人简历标准版
- 学校结核病防控培训课件
- 【精品】部编版五年级上册道德与法治全册课时练(一课一练)(含答案)
- DBJ50T 043-2016 工程勘察规范
- 八年级美术下册《弘扬真善美》优质课件
- 《流行病学》第十六章 分子流行病学
评论
0/150
提交评论