极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 13582|回复: 5

系统时间最长9小时22分钟,求大神帮我让这个程序在9小时22分后别乱

[复制链接]
发表于 2015-4-4 20:46:56 | 显示全部楼层 |阅读模式
  1. unsigned long zhongduan1=6000;
  2. #include <LiquidCrystal.h>
  3. #include <SD.h>
  4. // CS引脚为pin4,这里也沿用官方默认设置
  5. const int chipSelect = 4;  //设定CS接口
  6. int GP2D12 = 0;//把夏普GP2D12红外测距传感器连接在模拟量端口0
  7. int val;   //存储从GP2D12红外测距传感器读到的值     
  8. float temp;//存储由传感器读取值,通过算式处理后的浮点型距离值
  9. int distance;//存储由传感器读取值,通过算式处理后的整数型距离值
  10. float dataString;

  11. LiquidCrystal lcd(10,6,5,7,3,2);//构造一个LiquidCrystal的类成员。使用数字IO ,12,11,5,4,3,2
  12. void setup()
  13. {
  14.   lcd.begin(16,2);//初始化LCD1602
  15.   lcd.setCursor(4, 0);
  16.   lcd.print("YANG WEN QI ");//液晶显示
  17.     lcd.setCursor(3, 1);
  18.   lcd.print("IS SO COOl");
  19.   delay(5000);        //延时5000ms
  20.   lcd.clear();        //液晶清屏
  21.   Serial.begin(9600);  //设置串口通信波特率为9600
  22.   Serial.print("Initializing SD card...");  //串口输出数据Initializing SD card...
  23.   if (!SD.begin(chipSelect)) {  //如果从CS口与SD卡通信失败,串口输出信息Card failed, or not present
  24.     Serial.println("Card failed, or not present");
  25.     return;
  26.   }
  27.   Serial.println("card initialized.");  //与SD卡通信成功,串口输出信息card initialized.
  28. }

  29. void loop()
  30. {
  31.     unsigned long nowtime=millis(); //获取当前的系统运行时间长度
  32.     if(nowtime>zhongduan1)    //检测系统运行时间长度
  33. {
  34.    // 读取1个传感器值,写入数组
  35.   for (int GP2D12 = 0; GP2D12 < 1; GP2D12++) {
  36.     int sensor = analogRead(GP2D12);
  37.     dataString = 2547.8/((float)val*0.49-10.41)-0.42;
  38. }
  39.    // 打开文件,注意在同一时间只能有一个文件被打开
  40.   // 如果你要打开另一个文件,就需要先关闭前一个
  41.   File dataFile = SD.open("datalog.txt", FILE_WRITE);  
  42. // 打开datalog.txt文件,读写状态,位置在文件末尾。
  43.   if (dataFile)
  44.   {
  45.     dataFile.println(dataString);
  46.     dataFile.close();
  47.     // 数组dataString输出到串口
  48.     Serial.println(dataString);
  49.   }  
  50.   // 如果无法打开文件,串口输出错误信息error opening datalog.txt
  51.   else {
  52.     Serial.println("error opening datalog.txt");
  53.         }
  54. zhongduan1=nowtime+60000;
  55.     }
  56.     lcd.clear();
  57. //读取GP2D12红外测距传感器模拟量数据
  58.   val = analogRead(GP2D12);
  59.   //通过以下算式,把传感器读取值处理成浮点型距离值
  60.   temp=2547.8/((float)val*0.49-10.41)-0.42;
  61.   //lcd.clear();//LCD清屏
  62.   // 定位光标在LCD第0行、第0列
  63.   //lcd.setCursor(0, 0);
  64.   //在LCD第0行第0列开始显示"Distance:"
  65. // lcd.print("Distance:");
  66.   // 定位光标在LCD第1行、第7列
  67.   //lcd.setCursor(7, 1);
  68.   //如果传感器读取值大于80或者小于10,
  69. // if(temp>80||temp<10)
  70.       //  {
  71.       //则在LCD第1行、第7列开始显示"OverRange"
  72.         // lcd.print("OverRange");      
  73.    // }
  74.    //如果传感器读取值在10到80之间,
  75.   //else
  76.      //   {        
  77.         //把浮点型距离值取整
  78.         //distance=temp;
  79.         //则在LCD第1行、第7列开始显示距离值
  80.        // lcd.print(distance);
  81.         //在距离值后显示单位"cm"
  82.         //lcd.print("cm");
  83.   lcd.setCursor(0, 0);
  84.   //在LCD第0行第0列开始显示"Distance:"
  85.   lcd.print(dataString);
  86.   // 定位光标在LCD第1行、第7列
  87. lcd.setCursor(7, 1);
  88.      //则在LCD第1行、第7列开始显示距离值
  89.        lcd.print(temp);
  90.         //在距离值后显示单位"cm"
  91.         lcd.print("cm");
  92.    delay(1000);
  93. }
