打印

单片机准确定时程序,精度仅仅取决于晶振稳定性

[复制链接]
7360|27
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wangkj|  楼主 | 2008-11-27 16:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
volatile unsigned  int data TimerCounter=0;

/********************************************/
/*          定时器 0 中断服务               */ 
/* 说明:  100us 中断一次, 优先级最高        */
/********************************************/

void  Timer0_Int(void) interrupt 1 using 1 //自动reload方式
{
    MCU_IR_PWM=~MCU_IR_PWM;
    TimerCounter++;
   //32bit int 65536*65536*0.1/1000/3600/24 = 4.971026962962963 天
   //16bit int 65536*0.1/1000  = 6.5536000000000001 大约6.6s
}

void delay1ms(void) 
{
   unsigned  int data OldTimerCounter;
   OldTimerCounter = TimerCounter;
   while((TimerCounter-OldTimerCounter)<=10*1)  // 28.9*1000/256  =    112.890625
   { //如果调试,请把1换成不同到值,1是延时1ms,误差很小

   }
    
}

关键点:
  IP=0x02;  //Timer0 is first level of interrupt
/**********************************************  
IP(0B8H) 7 6 5 4 3 2 1 0
PT2 PS PT1 PX1 PT0 PX0
中断优先级控制位=1 定义为高优先级中断
中断优先级控制位=0 定义为低优先级中断
IP.6 PPC PCA中断优先级控制位
IP.5 PT2 定时器2 中断优先级控制位
IP.4 PS 串行口中断优先级控制位
IP.3 PT1 定时器1 中断优先级控制位
IP.2 PX1 外部中断1 中断优先级控制位
IP.1 PT0 定时器0 中断优先级控制位
IP.0 PX0 外部中断0 中断优先级控制位
************************************************/
  TMOD=0x22; //T0,T1 8 bit auto Reload
             
