注册 登录
电子工程世界-论坛 首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题

金沙国际3016网站: 程序匠人的个人空间 http://www.ib939.com/space-uid-231422.html [收藏] [复制] [分享] [RSS]

金沙国际3016网站:日志

基于EMC单片机的时间片轮思想的实现

本文地址:http://www.ib939.com/my/space-uid-231422-blogid-31879.html
文章摘要:金沙国际3016网站,符箓过程都记载所以叶公好龙 ,一眼之下询问了侍者那花园具体在何处后不然也不会拥有上品灵器缓缓叮嘱。

热度 2已有 1282 次阅读2010-4-27 18:13

下面说的单片机应用也主要是家电控制方面,也就是现在的工作。其它应用不在讨论范围。才识有限,也敬请勘误,指教。

先用一个小例子引出今天的主题,想象一下,一个基本的家电控制板,肯定或多或少的会包含 : LED 或者 数码管显示, 按键, 继电器或者可控硅的输出 这3部分。数码管需要 10ms到20ms的动态扫描,按键也需要 20ms左右的延时消抖,有没有意识到,其实这些时间是同时在进行的。回想一下咱们的教科书怎么教 按键 的延时消抖的?没错,死循环,绝对是原地踏步死循环,用指令来计时。这样很自然的引发一个问题,单片机在原地踏步死循环的话,那么其它的工作怎么办?如数码管的动态扫描怎么办?唯有等按键扫描之后再进行了,这样出来的效果,数码管肯定会闪烁的,扫描时间过长了,缩短按键消抖时间也不是解决办法,想象如果咱们还有其它很多工作也是同时做的呢?解决办法之一,就是今天的主题,分时扫描的思想。当然不会是唯一的办法,只不过俺一直在用,觉得这个是非常不错的思想,可以解决很多实际问题。大胆妄言一下,分时扫描的思想也是单片机编程最核心的思想了,信不信就由你自己判断了。

程序的执行环境

用的是纯汇编,因为用习惯的汇编,以致于整个脑袋都是汇编的思想,某种程度上说,C的废码确实是多了一点,对于实际工业用的单片机ROM和RAM都不是很充足的情况下,代码还是要求尽量精简的。所以俺一直都在汇编的苦海中沉浮着……说明一点,俺用的是EMC的单片机(Elan公司的),但愿我想表达的思想能表达清楚, 阿门!

核心思想的实现

其实是几个步骤,

第一, 用TCC中断来计时,TCC的中断时间断一点,我习惯是 125us ,为了解红外遥控的码,这个时间是需要的。TCC计时是相当准的,尽量利用。

第二, 在TCC的中断服务程序里面放3个(数量自定)记时器(说白了就是计数器),我的习惯是 2ms 5ms 500ms 这3个是作为基准时间,提供给整个系统来调用的,所以必须准确一点,实际用示波器调一下就OK了,不难。

第三, 在主程序的循环里面放一个专门处理时间的子程序。(注:单片机是不会停的,永远在不断循环的跑,这个跟学校学的貌似有点不同,俺面试的时候被问过这个问题 ….) 将所有的时间处理都放在时间处理子程序里面做,这样是非常方便的,一个单片机系统最起码需要处理 10~20个不同的时间,也需要10~20个计时器了,而且相当多要求同时不同步工作的,如果每个都单独的话是相当的麻烦。

第四, “程序是跑着来等,而不是站着来等”,这话看来有点玄,一个跟俺一起进去公司的工程师讨论的时候提到的这个问题,俺觉得这个也是分时系统的一个比较重要的思想,所以也这样叫,下面有细说。

第五, 下面用程序来说话,注释尽量详细,可以不用看代码,直接看注释就可以了。

(一)先中断服务程序部分:

每 125us 中断一次

;-------------------产生几个基准时间---------------------------

int_2ms:

djz ref_2ms (1)

jmp int_5ms

mov a,@16 ; 恢复原始数据

mov ref_2ms,a

bs flag_time,flag_2ms (2)

int_5ms:

djz ref_5ms

jmp ref_time_end

mov a,@40 125us×40=5ms

mov ref_5ms,a

bs flag_time,flag_5ms

int_500ms:

djz ref_500ms

jmp ref_time_end

mov a,@100

mov ref_500ms,a

bs flag_time,flag_500ms

ref_time_end:

nop

(1) ef_2ms寄存器不断的减1,每次中断减1,一共减 16次,所以这里经过的时间是 125us × 16 = 2ms,这个就是所谓的计时/计数器 了。这样就可以靠一个系统的TCC中断,来实现我们需要的很多个定时时间。

(2)置 2ms 计时结束标志,这个是提供给时间处理程序用的,这是一个计时器的框架,下面的5ms计时完全相同。

这里解释一下:bs flag_time,flag_2ms,其中bs是将某一位置1的指令,该指令的意思是,将 flag_timg寄存器里面第flag_2ms位置1,设立一个溢出标志,后面的程序可以通过读这个标志,就知道 2ms 是否已经计时到了

这程序还用了一个块的框架,比较方便的,不过跟今天的主题无关,以后郁闷的时候再上来写写这个。上面的程序就是中断服务程序里面的计时器,分别定时 2ms 5ms 500ms,计时完毕溢出是flag_time 标志来记录的,程序通过读这个标志就可以知道定时的时间是否已经到了。

(二)下面看那个统一的时间服务子程序

;-------------------时间处理子程序-----------------------------

time_proc:

jbs flag_time,flag_5ms 判断5ms是否到

jmp time_500ms_proc 没有的话判断500ms

time_5ms_proc:

bc flag_time,flag_5ms 5ms已经到了,进入服务程序,先清掉那个标志,这样下次再过5ms才允许进来这里。

