历史上的今天
今天是:2024年08月24日(星期六)
2021年08月24日 | 51单片机-微调定时精确时间
2021-08-24 来源:eefocus
1.定时器&蜂鸣器
一般定时器中断函数里的内容最好是能够快速地去执行完,比如只执行几条简单的语句,这样与主函数配合才会使程序更加高效。前期教学里,我们只使用定时器中断负责某个IO引脚间隔跳变或者使一个变量间隔自加1的简单语句。
比如我们现在要实现间隔50ms左右的时间让流水灯左右循环移动的同时,还需要无源蜂鸣器一直响,这样的功能,思路该怎么去思考?
首先我们知道无源蜂鸣器要想鸣叫的比较尖锐,那P1.6需要一个合适的脉冲信号,这个信号笔者打算使P1.6高低电平保持的时间为300微秒不断循环。
所以我们用定时器中断实现P1.6的电平间隔跳变,主函数里负责完成流水灯的任务即可。

2.代码
#include #include u8 T0RH, T0RL; void TIM0_Init(u32 us,int trim)//trim:微调 { u32 tmp; //临时变量 tmp = 11059200 / 12; //定时器计数频率 tmp = ( tmp * (us/100) )/10000;//计算所需的计数值 tmp = 65536 - tmp; //计算定时器重载值 tmp = tmp+trim; //补偿中断响应延时造成的误差 T0RH = (unsigned char)(tmp>>8);//定时器重载值拆分为高低字节 T0RL = (unsigned char)tmp; TMOD &= 0xF0; //清0低四位 TMOD |= 0x01; //设置定时器0为工作模式1 TH0 = T0RH; //加载T0重载值 TL0 = T0RL; ET0 = 1; //闭合定时器0中断的开关 TR0 = 1; //启动定时器0 } void main() { u8 i,dir; LED_Init(); //初始化LED硬件模块 EA = 1; //闭合总中断开关 TIM0_Init(300,0); //用定时器0定时300us,不微调 while(1) { if(i<8)dir=0;//向左移 if(dir==0)P0=~(0x01< if(i>=8)dir=1;//向右移 if(dir==1)P0=~( 0x80>>(i-7) );//当i大于等于8之后,(i-7)其实也还是在1~7之间变化 i++; if(i>=15)i=1;//让i一直在1~14之间变化 delay_ms(50); } } void TIM0_IRQHandler() interrupt 1 { TH0 = T0RH; //重新加载重载值 TL0 = T0RL; BEEP=!BEEP; } 可以看到使用定时器中断比外部中断触发还要高效。 3.讲解微调 然后回到上一讲说过的怎么测试然后去微调使定时时间更精确。 拿我们这讲的代码来说,首先在不微调的情况下,也就是传入的参数trim为0,看看定时的时间是多少。 进入软件调试模式,在“BEEP=! BEEP;”设置断点,在没有微调之前观察每次执行“BEEP =! BEEP;”的间隔时间。 按下RST复位之后,先按两次RUN 再按一次RUN 定时时间为0.003285-0.002979= 0.000306s 所以定时时间超了6微秒,则需要给trim一个合适的参数,这里笔者调出了最合适的数为6,所以我们初始化定时器时改为 TIM0_Init(300,6); //用定时器0定时300us,6是微调使定时时间更精确 这样每次跳转到中断函数去执行的间隔时间就为精确的300us了。 当我们要定时十毫秒或者二三十毫秒时,微调的数可能就不是6了,而是20之间或者其他数,所以每次想要精确定时就需要软件调试亲自测试。


上一篇:51单片机-代码参考
下一篇:51单片机-单独文件封装
史海拾趣
|
大家好:我的protel 99se中画pcb走线时可以走15度,30度等等好像是任意角度,我不想这样改怎么设置? 正常的是可以走45度,90度,135度 谢谢大家哦!… 查看全部问答> |
|
想用ds1302和1602做一个实时时钟,但ds1302的3个口接在P1,而1602的8位数据输入也用的是P1,请问能这样能做到吗?谢谢… 查看全部问答> |
|
第一代LED恒流芯片:此类芯片主要的技术特点是基于固定频率的PWM芯片(如UC384X等),通过降低电感纹波电流,固定电感峰值电流来实现恒流。但由于开关频率固定,为避免次谐振荡,它的最大占空比只能用到50%,其应用范围就很受限了;再者由于电感纹 ...… 查看全部问答> |




