tag 标签: 微系统

相关博文
  • 热度 18
    2016-2-16 16:39
    1148 次阅读|
    2 个评论
    首先我们来了解下什么是msOS。 操作系统( Operating System)简称OS,而msOS则是一种名叫ms的操作系统,相应的还有Linux、 uClinux 、WinCE、PalmOS、Symbian、 eCos 、uCOS-II、 VxWorks 、pSOS、Nucleus、ThreadX 、Rtems 、QNX、INTEGRITY、OSE、C Executive。msOS是由王绍伟从ucOS 中精简出来的,它基于C语言,采用C#的编程风格,遵循高效率、低耦合思想。 平时我们编程往往是一个 main 函数,里面有一个 while(1)大循环,很多功能比如按键、IO 访问等都放在这儿处理,此外还有一些中断的处理功能,这类最原始的程序结构通俗的讲叫裸奔,学术名词叫前后台软件架构。中断在前,大循环处理在后。 不得不说基于中断的前后台结构实时性较好,而且简单易用,但当函数有些地方需要延时的程序段时,在延时期间内CPU处于空转状态,不可避免的造成了CPU资源浪费。为解决这一问题,嵌入式编程引入了系统节拍、消息机制、任务切换等新元素。 所谓的系统节拍,就是开一个定时器,设置每隔一段时间发生一次中断,这段时间就叫系统节拍。系统节拍的长短根据实际情况而定,我们这次所学习的msOS定的节拍是10ms,也即每过10ms发生一次中断,在中断程序里面执行一些例行操作,比如键盘扫描、运行一次实时性要求不是很强、执行周期较短的外接设备。 当在系统节拍发生期间检测到有效的新消息时,OS将消息类型以及消息数据抛入消息队列,等待执行。基于51内核的msOS的消息队列最多可存放四个消息,且不支持多任务切换,只能一个一个的读取队列消息,执行完一个任务后方可执行下一任务,详细的消息机制介绍请参看上传的学习文档。   MS3 程序流程图:   下面我们来根据程序进一步学习。 首先我们来看下main函数: void main(void)  //main函数 {     ushort idata messageData;     byte idata type;  //type :消息的种类     byte idata value; //value : 消息数据       Initialize();     //系统及相关设备初始化       while(true)     {         messageData = PendMessageQueue(); /*等待消息,当消息队列为空时,会一直停留在PendMessageQueue()函数中,此时每过10ms发生一次中断,程序跳转到中断服务子程序中,当从键盘中检测到有效的新消息时,会把消息类型(KeyMessageType-按键消息)和消息数据(即检测到的按键值)抛入消息队列中,消息队列不再为空,退出 PendMessageQueue()函数,在大循环中会根据消息的消息类型对消息数据进行相应的处理 */           type = GetMessageType(messageData);   //获取消息类型         value = GetMessageData(messageData);  //获取消息数据         switch(type)                           {           case KeyMessageType:    //按键类型消息            #if 1     //默认函数指针方式处理                 (*MmiFunction)(value);        //函数指针处理方式            #else                 KeyProcess(value);            //状态机处理方式            #endif                 break;            #if 1           case UsartMessageType:            //串口消息类型                 UsartProcess(value);                 break;            #endif             //请填充消息及处理函数           default:                //软件定时器处理               Function(messageData);               break;         }     } }   我们再来看看系统节拍到来时要执行的服务子程序: void SystemTickInterruptHandler(void) interrupt 5   /*开T2定时器,用 {          STC12C5A60S2芯片的同学注意,这款单片机没有T2定时器,可改用STC89C52,不想换芯片的可改用定时器0,定时器1已用做串口的波特率发生器*/     ET2 = 0;    //进入中断先关掉T2定时器     TF2 = 0;    //相应标志位清零   KeySystemTickService();         /*按键例行服务程序。按键例行程序其中有效的按键值是在发生两次系统节拍后得到的。平常我们在第一次按键的时候会有个10ms的消抖时间,消抖后再确定这次按键是否有效,最终得到按键值。而在这里,当第一次检测到按键时会保留当前按键值,在第二次系统节拍到来时将第二次得到的按键值与第一次得到的按键值进行比对,判断有效后才会将这个消息抛入消息队列*/     RtcSystemTickService();         //时钟例行服务程序    TimerSystemTickService();       /*软件定时器例行服务程序,软件定时器只要求大家看懂其流程,具体怎样运用先不予考虑*/       /*例行程序,使用者可根据需要添加*/       ET2 = 1;    //打开T2定时器 }   在进入按键例行服务程序前我们先看下 按键扫描 函数: static byte ScanPin(void) /*  4*4矩阵按键扫描函数,static用来声明这是{       一个内部函数,只能由当前的.c文件调用,其他.C文件里不能调用                  该函数*/       byte scanValue;   //此变量用于保存这次扫描后得到的按键值         P1 = 0x0F;                      //P17~P14置低     Delay(1);                       //延时,延时极短,用于电平稳定     scanValue = P1;                 //读取低4位按键值         P1 = 0xF0;                      //P17~P14置低     Delay(1);                       //延时,等待电平稳定     scanValue = scanValue | P1 ;    //读取高四位按键值并与低四位合并     /*在裸奔程序中,我们通过循环将I/O口的高四位/低四位中的一位电位置低,然后检测低四位/高四位是否有变化,有变化是先消抖10ms,再确认按键是否有效,整个过程给我们的感觉就是一次过。而在这里,是第一次检测到I/O口的某一位有变化时,先保存该值,然后退出中断,返回大循环,在下一次系统节拍到来时,将这次的按键值与第一次的比对,最后得到有效按键值。也就是本来用于消抖的10ms现在用来执行其他操作,这样就避免了原来消抖CPU空转的情况*/         return(scanValue);    //得到的按键值返回给此函数的调用者并保存 } 运行上述函数一次便能得到一个按键值,当两次按键值相等时,按键值有效。下面是按键例行程序: void KeySystemTickService(void) {     byte scanValue;       scanValue = ScanPin();    //调用按键扫描函数   if (scanValue == invalid)      /*判断是否释放按键,变量invalid =     {                       0xff,只有按键释放方满足条件执行以下程序*/         if (DoubleHitCounter)      //防止双击计数器         {             DoubleHitCounter--;             ScanCounter = 0;             ScanValueSave = invalid;             return;         }                 if (ScanValueSave == invalid)    //判断按键值是否有效         {             ScanCounter = 0;             return;         }                     if (ScanCounter == LongInterval)        /*判断为长按键,发送按键消息,分长按键和短按键方便矩阵键盘的复用*/        {              PostMessage(KeyMessageType, RemapLongKey(ScanValueSave));        }         else if (ScanCounter ShortInterval)   //判断为短按键,发送短按键消息         {             PostMessage(KeyMessageType, RemapKey(ScanValueSave));         }         ScanCounter = 0;                                ScanValueSave = invalid;         DoubleHitCounter = DoubleHitInterval;   //设定防止双击计数值     }     else     //有按键动作时执行以下程序     {         ScanCounter++;             if (ScanCounter == 1)                   //存储第一次按键值         {             ScanValueSave = scanValue;         }         else if (ScanCounter == 2)                     {             if (scanValue != ScanValueSave) /*判断前后两次按键值是否相             {                                                  等*/                 ScanValueSave = invalid;                 ScanCounter = 0;             }         }         else if (ScanCounter = LongInterval)   //防止计数值溢出循环         {             ScanCounter = LongInterval;         }     } }   我们再来走一遍流程:    首先是系统设备(串口、图形交互界面、系统时钟、消息队列、系统节拍)的初始化,然后进入大循环,在大循环里面,程序会先判断消息队列里是否有消息,若消息队列为空会在此等待,直至有消息抛入,当有消息抛入时,程序会根据取出的消息类型对消息数据进行相应的处理,在处理时,可能需要的时间比较长,而在此期间,若系统节拍到来,则暂停当前任务,进入中断服务子程序也即系统节拍服务,若此时有新的消息抛入,退出中断,回到主函数的时候,会先把未完成的任务完成,然后把读取消息队列,执行新任务,这是主函数部分。在系统节拍服务里面(软件定时器例行、时钟例行服务程序暂不讨论),通过扫描键盘等设备来确认是否有新消息,当检测到有效的消息时将消息抛入消息队列,消息队列是连接前台(中断)和后台(主函数)的桥梁。    msOS是一个比较简单的微系统,它算不上真正的实时系统(RTOS),真正的RTOS是支持多任务切换的,并且可以通过识别任务的优先级,优先执行级别高的任务。当有新的级别较高的任务时,系统会把当前未完成的任务挂起,相应的数据入栈保存,新任务执行完之后再继续执行该任务。当然这只是其中的一点,有兴趣的可以查阅相关资料进行学习。
  • 热度 15
    2014-6-10 11:22
    1062 次阅读|
    1 个评论
    原文链接:http://user.qzone.qq.com/26033613/blog/1402282935?ptlang=2052 嵌入式微系统msOS成型记之一:何为嵌入式微系统   嵌入式微系统,顾名思义就是嵌入式微型操作系统,然而操作系统一词在嵌入式行业里往往专指uC/OS之类的带任务切换的系统,所以为了有别于这个专用名词,往往用开发平台一词来代替,所以嵌入式微系统更准确的名字为嵌入式微型开发平台。 大家肯定会问,uC/OS这样的嵌入式操作系统跟嵌入式微系统到底有什么区别,那么我们就要从项目需求开始说起。 某个公司需要在嵌入式芯片(MCU51或者STM32)上开发一个控制项目,涉及LCD界面、多种不同接口速度的外设、多种不同速度的业务逻辑控制,下图为常见的一种工业自动化项目需求。        作为项目负责人,首先要分析清晰项目需求,假设这个项目有点复杂,涉及多路采样及多路PWM输出,所以选择STM32之类的高性能处理器,之后再考虑软件设计。 这个项目设计到多路输入传感器及多路输出,有高速的业务逻辑控制,也有低速的菜单界面,为了把低速的菜单界面与高速的业务逻辑分开独立编程,所以引入嵌入式操作系统,比如uC/OS,会方便程序设计。 uC/OS除了任务切换功能等有限的功能外,没有别的,所以其它的东西还是需要我们自己添加,菜单界面就是一个。界面编程里面,简单的界面用状态机还比较容易编程,但若涉及到稍微复杂一点的界面,传统的状态机编程思想就完全不适合了,代码很难维护修改,为了提高可维护性,需要引入一个标准的菜单界面编程库(GUI),虽然现在网上也有不少,但适合自己的却很难找,往往需要自己编写一套菜单界面库,这个工作量很大,难度也很难,最后往往退回到传统状态机菜单编程方式。 其它的硬件相关的设备驱动库,都需要自己来完成,比如按键、串口、步进驱动等等。若这个项目需要多人协同开发、长期维护,则还需要制定架构标准,一些接口规范,命名标准,而这么多的要求,对于大部分的小、微型企业的嵌入式项目负责人来说,要求太高了。所以最后这个项目负责人,往往自己一个人埋头苦干,什么标准什么规范都没有,经过较长的一段时间开发加上后期的修修补补,项目勉强的交差了。然而当这个负责人离职的时候,面临着无人接手的窘境。 我们再看消费类电子产品的开发模式,以MTK6225功能手机为例,RTOS采用Nucleus,菜单界面软件库采用PlutoMMI,此外还需要多媒体、文件系统,电话本、短消息等中间件,之后是各种硬件设备驱动,整个软件架构类似ARM公司提倡的CMSIS架构。   MTK提供了整套硬件参考设计、PCB设计、生产流程、测试流程,软件开发标准。客户通过不长的时间培训即可掌握手机的开发设计,一般10来人的手机设计公司,在具有一定的手机设计经验的基础上,只需要2、3个月就可以设计出一款MTK提供的参考手机,之后公司基于这个参考手机做硬件上的机型改进及软件上的界面调整即可。到了Android时代更是简单了,因为Android软件属于通用软件,所以软件更是不需要培训了。 其他消费类电子,比如以前的VCD、DVD、MP3、MP4等等,都采用类似的方式,只有采用这种方式,源头厂家才可以快速的切入市场,并且可以同时管理、维护很多下游客户,比如MTK的下游山寨手机公司上千家,大的手机厂家也有近百家之多。因为采用了标准的设计模版,应用开发、客户维护人员都不是很多,尤其是维护人员,大大降低,获得高额的利润。而因为采用标准通用的软件架构平台,迅速的培养了大量的通用手机软件人员,而这些软件人员都可以在各个手机公司立即干活,不存在更换一个公司之后还需要培训的问题,这样下游厂家也不需要担心人才流动引起的工作交接问题。   从以上例子可以看到,通用标准化的开发设计,带来的好处是巨大的:提高了开发效率、缩短了开发周期、便于产品长期维护,容纳更多的下游客户。 /********************************************/ 本文为连载性质,每周一篇,总计十二篇,应与非网邀请撰写,首发于与非网。 msOS到今天已经完善,也有大量的实际使用例子,比如PID算法库、步进驱动库及扩展大屏幕串口屏等,非常适合于工业场合,形成了一个控制体系。很多网友基于msOS应用于自己的项目中了。
相关资源