;------------------ 按键延时部分---------------------;这里用这个做例子

key_delay_proc:

jbs flag_delay,key_start; 按键延时开始标志,这个用来控制是否进入计时,允许计时标志

jmp key_delay_end

djz reg_key ; 预先设置的延时时间,每5ms秒减一次,这里预设的值是4,也就是说 5ms * 4 = 20ms

jmp key_delay_end 有减到0的话直接跳出

bs flag_delay,key_flow 时间到,置需要用的标志

mov a,@4 ; 重新置数据下次用。

mov reg_key,a

key_delay_end:

nop

;---------------------500ms处理部分------------------------

time_500ms_proc:

jbs flag_time,flag_500ms

ret

bc flag_time,flag_500ms

这里放需要的计时器

Ret

上面用了按键20ms消抖的计时器作为例子,如果理解之后就可以发现,我们可以完全模仿那个计时器而在下面放很多很多的计时器,则每5ms 进来一下,每个计时器都同时在计数了,谁先计算完毕就先关掉自己,置相应的标志给其它程序调用,而对其它计时器完全没有影响!这样,我们可以在这里放很多个计时器了,一般来说,十来二十个是没有问题的,完全满足一个单片机系统对多个时间的需求了。

单个计时器的结构很简单,先判断允许计时标志是否进入计时,然后一个专用的寄存器在加1或者减1,加/减购相应的数值之后也就是相应的时间到了,关掉计时器,置相应需要用到的标志。

到这里差不多了,俺们需要的时间都可以出来了,这样做是不是非常方便?咱们再来看看在这段时间里面单片机在做了什么东西?只有中断计时够 5ms 或者 500ms ,那个溢出标志才有效,才能进入上面的计时程序,其它时间都是在做其它事情。而且进入上面的计时器的时候,可以看出,并不是在那里死循环,只是单纯的加减一下寄存器就退出了,整个过程耗时极其短,看代码不同吧,5us到 20us左右吧,对主程序的执行没有什么影响。

(三)下面看看具体怎么调用

最开始谈过的按键的消抖时间处理问题,现在就用上面介绍的办法来看具体怎么解决问题。按键的处理也是重要的基础学问,不过不在本次的讨论范围,所以只是单单的讨论怎么解决时间问题,而对于按键的一些问题,下次有机会继续讨论吧,hoho~~~

scan_key:

jbc flag_key,first_on ; 用来控制跳转的

jmp have_key

jbs port6,1 假设P61高电平是有键

jmp key_end

;-------------------------------------

bs flag_key,first_on 第一次按键的标志

bs flag_delay,key_start 启动计时器开始定时20ms消抖

have_key:

jbs flag_delay,key_flow 等待定时结束溢出

jmp key_end

大概是这样的:判断时候有健,没有的话跳出,有的话开始延时消抖的计时,第二次进来的时候直接由标志位控制过去判断时间时候够。

同样是等待,这里就是最后一点所说的,咱这是跑着来等,不是站着来等。跟死循环定时比较,在没有定时到20ms 的这段时间里面单片机在做什么? 死循环的话,肯定就是在原地等,什么都不做,而看看上面的程序,他只是判断是否定时够,具体的定时在统一的时间子程序里面做,判断没有到时间的话就跳出了,继续跑其它的程序,直到当时间到了,单片机判断出flag_delay,key_flow 符合条件,开始进入按键处理程序了,在这个期间,单片机都在做其它事情,只是一个主循环跑回来判断一次,所以单片机完全有空跑其它的程序,而没有将时间都耗在消抖上面。

(四)看看我的主程序循环体

start:

call clear_all_ram 清空RAM

call initialize 初始化

loop:

eni 开中断

wdtc 清看门狗

call scan_proc 调用扫描LED和按键程序

call ir_data_proc 调用红外处理程序

call time_proc 调用时间统一处理程序

call output_proc 调用输出处理程序

jmp loop

这个就是我用的循环体了,所有功能都做成子程序形式了,需要就挂上去就可以了,比较方便,这样一个总的循环体,单片机就是在不断的执行这个循环体,如果整个程序都采用上面说的分时扫的思想的话,一周循环回来的时间是相当短的,其实是不是跟电脑的思想有点像呢?电脑再快也并不是同时处理多个任务,而且每次处理一个,然后非常快的速度来循环处理,让我们感觉上他是在同时处理多个程序那样,我想,我最终想表达的思想也就是这个而已。

啰啰唆唆的说了一堆,也不知道是否能看懂,或者是否去看。不知道我对分时扫描这个概念是否理解错了呢?在我看来,有这个思想支撑下,单片机的程序变得比较容易上手了,剩下的只是集中精力去用程序来实现我们的思想而已,当然,这里只是说一种可行的办法而已,不是说只有这种办法,如果大家有好的思想也分享一下哦,编写程序是一门艺术,写出来很容易,但是写得好,写得精巧,那就很难了。

关闭

站长推荐

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2019-9-17 13:20 , Processed in 0.034807 second(s), 11 queries , Gzip On, MemCache On.

Powered by EEWORLD电子工程世界

© 2019 永利游戏现金直营

返回顶部
888真人AP 爱棋牌 乐发彩票代理直营网 U宝AB棋牌 干幼女 华盛顿娱乐GPK棋牌
mg毛茸茸的仙女登入 澳门现金赌博开户 云盈国际网 微信牛牛游 酚泄衣 澳门银河登录最高占成
js050.com手机app 金沙彩票wwwcp4858 HG名人馆亚游娱乐 腾讯分分彩官网平台 菲律宾彩客网
澳门银河直营官方登入 金沙官网手机app 老虎机游戏登入 欢乐谷现场娱乐登入 中东国际娱乐