复制代码

回复

使用道具 举报

 楼主| 发表于 2015-4-4 22:37:18 | 显示全部楼层
问题已解决
回复 支持 反对

使用道具 举报

发表于 2015-4-5 16:19:48 | 显示全部楼层
99uuuu 发表于 2015-4-4 22:37
问题已解决


已解决 ??
Are you sure 没问题 ?
Your code:
  unsigned long nowtime=millis(); //获取当前的系统运行时间长度
  if(nowtime>zhongduan1)    //检测系统运行时间长度
  {
   ...
   ...
   zhongduan1=nowtime+60000;
  }

Should be changed to:

  unsigned long nowtime=millis(); //获取当前的系统运行时间长度
  if(nowtime - zhongduan1 < 60000)    //检测系统运行时间长度
  {
    // do nothing  .. or
    // return;
  }else{
   zhongduan1=nowtime;
   ...
   ...
  }

这当 millis() 溢出(Overflow)归零时没有问题 !!


你的问题出在 nowtime+60000 这个地方,
由於 60000 是正的数,
而 nowtime = millis( ) 虽然是 unsigned long,
但当 millis( ) 达到unsigned long 接近最大数之时其实就是负很少的负数,
这时 millis( ) 或说 nowtime看作signed如为负数且
其绝对值如果小於 60000 则会使 nowtime+ 60000 变成正数就会出问题 !
这使得 millis( ) < zhongduan1 就会立即不成立 !!
(你的   zhongduan1= nowtime+60000; )
回复 支持 反对

使用道具 举报

发表于 2015-4-5 16:22:09 | 显示全部楼层
P.S.
  millis( )要 49.71 天才溢出(Overflow)归零,
不是 9小时22分 !
但 micros( ) 则大约 71.58分钟归零
因为 millis( )是用 unsigned long (32 bits)表示开机到现在为止几个 milli second,
用 32 bit 表示一个无符號整数, 32bit都是 1就是最大数, 等於 2 的 32 次方 -1 = 4294967295
从 0 数到 4294967295 共要 4294967296  milli seconds,
等於 4294967296 /1000 /60 /60 小时; 每天有 24小时,
所以等於 4294967296 /1000 /60 /60 / 24 天 = 49.710 天
也就是说, 开机后大约快要 50 天之时 millis( )会归零 !
回复 支持 反对

使用道具 举报

发表于 2015-4-5 16:30:20 | 显示全部楼层
tsaiwn 发表于 2015-4-5 16:19
已解决 ??
Are you sure 没问题 ?
Your code:





为何说原则上millis()溢出归零是没问题,
但是如果程序码没写好则有问题 ! 因为问题並不是出在 millis( ) 归零本身 !
请看以下这 Arduino 的 delay( ) 代码:  (正確 )

void delay( unsigned long dtms ){
  unsigned long start = millis();
  while (millis() - start < dtms);;
} // delay(

以上这程序完全正確, 且即使 millis( ) 溢出归零也不会有问题 !!

但是以下看起来很像的写法则是有问题的: (错误)
void delay( unsigned long dtms ){
  unsigned long start = millis();
  while (millis() < start + dtms);;   // 有问题 !
} // delay(

从数学观点看起来似乎相同,
  因为   millis() - start < dtms)
应该就相当於  millis() < start + dtms
可是这只在没有 Overflow 之时成立, 因为把左边的 减项移到右边变 加项, 应该对啊 !?
可是,
如果 millis( ) 前进到 Overflow 之时就不相同 !!其实也不是 millis( ) 本身 Overflow 或 RollOver 归零(变成 0)之时出问题!
严格说是当 millis( )  前进到 unsigned long 最大数的一半时大约24天半之后就会开始出问题!!
因为它的问题是出在 start + dtms 这运算 !
並不是出在 millis( ) 本身是否 Overflow !!!

先別管为什么 !
直接测试最准啦, 可是如何测试呢?
总不能等到 millis( ) 快要 Overflow 吧,
那要將近 50天ㄟ! (或是等一半 24.8天也受不了!)

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

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

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

回复 支持 反对

使用道具 举报

发表于 2015-4-5 16:34:30 | 显示全部楼层
tsaiwn 发表于 2015-4-5 16:30
为何说原则上millis()溢出归零是没问题,
但是如果程序码没写好则有问题 ! 因为问题並不是出在  ...

可否偷改 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( ); // 允许中断
}
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-7 23:33 , Processed in 0.043025 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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