文章目录

  • 1. 很多人常常利用 millis( ) 或 micros( )检查是否到了该做事情,
  • 2. 真正溢出(Overflow)的定义应该是当把 millis( ) 看作 signed 有正负,
  • 3. 你可以用简单 Arduino 程序测试:
  • 4.其实我们可以在程序中偷改 millis( ), 这我在以下这篇有写过:
  • 5.那可否偷改 micros( )的答案呢 ?

https://www.arduino.cn/thread-12550-1-1.html

1. 很多人常常利用 millis( ) 或 micros( )检查是否到了该做事情,

或是用来设定定时做事( Timer 库或 SimpleTimer 库都是这样);

但是, 有时很想知道如果 millis( ) 很大会怎样, 到那时自己的写法有没问题 ?
认真仔细推想当然可以,
不过, 懒得仔细想的人就想到说那直接用实验测试,
可是官方网站说 millis( ) 用 unsigned long,
要等到Arduino开始执行之后 49.710 天: (没有人想等那么久吧 ?!)
4294967296 /1000 /60 /60 / 24 天 = 49.710 天
http://arduino.cc/en/Reference/millis
这时 millis( ) 会由最大值的 4294967295 又加 1 变为 0,
一般称这为溢出(Overflow), 其实应该称 Rollover (归零)!
即使是用 micros( ), 那想要等到接近 unsigned long 最大值也要等大约 71.58分钟:
4294967296 /1000/1000 /60 分钟 = 71.58 分钟
也就是说, micros( ) 要开机后大约 71.58分钟才会溢出(Overflow), 或应该说Rollover (归零)!

2. 真正溢出(Overflow)的定义应该是当把 millis( ) 看作 signed 有正负,

然后它从本来正数再次加 1 后瞬间变成负数之时:
在你 PC 上做个测试:
开启微软的计算器(Calculator):
点 View 选 Programmer, 然后点 Dword
输入 0 - 1 并按 =
此时中间有 32 个 1, 最右边编号 0, 最左边是 bit31
用鼠标点一下最左边 bit 31, 该 bit 会变为 0,
得到答案是 2147483647, 这就是有正负之 long 的最大值(即0x7fffFFFF),
这时, 请用鼠标点计算器的 + 再点 1 然后点 =
怪事发生了, 出现答案是负数: -2147483648
也就是说, 把 2147483647 这数加 1 就会变成 -2147483648,
这才是 CPU 对真正 Overflow 的定义 !
但如果看做 unsigned long , 它就是正数 2147483648,
再次加 1, 变成 -2147483647, 它就是 unsigned long 的 2147483649,
一直加 1, 最后会达到 4294967295, 这数看做 signed 有正负就是 -1;
也就是二进制 32 个 1, 此时若不限制只有 32 bit, 则再次加 1 后会
变成 10000… 共 32 个 0 , 这个数其实就是 4294967296

3. 你可以用简单 Arduino 程序测试:

void setup( ) {unsigned long k = -1;Serial.begin(9600);Serial.println( String("k=") + k);long gg = k;Serial.println( String("gg=") + gg);k = k / 2;Serial.println( String("k / 2 = ") + k);
}
void loop( ) {;
}

4.其实我们可以在程序中偷改 millis( ), 这我在以下这篇有写过:

关于 millis() 溢出(overflow)归零(rollover)有没问题?(教程)
http://www.arduino.cn/thread-12506-1-2.html

现在再简单举例说一下如何改:
(a)在你程序最前面写以下这句:
extern unsigned long timer0_millis;
这是宣告说我们要直接存取(访问)纪录 millis( ) 的变量 timer0_millis
(b)想改为接近快要归零或是接近 49.710 天,
这样写:
timer0_millis = -5678; // 就是再过 5.678 秒就会归零
然后你可以立即 Serial.print( millis( ) ); 印出来看看 millis( ) 是多少 !?

©想改为接近 unsigned long 的一半或说大约 24.8 天,
可以这样:
timer0_millis = 2147483647L -5677; // 再过 5.678 秒就会过一半 !
或是不记得这么长的 2147483647L,
那简单写这样也一样:
timer0_millis = ((unsigned long) -1 ) /2 -5677; //再过 5.678 秒就会过一半 !

