zoukankan      html  css  js  c++  java
  • 计算51单片机定时器定时时间方法

    计算定时器定时时间

    • 假设现在使用晶振是 11.0592M

      • 则时钟周期为:

        [frac{1}{11059200} ]

      • 则机器周期为:

        [frac{12}{11059200} ]

    • 如果现在要定时20ms, 就是0.02秒, 要经过x个机器周期后得到0.02秒, 列出方程:

      [x * frac{12}{11059200} = 0.02 \ \ x = 18432 ]

      • x(18432 )个机器周期后刚好达到 65536(溢出)
      • 因为16 位定时器 的溢出值是 65536(因 为65535 +1 才是溢出)
    • 得到寄存器初值y

      [y = 65536 - 18432 = 47104 ]

      • 将y转成 16 进制 就是 0xB800
        • TH0 = 0xB8
        • TL0 = 0x00

    Matlab计算

    • 如果以上方程懒得手算求解的话,有个好方法就是用Matlab解一下 [滑稽].

      syms x
      
      eqn = x * 12 / 11059200 == 0.02
      
      solve(eqn, x)
      
    • 同样可以得到18432

    定时时间精准性调整

    问题提出

    • 单片机系统里,硬件进入中断需要一定的时间,大概是几个机器周期,还要进行原始数据保护,就是把进中断之前程序运行的一些变量先保存起来,专业术语叫做中断压栈,进入中断后,重新给定时器 TH 和 TL 赋值,也需要几个机器周期,这样下来就会消耗一定的时间.
    • 虽说这点时间很短,但这所造成的时间误差是会累计的,没1秒钟都差了几个微秒,时间一久造成的误差就不可小觑了。

    解决方案

    1. 使用软件debug进行补偿:

      • keil Debug观察程序运行时间, 可以把2次进入中断的时间间隔观察出来,比较和实际定时的时间相差了几个机器周期,然后在进行定时器初值赋值的时候,进行一个调整。
      • 目前我STC89C52上用的是11.0592M晶振,发现差了几个机器周期,就把定时器初值加上几个机器周期,这样相当于进行了一个补偿。
    2. 使用累计误差计算出来:

      • 有时候,除了程序本身存在的误差外,硬件精度也有可能会影响到时钟的精度,比如晶振,会随着温度变化出现温漂现象,就是实际值和标称值要差一点。那么还可以采取累计误差的方法来提高精度:
        • 比如我们可以让时钟运行半个小时或者一个小时,看看最终时间差了几秒,然后算算一共进了多少次定时器中断,把这差的几秒平均分配到每次的定时器中断中,就可以实现时钟的调整。
    3. 这个世界上没有绝对的精确,只能在一定程度上提高精确度,但是永远不会使误差为0,只能无限接近0,如果在上两个基础上,还是觉得不够精确的话,那么建议使用时钟芯片(DS1302),通常时钟芯片计时的精度比单片机的精度要高一些。

    Code

    • 精确到ms定时时间的函数

      /* 定义定时器高低位重装数据的全局变量 */
      #define CRYSTAL_VALUE 11059200 // 当前单片机所使用的晶振值
      #define MACHINE_CYCLE 12       // 当前单片机的机器周期
      
      unsigned char T0RH = 0; // T0 重载值的高字节
      unsigned char T0RL = 0; // T0 重载值的低字节
      
      /* 配置并启动 T0,ms-T0 定时时间 */
      void ConfigTimer0(unsigned int ms) {
        unsigned long tmp_value;
        //临时变量
        tmp_value = CRYSTAL_VALUE / MACHINE_CYCLE;
      
        //定时器计数频率
        tmp_value = (tmp_value * ms) / 1000;   // 计算所需的计数值
        tmp_value = 65536 - tmp_value;         // 计算定时器重载值
        tmp_value = tmp_value + 18;            // 补偿中断响应延时造成的误差
        T0RH = (unsigned char)(tmp_value>>8);  // 定时器重载值拆分为高低字节
        T0RL = (unsigned char)tmp_value;
        TMOD &= 0xF0;                   // 清零 T0 的控制位
        TMOD |= 0x01;                   // 配置 T0 为模式 1
        TH0 = T0RH;                     // 加载 T0 重载值
        TL0 = T0RL;
        ET0 = 1;                        // 使能 T0 中断
        TR0 = 1;                        // 启动 T0
      
      }
      
      /* 定时器0中断服务函数 */
      void InterruptTimer0() interrupt 1 {
        TH0 = T0RH; // 重新加载初值
        TL0 = T0RL;
      
      }
      
  • 相关阅读:
    从源代码解释Android事件分发机制
    怎样让oracle实验本在不做实验时性能提升——win7下举例
    could only be replicated to 0 nodes, instead of 1
    虚拟机和主机ping不通解决的方法
    ZOJ3623:Battle Ships(全然背包)
    Android 网络编程之---HttpClient 与 HttpURLConnection 共用cookie
    注冊成为Windows Phone开发人员而且解锁Windows Phone 8.1手机
    sharding-method首页、文档和下载
    rootsongjc/kubernetes-handbook: Kubernetes中文指南/实践手册
    如何基于K8S打造轻量级PaaS平台
  • 原文地址:https://www.cnblogs.com/ieeqc/p/14373828.html
Copyright © 2011-2022 走看看