首先声明下我只是个菜鸟,
只会1点C语言,汇编什么的~对我而言是天书,看不懂
开发板也周日下午到的手,
“十天学会单片机和C语言编程”也才看完 Lesson3,讲到 T0 中断。
试着做教程里的 课后练习,第1题,
题目是:第一个发光管以间隔200ms闪烁
题目说了200ms,我的强迫症啊,发作了,就想让他很精确的间隔200ms
看了其它的例子,
比如:http://www.51hei.com/bbs/dpj-13914-1.html
都没有很精确~
然后就试着自己写1个,
用我目前学会的办法,写了1段代码,
用Keil的软件模拟,看间隔时间,
结果是闪烁1次慢1微秒,折换到1小时就是慢 18ms
也就是只能做到 “第一个发光管以间隔199.999ms闪烁”
再精确~我目前是无能为力了 =_=!
下面是我写的程序代码[数码管的干扰什么的请无视]
另外,代码我只是刚在公司写完,还没在开法板上测试过 ^=^
//第一个发光管以间隔200ms闪烁
//计时器 T0 中断的使用
//使用 12MHz 晶振,方便计时
#include <reg52.h> //52单片机头文件
unsigned char T50ms=0;
sbit leds=P1^4; //灯总开关
sbit led1=P0^0; //第1个灯开关
void main()
{ leds=0; //开灯
TMOD=0x01; //T0工作方式为 定时+16位定时
TH0=(65536-50000)/256; //定时器高8位初始时值
TL0=(65536-50000)%256; //定时器低8位初始时值
//50ms 计时
EA=1; //中断总开关
ET0=1; //中断小开关-T0计时开关
TR0=1; //开始计时
while(1)
{
if(T50ms==4)
{led1=!led1; //灯闪烁
T50ms=0;} //重新计次
}
}
void delay50ms() interrupt 1
{
//中断程序耗时_跳进中断堆栈操用5个机器周期= 5 μs
T50ms++;
//中断程序耗时_++运算用1个机器周= 1 μs
TH0=(65536-50000)/256; //定时器高8位初始时值
//中断程序耗时_一次赋值用2个机器周= 2 μs
TL0=(65536-50000)%256+8; //定时器低8位初始时值
/*
在 TL0 中
+8 后灯每次变化慢 1μs
每即 200ms 慢 1μs
1小时慢 18ms
在 led1=!led1; 处设断点,用Keil软件模拟,查看 sec 的值,
#1=0.20045900
#2=0.40045800
#3=0.60045700
#4=0.80045600
#5=1.00045500
*/
}
我原来曾经专门开过一个帖子介绍过精确定时的问题 http://www.51hei.com/bbs/dpj-4711-1.html
你按上面网址的做 能精确到1微妙 .
看了那个贴子,汇编不懂~哈
参照贴子,按思路试了一下,应该也是可以调整 延迟语句 精确定时到200ms,
但这种 延迟语句 没办法方便调整成其它时间,比如改成250ms,又得反复调 延迟语句 到精确。
【这方法也可以把精确定时调小,比如 延迟语句 1次是50ms,要250ms定时 就调用5次】
又顺着贴子看到 _nop_() 函数正好是 1 μs,看了之前的程序,
闪烁1次慢1 μs 不对,而是快了1 μs;
加个 _nop_() 应该正好
调了下我的程序,关了数码管干扰,加了 _nop_() 空函数,正好间隔200ms,非常精确。
改定时就修改 if 的判断语句,可以随便改 50ms 倍数 的间隔时间,都是精准的。
当然主程序循环体语句数量改变等,定时器中断程序里的 堆栈 操作时间也会随着变,调起来也麻烦了 =_=!
我的程序改成这样了:
首先你的精益求精的精神我是赞赏的。
基于你这种精神和目的,但是我不得不告诉你:定时器工作在这种模式下,不可能那么精确!(12m晶振,只要有误差就肯定大于1us)
原因是由于51单片机在响应中断请求时的一些条件(具体的你自己再看看资料吧),不可能任何情况下都及时响应。由于重新装载定时初值是在中断内,所以就会造成重新装载初值的时间不确定(当然是us级的),自然就造成了误差。
怎么办呢?如果是做单片机时钟(不用时钟芯片),确实需要这么高的精度时,可以采用定时器/计数器2(51没有,52有),自动重装载初值的工作模式。
呵呵,我的代码里,12M晶振不准引起的误差,我就是再怎么个强迫症,我也无能为力了
【STC-ISP下载时显示的貌似确实不是精确12M,是不满12M】
我们开发板 STC89C52单片机 芯片
是有 定时器/计数器2 的吧,
查了 reg52.h , 定时器/计数器2 不是很懂,
是不是这样
IE 寄存器的 ET2 位是 定时器/计数器2 开关
对应的 T2CON 寄存器的 TR2和TF2位是 开始计时和溢出的标志位
T2CON 其它位都是什么作用?
始初值、工作方式啊 什么的是哪在个寄存器位?
看不懂啊,还缺点理论知识,
定时器/计数器2 使用教程在哪有的没?
TH2=(65536-46080)/256 ;//46080...11.0592MHZ晶振的初装值
TL2=(65536-46080) MOD 256 ;//初值0DC00H送定时器T2
RCAP2H=(65536-46080)/256;
RCAP2L=(65536-46080) MOD 256 ;//初始化重装初值
T2CON=0x04 ;//初始化T2工作方式(自动重装初值、定时)
;//并启动了T2
ET2=1 ;//允许定时器T2中断
继续学习~发现T0 T1 的工作方式2 也是具有自动重装的,
只不过只能有8位也就是最大256us [12M晶振]
256us 时间有点短,留给程序执行的其它代码时间不多。
我这样理解不错吧?
你的理解是对的!
按我上面给你的回复试一试,就那么多。
结果是闪烁1次慢1微秒,折换到1小时就是慢 18ms
也就是只能做到 “第一个发光管以间隔199.999ms闪烁”
肉眼观察到这种现象?
软件仿真本就不准!
在网上查了一下,能测1微秒的量具还真没找到。
单独计量一个us是不容易,但是10天差5秒是可以计量的。
只是截图时用的 Notepad++ 文本编辑器
应用了 tomorrow_night_bright 皮肤
欢迎光临 (http://www.51hei.com/bbs/) | Powered by Discuz! X3.1 |