如果你不相信,
那就写个简单的 Arduino 程序测试看看吧

5.那可否偷改 micros( )的答案呢 ?

答案是当然可以 !
不然要开机后约 71.58 分钟 micros( )才会到很大接近归零也是很久:
4294967296 /1000/1000 /60 分钟 = 71.58 分钟
http://arduino.cc/en/Reference/micros
那要如何偷改 micros( )的答案呢 ?
很简单, 只要偷改计算基础的 timer0_overflow_count 即可,
原理就不多说的, 我写了两个函数方便设定为快要溢出或快要到 unsigned long 的一半

     setMicrosEndBackMs(3250);  // 再过大约 3.25秒 micros( )会溢出(相当于71.58分钟)unsigned long you = micros( );   // 可用 Serial.println(you);  看看setMicrosHalfBackMs(3388); //再过大约  3.388 秒 micros( )会过unsigned long的一半(即快要35.79分钟):unsigned long her = micros( );  //   可用 Serial.println(her);  看看

两个函数如下, 大家可以直接抄去用即可:

// 71.58分钟倒回 back ms (注意不是 back us)
void setMicrosEndBackMs(unsigned long back) {extern unsigned long timer0_overflow_count;back = ( ((unsigned long)(-1)) / 4 / 256 - 2) - back;cli( ); // 禁止中断timer0_overflow_count = back;sei( ); // 允许中断
}// 35.79分钟倒回 back ms (注意不是 back us)
void setMicrosHalfBackMs(unsigned long back) {extern unsigned long timer0_overflow_count;back = ( ((unsigned long)(-1)) / 4 / 256 - 2) / 2 - back;cli( ); // 禁止中断timer0_overflow_count = back;sei( ); // 允许中断
}

关于 millis( ) 与 micros( ) 是如何计算出时间的请参考:
http://www.arduino.cn/thread-12468-1-3.html

不过为了方便, 我把相关的源代码复制在以下:

unsigned long timer0_millis = 0; // 开机到现在几个 millis ?
unsigned char timer0_fract = 0; // 调整误差用
unsigned long timer0_overflow_count; // 给 micros( ) 用// 以下 ISR( ) 中断处理程序每隔 1.024 ms 会执行一次SIGNAL(TIMER0_OVF_vect) {timer0_millis += 1;timer0_fract += 3;if (timer0_fract >= 125) {timer0_fract -= 125;timer0_millis += 1;}timer0_overflow_count++;
}// call 要 4 clock, 回传后把答案复制到变数(variable变量)要8clock
unsigned long millis( ) {unsigned long m;uint8_t oldSREG = SREG;  //状态寄存器(包括是否允许 Interrupt); 1clock// disable interrupts while we read timer0_millis or we might get an// inconsistent value (e.g. in the middle of a write to timer0_millis)cli( ); // 禁止中断; 1 clockm = timer0_millis; // 读取内存的全局变量 timer0_millis;8 clockSREG = oldSREG;  // 恢复状态寄存器(注意不一定恢复中断喔 !);1 clockreturn m;  // 6 clocks
} // millis(   //  total 17 clock cycles
/// unsigned long ans = millis( );  // total 4+17+8 = 29 clocksunsigned long micros() {unsigned long m;uint8_t oldSREG = SREG; // 状态寄存器(包括是否允许 Interrupt)uint8_t t;  // 临时变量cli();    // 禁止 Interruptm = timer0_overflow_count;  // timer0 已经 overflow 几次 ?t = TCNT0;  // timer0 目前的值if ((TIFR0 & _BV(TOV0)) && (t & 255)) m++; // timer0 目前的TCNT0值不是 0且欠一次中断SREG = oldSREG;  // 恢复状态寄存器(注意不一定恢复中断喔 !)return ((m * 256) + t) * 4; // 最大只能代表约 71.58 分钟
} // micros(

