99uuuu 发表于 2015-4-4 20:46:56

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

unsigned long zhongduan1=6000;
#include <LiquidCrystal.h>
#include <SD.h>
// CS引脚为pin4,这里也沿用官方默认设置
const int chipSelect = 4;//设定CS接口
int GP2D12 = 0;//把夏普GP2D12红外测距传感器连接在模拟量端口0
int val;   //存储从GP2D12红外测距传感器读到的值   
float temp;//存储由传感器读取值,通过算式处理后的浮点型距离值
int distance;//存储由传感器读取值,通过算式处理后的整数型距离值
float dataString;

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

void loop()
{
    unsigned long nowtime=millis(); //获取当前的系统运行时间长度
    if(nowtime>zhongduan1)    //检测系统运行时间长度
{
   // 读取1个传感器值,写入数组
for (int GP2D12 = 0; GP2D12 < 1; GP2D12++) {
    int sensor = analogRead(GP2D12);
    dataString = 2547.8/((float)val*0.49-10.41)-0.42;
}
   // 打开文件,注意在同一时间只能有一个文件被打开
// 如果你要打开另一个文件,就需要先关闭前一个
File dataFile = SD.open("datalog.txt", FILE_WRITE);
// 打开datalog.txt文件,读写状态,位置在文件末尾。
if (dataFile)
{
    dataFile.println(dataString);
    dataFile.close();
    // 数组dataString输出到串口
    Serial.println(dataString);
}
// 如果无法打开文件,串口输出错误信息error opening datalog.txt
else {
    Serial.println("error opening datalog.txt");
      }
zhongduan1=nowtime+60000;
    }
    lcd.clear();
//读取GP2D12红外测距传感器模拟量数据
val = analogRead(GP2D12);
//通过以下算式,把传感器读取值处理成浮点型距离值
temp=2547.8/((float)val*0.49-10.41)-0.42;
//lcd.clear();//LCD清屏
// 定位光标在LCD第0行、第0列
//lcd.setCursor(0, 0);
//在LCD第0行第0列开始显示"Distance:"
// lcd.print("Distance:");
// 定位光标在LCD第1行、第7列
//lcd.setCursor(7, 1);
//如果传感器读取值大于80或者小于10,
// if(temp>80||temp<10)
      //{
      //则在LCD第1行、第7列开始显示"OverRange"
      // lcd.print("OverRange");      
   // }
   //如果传感器读取值在10到80之间,
//else
   //   {      
      //把浮点型距离值取整
      //distance=temp;
      //则在LCD第1行、第7列开始显示距离值
       // lcd.print(distance);
      //在距离值后显示单位"cm"
      //lcd.print("cm");
lcd.setCursor(0, 0);
//在LCD第0行第0列开始显示"Distance:"
lcd.print(dataString);
// 定位光标在LCD第1行、第7列
lcd.setCursor(7, 1);
   //则在LCD第1行、第7列开始显示距离值
       lcd.print(temp);
      //在距离值后显示单位"cm"
      lcd.print("cm");
   delay(1000);
}

99uuuu 发表于 2015-4-4 22:37:18

问题已解决

tsaiwn 发表于 2015-4-5 16:19:48

99uuuu 发表于 2015-4-4 22:37 static/image/common/back.gif
问题已解决


已解决 ??
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; )

tsaiwn 发表于 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 共要 4294967296milli seconds,
等於 4294967296 /1000 /60 /60 小时; 每天有 24小时,
所以等於 4294967296 /1000 /60 /60 / 24 天 = 49.710 天
也就是说, 开机后大约快要 50 天之时 millis( )会归零 !

tsaiwn 发表于 2015-4-5 16:30:20

tsaiwn 发表于 2015-4-5 16:19 static/image/common/back.gif
已解决 ??
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 程序测试看看吧 :-)

tsaiwn 发表于 2015-4-5 16:34:30

tsaiwn 发表于 2015-4-5 16:30 static/image/common/back.gif
为何说原则上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( ); // 允许中断
}
页: [1]
查看完整版本: 系统时间最长9小时22分钟,求大神帮我让这个程序在9小时22分后别乱