找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6592|回复: 11
收起左侧

[讨论]菜鸟纠结于精确计时

[复制链接]
ID:44260 发表于 2012-8-30 14:31 | 显示全部楼层 |阅读模式

首先声明下我只是个菜鸟,
只会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闪烁”
再精确~我目前是无能为力了 =_=!

 

下面是我写的程序代码[数码管的干扰什么的请无视]
另外,代码我只是刚在公司写完,还没在开法板上测试过 ^=^

 

 

111.png

 

//第一个发光管以间隔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
*/ 
}


 

[此贴子已经被作者于2012-8-30 14:36:25编辑过]
回复

使用道具 举报

ID:1 发表于 2012-8-30 16:23 | 显示全部楼层

我原来曾经专门开过一个帖子介绍过精确定时的问题 http://www.51hei.com/bbs/dpj-4711-1.html  

 

你按上面网址的做 能精确到1微妙 .

回复

使用道具 举报

ID:44260 发表于 2012-8-30 21:50 | 显示全部楼层

看了那个贴子,汇编不懂~哈

 

参照贴子,按思路试了一下,应该也是可以调整 延迟语句 精确定时到200ms,

但这种 延迟语句 没办法方便调整成其它时间,比如改成250ms,又得反复调  延迟语句 到精确。

 【这方法也可以把精确定时调小,比如 延迟语句 1次是50ms,要250ms定时 就调用5次】

 

 

又顺着贴子看到 _nop_() 函数正好是 1 μs,看了之前的程序,

闪烁1次慢1 μs 不对,而是快了1 μs

加个 _nop_()  应该正好

 

调了下我的程序,关了数码管干扰,加了 _nop_() 空函数,正好间隔200ms,非常精确。

改定时就修改 if 的判断语句,可以随便改 50ms 倍数 的间隔时间,都是精准的。

 

当然主程序循环体语句数量改变等,定时器中断程序里的 堆栈 操作时间也会随着变,调起来也麻烦了 =_=!

 

我的程序改成这样了:

 

 

 

[此贴子已经被作者于2012-8-30 22:01:37编辑过]
回复

使用道具 举报

ID:7485 发表于 2012-8-31 08:08 | 显示全部楼层

首先你的精益求精的精神我是赞赏的。

 

基于你这种精神和目的,但是我不得不告诉你:定时器工作在这种模式下,不可能那么精确!(12m晶振,只要有误差就肯定大于1us)

 

原因是由于51单片机在响应中断请求时的一些条件(具体的你自己再看看资料吧),不可能任何情况下都及时响应。由于重新装载定时初值是在中断内,所以就会造成重新装载初值的时间不确定(当然是us级的),自然就造成了误差。

 

怎么办呢?如果是做单片机时钟(不用时钟芯片),确实需要这么高的精度时,可以采用定时器/计数器2(51没有,52有),自动重装载初值的工作模式。

回复

使用道具 举报

ID:44260 发表于 2012-8-31 12:07 | 显示全部楼层

呵呵,我的代码里,12M晶振不准引起的误差,我就是再怎么个强迫症,我也无能为力了

STC-ISP下载时显示的貌似确实不是精确12M,是不满12M】

 

我们开发板 STC89C52单片机 芯片

是有 定时器/计数器2 的吧,

 

查了 reg52.h , 定时器/计数器2 不是很懂,

是不是这样

IE 寄存器的 ET2 位是 定时器/计数器2 开关

对应的 T2CON 寄存器的 TR2和TF2位是 开始计时和溢出的标志位

 

T2CON 其它位都是什么作用?

始初值、工作方式啊 什么的是哪在个寄存器位?

 

看不懂啊,还缺点理论知识,

定时器/计数器2 使用教程在哪有的没?

 

 

[此贴子已经被作者于2012-8-31 12:07:58编辑过]
回复

使用道具 举报

ID:7485 发表于 2012-8-31 21:41 | 显示全部楼层

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中断

 

[此贴子已经被作者于2012-9-1 9:36:46编辑过]
回复

使用道具 举报

ID:44260 发表于 2012-8-31 22:01 | 显示全部楼层

继续学习~发现T0 T1 的工作方式2 也是具有自动重装的,

 

只不过只能有8位也就是最大256us [12M晶振]

 

256us 时间有点短,留给程序执行的其它代码时间不多。

 

我这样理解不错吧?

回复

使用道具 举报

ID:7485 发表于 2012-9-1 09:34 | 显示全部楼层

你的理解是对的!

 

按我上面给你的回复试一试,就那么多。

回复

使用道具 举报

ID:42637 发表于 2012-9-1 22:26 | 显示全部楼层

结果是闪烁1次慢1微秒,折换到1小时就是慢 18ms
也就是只能做到 “第一个发光管以间隔199.999ms闪烁”
肉眼观察到这种现象?

软件仿真本就不准!

在网上查了一下,能测1微秒的量具还真没找到。

[此贴子已经被作者于2012-9-1 22:31:50编辑过]
回复

使用道具 举报

ID:7485 发表于 2012-9-2 00:32 | 显示全部楼层

单独计量一个us是不容易,但是10天差5秒是可以计量的。

回复

使用道具 举报

ID:1 发表于 2012-9-3 22:04 | 显示全部楼层
敢问楼主用的什么代码编辑器  貌似不是keil?
回复

使用道具 举报

ID:44260 发表于 2012-9-4 08:48 | 显示全部楼层

只是截图时用的 Notepad++ 文本编辑器

 

应用了 tomorrow_night_bright 皮肤

[此贴子已经被作者于2012-9-4 8:48:55编辑过]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表