如何偷改 millis( ) 与 micros( )的值方便测试(教程)(定时器相关)相关推荐

  1. Arduino Tutorial: Avoiding the Overflow Issue When Using millis() and micros()

    Arduino Tutorial: Avoiding the Overflow Issue When Using millis() and micros() 原文链接: https://www.nor ...

  2. linux 查询线程是否结束_批量随机键值查询测试

    [摘要] 当数据量巨大时,使用大批量随机键值集获取对应记录集合,不仅仅考验数据库软件本身,更在于程序员对数据的理解!如何在硬件资源有限的情况下将性能发挥到极致?点击:批量随机键值查询测试,来乾学院一探 ...

  3. 2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码)

    2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码) 1.引用(普通引用) 变量 ...

  4. 怎么看计算机的网络ping值,Win7怎么查看ping值 win7测试ping值的方法

    Ping值是指从PC对网络服务器发送数据到接收到服务器反馈数据的时间,当我们在win7系统中玩网络游戏的时候,如果ping值高的话就会感觉操作延迟,所以在玩游戏之前我们可以先查看一下ping值,那么我 ...

  5. 手机sar值_手机SAR值仪器测试全过程

    0 手机SAR值仪器测试全过程 2014-03-18 15:38 { "info": { "setname": "手机SAR值仪器测试全过程" ...

  6. 王者荣耀java修改_王者荣耀战区怎么改到其他地方 王者荣耀战区修改教程最新...

    王者荣耀战区修改教程是游戏战区玩法,玩家们想知道如何修改喔,那么王者荣耀战区怎么改到其他地方.王者荣耀战区修改教程最新呢,跑跑车手游网为大家带来了介绍. *王者荣耀战区怎么改到其他地方? 王者荣耀中有 ...

  7. 中国工业经济-污染与经济增长面板数据熵值法计算教程

     一.污染与经济增长数据集(面板数据) 1.数据来源:国家统计局,中国环境保护数据库.气象站等机构.环境统计年鉴.https://earthdata.nasa.gov/eosdis(pm2.5) 2. ...

  8. 使用Ajax实现简单的增删查改前端Ajax传的值,后端如何获取

    实现查询和增删改 一.Ajax最基本语法 二.增删查改 1.查询(Get请求) 2.增删改(Post请求) 三.后台(MVC/WebForm) 1.MVC(Post请求) 2.WebForm(Post ...

  9. 某些列满足某些条件就被改是什么值,不满足就被改为另外的一些值(python pandas)

    直接上实例代码吧 import pandas as pd import numpy as np if __name__ == '__main__':df = pd.DataFrame({'AAA': ...

最新文章

  1. 19号晚-21号上午
  2. IOS7开发~API变化
  3. 禁用/启用本地连接的dos命令是什么啊?
  4. 【项目管理】记第一次出差到客户现场推进项目验收感悟
  5. chrome android 远程调试,chrome 远程调试
  6. 680. 验证回文字符串 Ⅱ golang
  7. LINUX下安装软件方法命令方法
  8. What is Leanstar.cn?
  9. 黑马程序员-Java学习笔记之抽象类,接口,多态和内部类
  10. 在线JSON校验格式化工具,文本对比工具,截图notepad工具
  11. 富士康计划将苹果生产线转移到越南,是什么原因呢?
  12. 5s管理推进的三个阶段及三大实施原则
  13. 谷歌绝不会退出中国市场
  14. 学术-物理-维空间:一维空间
  15. 实现圆形头像(并且不管图大小都显示成固定尺寸)-和上一篇有点不同。
  16. 进制转换(进制转换)
  17. Sublime Text 4 如何安装插件
  18. 图像视频降噪的现在与未来——从经典方法到深度学习
  19. 教你用响应式设计的H5网站模板,快速实现自适应
  20. pc端android端 倒数日,倒数日电脑版下载-倒数日电脑版下载 v4.5.2--PC6电脑版

热门文章

  1. matlab人眼虹膜定位,基于Hough变换的人眼虹膜定位方法
  2. fcntl.py模块
  3. 【原创达人】笔记本进水就坏了么
  4. Linux系统Redis安装教程-附带后台启动
  5. 浅聊DAO图景和未来
  6. 关系网络数据可视化:1. 关系网络图Gephi
  7. linux肉鸡检测,一台linux肉鸡的简单手工入侵检测过程
  8. 【Linux Socket 编程入门】06 - 拉个骡子溜溜:UDP编程模型代码分析
  9. opencv(python)使用knn最近邻算法识别手写数字
  10. 战队口号霸气押韵8字_精选励志的运动会口号27句