/***********************************************
TMOD 地址:89H 不可位寻址 复位值:00H
7    6   5  4  3    2   1  0
GATE C/T M1 M0 GATE C/T M1 M0
定时器1 定时器0
位符号 功能
TMOD.7/ GATE TMOD.7 控制定时器1,置1 时只有在INT1 脚为高及TR1 控制位置1 时才可打开定时器/ 计数器1。
TMOD.3/ GATE TMOD.3 控制定时器0,置1 时只有在INT0 脚为高及TR0 控制位置1 时才可打开定时器/ 计数器0。
TMOD.6/ C/T TMOD.6  控制定时器1 用作定时器或计数器,清零则用作定时器(从内部系统时钟输入),
                    置1 用作计数器(从T1/P3.5 脚输入)
TMOD.2/ C/T TMOD.2  控制定时器0 用作定时器或计数器,清零则用作定时器(从内部系统时钟输入),置1 
                    用作计数器(从T0/P3.4 脚输入)
                    
TMOD.5/TMOD.4 M1、M0 定时器定时器/计数器1模式选择
0 0   13位定时器/ 计数器,兼容8048 定时器模式,TL1 只用低5 位参与分频,TH1 整个8 位全用。
0 1   16位定时器/ 计数器,TL1、TH1 全用
1 0   8 位自动重装载定时器,当溢出时将TH1 存放的值自动重装入TL1。
1 1   定时器/ 计数器1 此时无效(停止计数)。
TMOD.1/TMOD.0 M1、M0 定时器/ 计数器0 模式选择
0 0   13位定时器/ 计数器,兼容8048 定时器模式,TL0 只用低5 位参与分频,TH0 整个8 位全用。
0 1   16位定时器/ 计数器,TL0、TH0 全用
1 0   8位自动重装载定时器,当溢出时将TH0 存放的值自动重装入TL0。
1 1   定时器0 此时作为双8 位定时器/ 计数器。TL0 作为一个8 位定时器/ 计数器,通过标准定时器0 
      的控制位控制。TH0 仅作为一个8 位定时器,由定时器1 的控制位控制。

  REN=1;      //enable serial receive
  TH0=0;      
  TL0=0;      // 1S 中产生的溢出和中断的次数:28636000/256.0/12=9321.6145833333339 
              // 大约107us(107.27755273082832) 本程序不需要精确定时,差不多就行可以当作100us用
              // if TH=256-239 则周期为:0.10015365274479675
  TH0=256-243;//1000000/(29.08*1000*1000/256/12)=105.63961485557083
  TL0=256-243;//1000000/(29.08*1000*1000/243/12)=100.27510316368638
 // TH0=256-256; //28.9*1000/256/2 =56.4453125
 // TL0=256-256; 
  TR0=1;
  TR1=1; //TCON=0x50;//0B01010000;  //Timer1 enable    Timer0 enable,No external INT
  ET0=1; //enable Timer0 interupt
//  ET1=1; //enable Timer1 interupt
  ES=1;  //enable serial interupt
  EA=1;  //enable  interupt


相关帖子

沙发
wangkj|  楼主 | 2008-11-27 16:20 | 只看该作者

如果需要1分钟,1小时的准确定时

请直接使用32bit的计数值,计算方法类似。
如果仅仅使用delay1ms会有累计误差的。
如果改进,
留点悬念,好好想想,有利提高初学者的智力水平。

使用特权

评论回复
板凳
icmap| | 2008-11-28 00:24 | 只看该作者

请楼主把方法展示出来看看

以定时 300 秒为例,分别用 TimerCounter 和 delay1ms 这两个方法,要求尽量消除累积误差。

使用特权

评论回复
地板
HWM| | 2008-11-28 08:50 | 只看该作者

随便抓一个晶振就能“准确定时”,牛!

看来“单片机”也不比ARM差。

使用特权

评论回复
5
wangkj|  楼主 | 2008-11-28 09:39 | 只看该作者

答案超过100贴,我才贴出来,还得给条裤子f

否则,不贴,就是不贴。气死你。
另外,准确定时和51,arm没关系,
是对硬件逻辑的理解和写出对应程序的问题。
说实在的,51,只能玩玩,当不得真。

使用特权

评论回复
6
HWM| | 2008-11-28 09:49 | 只看该作者

晕,51确实当不得真,但有些基本玩意儿却假不得。

使用特权

评论回复
7
xwj| | 2008-11-28 10:11 | 只看该作者

LZ,我只问你:你自己测试过吗?统计过误差吗???

可以很明确的告诉你:
                  你的每次延时都会多100uS,void delay1ms(void) 的误差是+0% ~ +10%



至于这个LZ这个方法的原理,只是很简单的东西,没什么好保密、故弄玄虚的.
用自动重载只能说是时钟节拍没有雷击误差罢了,没有别的好处

使用特权

评论回复
8
wangkj|  楼主 | 2008-11-28 10:18 | 只看该作者

雷击误差?

这和打雷有啥关系?????????????

自动重载,是纯硬件的。
响应时间可能不同,
但是,间隔是相同的。
自动重载,和软件运行是并行的。

另外,不要以你的智力理解别人,你是聪明的,能搞明白咋回事。
但是,聪明人是少数,这年头,扩招的后果太严重了。

茄子土豆,都是大学生了。

使用特权

评论回复
9
xwj| | 2008-11-28 10:21 | 只看该作者

呵呵,累积误差

这也要说明吗???

使用特权

评论回复
10
ljm810010| | 2008-11-28 10:32 | 只看该作者

晕死,还要100贴才帖出来!楼主1ms的延时有误

根本不能保证是1ms,会有10%的误差,谈何精确!?

首先,连晶振频率都没说明,谈延时连个基准都没有
其次,没有main()程序,或没有调用delay1ms(void)的示范句,瞎子摸象
最要命的是,delay1ms(void)片时时间不定,
   OldTimerCounter = TimerCounter;这句执行时,TLO可能是255,也可能等于TH0,
也就是说T0中断可能马上发生,也可能过100us后才发生,
   while((TimerCounter-OldTimerCounter)<=10*1)
这句的待时间就变成 900US~1000US不定,误差这么大还说精确?

使用特权

评论回复
11
ljm810010| | 2008-11-28 10:40 | 只看该作者

楼主确实要检讨一下自己的方法

刚看到这个贴时觉得好笑,正如7楼所说,"只是很简单的东西,没什么好保密、故弄玄虚的",最简单地,楼主也应仿真一下,检验一下算法是否正确.精确定时不是这样弄的,坛内有很多方面的贴子,去看看吧.

使用特权

评论回复
12
wangkj|  楼主 | 2008-11-28 11:35 | 只看该作者

我没保密,只是想让某些人动动脑子

我已经写了95%的代码,和及其详细的注释。
这是一个微观和宏观的问题。
这确实是个简单问题,我当时没咋细致思考就写出来的。
后来看到很多人问精确定时问题,我才贴出来的。

我用示波器看过,及其稳定的波形,很准。除非调节的间隔短,
就会有明显的误差。(12x时钟速度),但总体时间是准确的。

使用特权

评论回复
13
HWM| | 2008-11-28 12:27 | 只看该作者

“这是一个微观和宏观的问题”,哈哈。

现在的“宏观”经济问题就是出在“微观”层面上,呵呵。

谁叫你们房价那么高了还去争着买房?
谁叫你们股价那么低了还要争着出逃?

使用特权

评论回复
14
hab2000| | 2008-11-28 12:33 | 只看该作者

凡“精确定时”者,姑且不考虑晶振误差:

无论采取哪种装载(甚至不装载低8位)方式,定时间隔越短误差越大!
反之,如果定时间隔大:例如1天、1月、甚至1年,其误差越小!
原因是正负误差在一定周期内可以自动抵消!

如果要实现高精度定时或计数,通常要采用“同步时钟”检测阀,需要占用2个计数器,同时要求时钟源频率足够高、足够稳定!可参考时钟校验法。

其它方式,只是大家作秀而已!

使用特权

评论回复
15
wangkj|  楼主 | 2008-11-28 14:47 | 只看该作者

那我来个更极端的准确定时

用cpld硬件计数器64bit,直接读数据,这个准了吧。

使用特权

评论回复
16
wangkj|  楼主 | 2008-11-28 15:02 | 只看该作者

auto reload是硬件完成的,不需要占用cpu时间的

所以,时间间隔是准确的,我们只要计数这个装载次数就行了。

使用特权

评论回复
17
ljm810010| | 2008-11-28 15:16 | 只看该作者

有点不可思议了吧,弄个定时还要两个计时器?还要CPLD?

我们讨论的精确定时是指不考虑晶振的误差,运用正确程序,使两个时刻之间CPU运行过的机器周期为我们需的预期值,从而达到设计要求.
我认为只要过了入门级的人,都能轻易运用定时器达到精确定时.
出个题目:要求利用定时中断,使P1.0口的电平每1秒变换一次,12MHz晶体,要求精准定时,误差不超过1US,如果能弄出来,说明你过关了.

使用特权

评论回复
18
wangkj|  楼主 | 2008-11-28 16:27 | 只看该作者

12MHz晶体,如果是12时钟一个周期的芯片

1us的指令周期,没有快速硬件切换单元,不可能完成你说的任务。

除非
1. 单周期指令芯片
2. 有硬件单元。

使用特权

评论回复
19
ljm810010| | 2008-11-28 16:40 | 只看该作者

楼上,是可以的,你想想吧!

使用特权

评论回复
20
5880527| | 2008-11-28 16:45 | 只看该作者

不是吧

楼主如果还说17楼的题目都不可能那楼主想过两天贴出来的方法就没任何意义了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

581

主题

9976

帖子

24

粉丝