掌握前三通过掌握前三节的内容来解决很多问题,但我们会发现仍然存在很多问题。例如,在模拟单总线时,我们需要准确调整时间,我们使用空循环来实现时间延迟。我们不知道一个特定的循环会延迟多久。我们常用的方法是反复调整:感觉时间短,循环次数大写,感觉时间长,循环次数减少..感觉实际上是不可靠的在调节参数上花费了很多精力,把宝贵的计算机操作能力放在空循环上不是浪费吗?计算机有时间做点别的,系统的运行速度不是更快吗?计算机有时间做其他事情,系统运行速度不是更快吗?此外,让我们看看键盘扫描功能,程序一次又一次地检查一些端口,看看是否有信号变化来判断是否有按钮,但实际上我们的按钮数量非常有限,计算机把他们的精力放在检查端口上,这也导致了系统效率的下降!你现在发现了这个问题,计算机科学家也发现了这个问题。他们的解决方案是在所有计算机系统中必须提供的设备---,并提供一种机制---。
1.定时计数器
所谓定时计数器实际上就是数字电路中学习过的计数器:每当输入一个脉冲上,计数器中的值就加1(也有是减1的,加1的叫加法计数器,减1的叫减法计数器)。如果输入的脉冲是一个周期性的信号,也就是说,两个信号之间的间隔(时间)是固定的,那么只要我们知道有多少信号从开始到现在连接到计数器,我们就知道需要多长时间。它是一个定时计数器,其本质是计数器。当然,我们可以计算一个信号输入了多少脉冲。定时计数器的主要功能是定时。更准确地说,它主要使用时钟(多少时间)和闹时功能(在一定时间内提醒)。
要知道时间,首先要考虑的是周期性信号从何而来?什么是时钟源?我们通常考虑从系统晶体振动引入的振荡信号,所有系统必须有晶体振动(?),晶体振动为系统中的所有设备提供了统一的时间信号。计算机系统的时钟系统越来越复杂,甚至有不止一个时钟源:系统的核心(CPU)希望速度越快越好,但是外设多样,速度千差万别,我们都要满足他们的需求。MCU不仅可能有外部时钟源(包括系统晶体振动,可能有多个),还可能有内部时钟源;为了系统的可靠性,外部晶体振动的频率fosc为了获得核心所需的高频信号,系统也可能相对较低PLL(锁相环)将低频时钟信号转换为高频信号,以及所谓的分频、倍频等设备...但无论如何处理,万变不离其宗,始终将周期性信号发送到计数器(定时功能输入的信号为标准脉冲信号,计数外部脉冲可能涉及滤波、整形手术等,如将正弦信号转换为标准方波信号)。
当我们知道时钟源时,我们还需要知道如何启动计数器。这是一个开关和按钮。具体的设备是不同的。一般来说,您可以设置寄存器,或者设备或端口发出信号启动计数器工作。这是可能的。具体情况不详细。
此外,我们还需要知道定时器记录了多少时间。一般的方法是检查计数器的值。然而,我们应该知道计数器记录的脉冲数量是有限的。例如,8位计数器最多记录255个脉冲,16位计数器最多记录65535个脉冲。如果超过了怎么办?方法很简单:让计数器多计数几次。我们需要知道,一旦计数器达到上限,它就会溢出,并输出信号溢出信号。以8位加法计数器为例。例如,我们需要定期的100脉冲。我们可以让计数器从155开始计数,然后我们不断检查(查询)溢出信号的值。当它出现时,我们可以知道已经有100个信号。若需要定时1000脉冲?我们可以重复上述过程10次。
这里强调计数器输出的脉冲也有很多用途:触发中断,改变特定管脚的值,触发事件...它可以实现许多功能,就像推倒第一块多米乐骨牌一样。这取决于系统设置。一般来说,我们常见的系统必须提供计数脉冲触发中断的机制。如果不提供其他机制,我们也可以通过中断来实现,只是不那么方便和高效而已。
什么是中断?中断就是中断,interrupt!其实这个还没解释清楚。比如我学生时代,学校很远,我住在学校,一周只能回家一次。每周末我的母亲总是很紧张:她要一遍又一遍的到路口看我有没有回来(每次想起这个场景总是心酸),没看到我回来,她总是心神不宁的,事情也做不好,她这样一遍遍地到路口查看我们称之为“查询”。现在要回去怎么办?我只需要打电话告诉她我什么时候回来。这样,电话一响,她就知道我要回来回家了。这可以称为中断。
学术上说:中断是打断当前系统正常运行的机制。中断时,系统停止当前工作,处理中断事务。中断事务完成后,系统返回原始事务继续执行。在这里,我们应该记住,中断是系统用于与外界(人或其他设备)互动和处理随机事件的机制,是一种互动手段。其实在CPU内部仍然有一个设备,它一直在监控信号(中断信号)。一般来说,CPU每执行一个指令,设备查询一次,一旦发现中断信号,立即通知CPU执行中断功能。事实上,我们给了它CPU查询功能了查询功能CPU从低价值工作中解脱出来。
另外还有几个概念需要掌握:
中断源:发出中断信号的设备。
中断服务(处理):当中断发生时,计算机执行工作。一般计算机一旦发现中断,立即停止当前工作,并做记录(机器自动完成)处理返回,称为中断保存。处理完成后,机器返回,然后处理中断的事务,称为中断恢复。
中断向量:中断发生后,机器首先中断保存,然后预设计,CPU指定地址为中断向量。一般来说,机器可以实现多个中断,相应的中断向量放在一起,形成中断向量表。它们的地址通常是特殊的,比如MCS将51的中断向量表放在存储器地址的开头。
中断屏蔽、中断优先级和不可阻挡中断:当中断发生时,我不想处理它——中断屏蔽。几个中断同时发生。谁执行优先级和高执行?高优先级中断可以知道低优先级中断,低优先级中断不能中断高优先级中断。你无法避免一些中断——无法阻止中断。
比如你在做作业(正常事务),朋友叫你打篮球(中断),你放下笔,夹好书(中断保存),告诉他:忙!(中断处理)。然后打开书,拿起笔,然后继续才的地方(中断恢复)。也可能你抹不开面子去打球了(中断处理,中断服务),打完球再回来做作业。当你也有可能玩的时候,你的女朋友来找你去购物(新中断),如果你重朋友轻(女朋友优先级低),你忽略她,继续玩,如果重朋友(女朋友优先级高),你会停止玩,然后陪女朋友去购物。当然,也有可能你认为作业太重要,不想被任何人或任何事打扰。关掉手机,把自己锁在房间里(中断屏蔽),全心全意做作业。但是世界上总有意外:你的楼着火了(不能屏蔽中断)...
一般来说,中断管理是分层的,包括三层和两层。两层为设备层和内核层,设备直接与内核有中断信号线(CPU)这样,设备与内核高度绑定。三层是在设备和内核之间增加中断向量管理器(VIC),这种方法更灵活,设备更多样化。MCS51采用两层管理。
中断信号从设备发出,通过中断向量管理器传输到内核(或直接传输到内核)。我们可以从设备层面关闭或中断CPU中断信号也可以从中断向量管理器关闭CPU如果开关相当于总开关,CPU关闭中断,设备无论如何发出中断信号都没用!
MCS51中有两个计数器,每个计数器有四种计数方法(选择太多),以下是精确延迟和中断定时。
//采用12系统M因此,计时脉冲周期为1us ///定时器0用于延迟,16位定时 ///定时器1用于计数,8位自动重新安装 ///延迟范围为1~65535ns void delay_ns(unsigned int t){ //将TMOD最低位为01,不影响其他位置 TMOD&=~(3<<0); TMOD|=1<<0; //设置设计数的起始值 TH0=(65535-t)>>8; TL0=(65535-t)&0x00FF; ///启动定时器 TR0=1; while(!TF0); TF0=0; TR0=0; } ///延迟范围为1~65535ms void delay_ms(unsigned int t){ //将TMOD最低位为01,不影响其他位置 TMOD&=~(3<<0); TMOD|=1<<0; //设置设计数的起始值,定时1ms _start: t--; TH0=(65535-1000)>>8; TL0=(65535-1000)&0x00FF; ///启动定时器 TR0=1; //等待计数结束 while(!TF0); while(t){ TF0=0; goto _start; } }
void time1ISR() interrupt 3{ ... } void initTimer1(u8 t){ TMOD&=~(3<<4)//定时器1计数清零 TMOD|=2<<4./定时器1计数方法2; TH1=TL1=t; };
*注:对MCS51当其系统晶振为12时Mhz时间意味着每次执行机器指令约需要1us这就是为什么有上述时间delay_us精度误差大,时间越短,相对误差越大!即使难以忍受,也许其计时精度不如空循环,可以考虑使用汇编指令或使用C实现51提供的单个指令!对于现代MCU单个指令周期基本实现,即一个系统周期处理一个指令,如LT320T采用8Mh经倍频后72Mhz,每个指令的执行时间约为1/72us,与MCS51优势明显!其延迟函数的调用和执行时间较少,相对精度较高!但即便如此,还是要做适当的时间补偿,在实际应用中可以用示波器等来测量具体的延迟时间。