开场白:
上一节说到在累计主循环次数来完成计时,跟着主函数里使命量的添加,为了确保延时时刻的准确性,要不断批改设定上限阀值const_time_level 。咱们该怎样处理这个问题呢?本节教咱们使用累计守时中止次数的办法来处理这个问题。这一节要教会咱们四个知识点:
榜首点:使用累计守时中止次数的办法完成时刻延时
第二点:展现鸿哥最完好的实战程序结构。在主函数循环里用switch句子完成状况机的切换,在守时中止里累计中止次数,这两个的结合便是我写代码最实质的结构思维。
第三点:提示咱们C语言中的int ,long变量是由几个字节构成的数据,但凡在main函数和中止函数里有或许一起改动的变量,这个变量应该在主函数中被更改之前,先封闭相应的中止,更改完了此变量,再翻开中止,不然会留下不宜发觉的缝隙。当然在大部分的项目中能够不必这么操作,可是在一些要求十分高的项目中,有一些中心变量有必要这么做。
第四点:守时中止的初始值该怎样设置。不必严厉按公式来核算时刻,一般取个经历值是最大初始值减去1000就能够了。
具体内容,请看源代码解说。
(1)硬件渠道:根据朱兆祺51单片机学习板。
(2)完成功用:让一个LED闪耀。
(3)源代码解说如下:
#include “REG52.H”
#define const_time_level 200
void initial_myself();
void initial_peripheral();
void delay_long(unsigned int uiDelaylong);
void led_flicker();
void T0_time(); //守时中止函数
sbit led_dr=P3^5;
unsigned char ucLedStep=0; //过程变量
unsigned int uiTimeCnt=0; //计算守时中止次数的延时计数器
void main()
{
initial_myself();
delay_long(100);
initial_peripheral();
while(1)
{
led_flicker();
}
}
void led_flicker() ////第三区 LED闪耀应用程序
{
switch(ucLedStep)
{
case 0:
/* 注释一:
* uiTimeCnt累加守时中止的次数,每一次守时中止它都会在中止函数里自加一。
* 只要当它的次数大于或等于设定上限const_time_level时,
* 才会去改动LED灯的状况,不然CPU退出led_flicker()使命,持续快速扫描其他的使命,
* 这样的程序结构就能够到达多使命并行处理的意图。这便是鸿哥在所有开发项目中的中心结构。
*/
if(uiTimeCnt>=const_time_level) //时刻到
{
/* 注释二:
* ET0=0;uiTimeCnt=0;ET0=1;—-在清零uiTimeCnt之前,为什么要先制止守时中止?
* 因为uiTimeCnt是unsigned int类型,实质上是由两个字节组成。
* 在C语言中uiTimeCnt=0看似一条指令,实际上通过编译之后它不只一条汇编指令。
* 因为守时中止函数里也对这个变量进行累加操作,假如不制止守时中止,
* 那么uiTimeCnt这个变量在main()函数中还没被彻底清零的时分,假如这个时分
* 忽然来一个守时中止,并且在中止里又更改了此变量,这种状况在某些要求高的
* 项目上会是一个不容易发觉的缝隙,为项目带来危险。当然,大部分的一般项目,
* 都能够不必那么严厉,能够不必制止守时中止。在这儿仅仅提示各位初学者有这种状况。
*/
ET0=0; //制止守时中止
uiTimeCnt=0; //时刻计数器清零
ET0=1; //敞开守时中止
led_dr=1; //让LED亮
ucLedStep=1; //切换到下一个过程
}
break;
case 1:
if(uiTimeCnt>=const_time_level) //时刻到
{
ET0=0; //制止守时中止
uiTimeCnt=0; //时刻计数器清零
ET0=1; //敞开守时中止
led_dr=0; //让LED灭
ucLedStep=0; //回来到上一个过程
}
break;
}
}
/* 注释三:
* C51的中止函数格局如下:
* void 函数名() interrupt 中止号
* {
* 中止程序内容
* }
* 函数名能够随意取,只需不是编译器现已征用的要害字。
* 这儿最要害的是中止号,不同的中止号代表不同类型的中止。
* 守时中止的中止号是 1.至于其它中止的中止号,咱们能够查找
* 相关书本和材料。咱们进入中止时,有必要先铲除中止标志,并且
* 封闭中止,然后再写代码,最终出来时,记住重装初始值,并且
* 翻开中止。
*/
void T0_time() interrupt 1
{
TF0=0; //铲除中止标志
TR0=0; //关中止
if(uiTimeCnt<0xffff) //设定这个条件,避免uiTimeCnt超范围。
{
uiTimeCnt++; //累加守时中止的次数,
}
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
TR0=1; //开中止
}
void delay_long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i { for(j=0;j<500;j++) //内嵌循环的空指令数量 { ; //一个分号相当于履行一条空句子 } } }
void initial_myself() //榜首区 初始化单片机
{
/* 注释四:
* 单片机有几个守时器,每个守时器又有几种工作方式,
* 那么多种改变,咱们记不了那么多,怎样办?
* 咱们记住鸿哥的话,不管一个单片机有多少内置资源,
* 咱们做体系结构的,只需求一个守时器,一种工作方式。
* 开守时器越多这个体系越欠好。需求哪种守时工作方式呢?
* 就需求呼应守时中止后重装一下初始值持续跑那种。
* 在51单片机中便是工作方式1。其它的工作方式很少项目能用到。
*/
TMOD=0x01; //设置守时器0为工作方式1
/* 注释五:
* 装守时器的初始值,就像一个水桶里装的水。假如这个桶是空桶,那么想
* 把这个桶灌满水的时刻就很长,假如是里边现已装了多半的水,那么想
* 把这个桶灌满水的时刻就相对比较短。也便是守时器初始值越小,发生一次
* 守时中止的时刻就越长。假如初始值太小了,每次发生守时中止
* 的时刻分辨率太粗,假如初始值太大了,尽管每次发生守时中止的时刻分辨率很细,
* 可是太频频的发生中止,不但会影响主函数main()的履行功率,并且累记中止次数
* 的时刻误差也会很大。凭鸿哥多年的江湖经历,
* 我觉得最大初始值减去2000是比较好的经历值。当然,大一点小一点不要紧。不要走
* 两个极点就行。
*/
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
led_dr=0; //LED灭
}
void initial_peripheral() //第二区 初始化外围
{
EA=1; //开总中止
ET0=1; //答应守时中止
TR0=1; //发动守时中止
}
总结陈词:
本节程序麻雀虽小五脏俱全。在本节中现已展现了我最完好的实战程序结构。
本节程序只要一个LED灯闪耀的单使命,假如要多添加一个使命来并行处理,该怎样办?
欲知概况,请听下回分解—–蜂鸣器的驱动程序。