成为订阅者(免费)

加入29,000名其他订阅者以获得用户销售折扣和 其他免费资源。
:
:
大学教师'担心 - 您的邮件地址完全是 安全的。我保证使用它 只要 to send you MicroZine.

如何使用Arduino Millis()


arduino millis()函数是一个非常有用的函数,返回a 自重置以来表示毫秒的数字。在此页面上,您可以找到 如何为事件时间和延迟有效地使用它,以及 学习它如何详细运作。

使用Arduino Millis作为延迟计时器

Millis()函数以毫秒为单位返回当前时间 (1/1000 TH. 一秒钟)从电源电源电源时(或重置 它)。它为您提供了一种从您的程序中测量时间的方法,这 与延迟()函数完全不同,它根本没有关于时间的反馈。

警告: arduino. Millis使用定时器中断,中断必须打开。

测量使用Millis()的时间段只是将当前时间进行比较的问题 存储在变量中的时间值。当你不断绕过循环 执行一个简单的数学: 

Millis() - 存储_time

这为您提供了从毫秒的经过时间"stored time value".

此操作显示在下面的伪代码中:

环形
   ...
   // An event happens
   if(事件== true)存储_time = millis();
   ...
   Elapsed_time = millis() - 存储_time;
   ...
END_LOOP

上面的伪代码段导致变量"elapsed_time" 由于事件发生以来,测量时间以毫秒为单位。一个事件可能是一个 按钮按或从程序的另一部分中按操作。

也许你想以第二间隔发送串行消息 这种情况事件将是消息传输,您将等到 在发送下一个之前经过的时间大于1000(1000ms = 1秒) 串行消息(再次存储时间)。

毫米()函数由毫秒计时器中断驱动 每次激活并返回值时,才会递增无符号 of that variable.

arduino. Millis LED闪烁

以下示例显示了如何使用Millis()来给出非阻塞 延迟。非阻塞延迟是允许其他代码的延迟类型 即使在其他地方存在延迟运行,也运行。这是非常的 不同于使用该功能"delay()"您的代码停止处理的地方 (中断除外)并没有任何用途对于延迟持续时间有用 period.

下面显示的伪代码给出了500ms的非阻塞延迟 反复触发延迟。这向您展示了如何创建一个 Arduino Millis定时器可以具有任何长度的延迟时间( 高达49.7. days )。


    if ( (millis()-oldtime) > 500) {
       oldtime =  Millis() ;

      // Do something every after 500ms

    }
对于每12小时的动作,您将使用(12 * 60 * 60 *的延迟间隔 1000)= 43200000ms更换500带43200000L(L表示长值 到了Comiler)。有几天,您需要更多毫秒的千分之一。需要3天 (3 * 24 * 60 * 60 * 1000)= 259200000L再次更换500,259200000L更换500。到 停止重复动作看到 这里 .

示例1:延迟代码

#define LED 13

void setup (void) {
   pinMode(LED,OUTPUT);
}

void loop(void){
static uint8_t tog=0;
static  UINT32_T.  oldtime=millis();

    if ( (millis()-oldtime) > 500) {
       oldtime = millis();

       tog = ~tog; // Invert
       if (tog) digitalWrite(LED,HIGH); else digitalWrite(LED,LOW);

    }
}
[Millis-Blink]

代码操作:Arduino Millis延迟 operation

上面的Arduino代码显示了循环函数,在这种情况下是 唯一需要的代码;根据您的情况,使setup()函数的内容为空't 需要初始化任何我。你不'T需要启动串行端口或 在这种情况下SPI接口。

循环代码操作:用于非阻塞延迟

旧时间的值被设置为毫秒()的值。如果是 Millis()的价值每毫秒增加,大于500 高于Oldtime的计数,那么IF语句中的条件表达式 变成真。这意味着自从旧时间的价值以来的500毫秒 被设置为I.E.延迟为500ms。

在if-stallate的身体内,LED从其之前切换 状态。这意味着LED以1Hz的速率闪烁(500ms,500ms) or once a second.

自毫米()仅由条件的IF语句测试,您可以添加 循环中的其他代码可以执行其他有用的工作i.e.使用Arduino Millis() 以这种方式不会阻止处理器。

提示: 您在if-dispolate中设置了旧时间是至关重要的 到当前毫米()值,以便可以执行下一个延迟时间 否则IF-STALEX表达式在第一次之后将始终如此 表情变得真实。

笔记: 类型 UINT32_T. is the same type as "无符号 long"。 UINT32_T用于嵌入式编程为 它直接指定类型中的位数,而"unsigned long"可能对不同编译器具有不同数量的比特。

arduino. Millis限制

那么你可以衡量多久(你为什么要关心?)。毫米()函数返回一个 魔术号码出现在Arduino代码的深处,但作为工程师 您需要知道它是什么以及它是如何创建的。你需要知道因为 所有系统都有限制,以其绊倒,使系统失败。

可以测量的最长时间取决于所使用的变量类型 存储毫无符号长期和使用此类型的Millis()数据允许 你才能衡量49天。如果您的项目永远不会持续 那时49天然后你不't have a problem.

对于arduino,来自Millis()的最大值是:

4,294,967,295或(0xffffffff)

这是因为Arduino Millis数据类型是:

无符号 long (which can also be written as uint32_t)...

...... 在其中,您可以更轻松地看到类型中的位数。

Millis()的最大天数

计数 那个毫无符号的长期有能力 持有是:POW(2,32)-1或4,294,967,295或40亿294万967 千和295.所以,如果每个计数都值得一毫秒,那么有多少天 is that?

首先划分1000秒,然后乘60分钟,然后乘60分 几个小时然后24天=〜 49.71天 .

大约50天(或超过49.7天)的定时器包装 舍入到零,这是Arduino Millis溢出问题。

笔记: arduinos可以具有谐振器(3针)而不是a 晶体(2针)和这些不像晶体那样准确。

如果您正在设计一个必须时间超过49天的项目 这可能会导致问题,因为在包装周围,时间 以毫秒逐渐增加,突然转到零。如果你 在49.71天后使用Millis()录制了数据记录设备的时间戳 时间戳将返回开始时间即是错误的。

另一个问题正在使用计时器进行延迟。闪光灯,在哪里 你等待定时器到达当前时间加500ms说,如果是计时器 包裹在该500ms内,然后等待的时间是50天 有点很久了闪光的LED!

(但是看 以下 解决这个问题的解决方案)。

提示: 如果您想超越50天,请添加另一个变量 这在unsigned long前面的额外位起作用。一个无符号的炭 将延长256 * 50天。每次毫无时间()时间都会增加它 缠绕在一起。缺点是您需要包含8位 在所有时间计算中的数量,所以您需要自己制作"greater than" operation etc.

如何避免Arduino Millis溢出

让我们说你想要每100毫秒重复动作。所以你写下类似的代码:

    // LED Flash
    if ( (millis()-ledtime) > 100) {
       ledtime =  Millis() ;

       tog = ~tog; // Invert
       if (tog) digitalWrite(LED,HIGH); else digitalWrite(LED,LOW);
    }

通常你只是假设董事会并没有真正留下来 大于〜50天!所以你不'真的考虑溢出。让我们 考虑一下,看看在这种情况下会发生什么。

毫米()溢出解决方案

以下解决方案避免了溢出问题,但仅当您的情况下 完全按照所示写入时间释放部分 - 如果您倒换 术语或移动它们,您将使它失败!

可以避免溢出,但仅用于测量时段更小 比最大溢出时间(用例),这是由于一个属性 数字如何存储在内存中..模数算术和整数的方式计算。为了 unsigned long 4字节是 used.

在Modulo Maths中,(在C modulo中由符号%的百分比表示) 例如,值的约束为1少于模数:

9%10返回9

但10%10返回0

相似地

19%10返回9

和20%10返回0

数字包裹,这正是如何解决溢出的 问题。但它而不是实际调用模数运营商它是 由于4字节内存存储器的约束,已处于活动状态 毫无符号。因此,unsigned long自动将值从0从0到pow(2,32)-1。

由于整数数字也使用两个'S补充表示,您在减去和添加时获得正确的数字。

毫无符号 millis溢出的例子

让我们说LEDTETE设置为unsigned long的最大值:

LEDTIME = 0xFFFFFFFF或POW(2,32)-1或4294967295

这意味着当下一个超时检测然后millis()时 将重新加回积极的价值,让我们说毫米()返回值1 下一个检测然后用于正常数学:

Millis() - LEDTIME == 1 - 4294967295 = -4294967294

TwoS补充和Modulo Maths意味着毫无符号这代表:

-4294967294 == 2

所以即使毫米()值小于米兰()值,这是正确的答案 LEDTIME的实际价值。 Twos补充数学意味着$ fffffff是 解释为负数($ fffffff == -1)。所以:

LEDTIME(1) - ($ FFFFFFFF)==(1) - (-1)== 2。

因此,定时器检测代码已以溢出忽略的方式编写!

...... ...用警告,这种方法只能准确测量 三角一句数和代码必须如下写入:
if ( (millis()-ledtime) > 100) 

时间转换 Arduino millis

arduino millis到几秒钟

自毫升以来,自毫秒是毫秒和米利的工程术语 代表1/1000,一秒钟内有1000毫秒。因此到 计数秒划分米兰1000。

秒= millis()/ 1000;

通常,您将希望在一秒钟的级分中使用Millis()。为了 使用ON / OFF将MILLIS()闪烁每400ms闪烁每400ms 每200ms切换,导致400ms的时间段。

arduino millis到几个小时

如果您想在使用Arduino Millis作为您需要的计时器时出入小时 做更多的部门:

分钟=(Millis()/ 1000)/ 60;

小时=((millis()/ 1000)/ 60)/ 60;

Arduino millis to Days

整整一组时间值都在这里:

天=小时/ 24;

小时=分钟/ 60;

分钟=秒/ 60;

秒= millis()/ 1000;

如前所述,以前是变量 能够 only have a maximum value of 49.7 days.

笔记: 几个小时以来。几分钟和秒和日子只能有 最大值低于255,您可以为上面的每一个使用类型UINT8_T 数量。 uint8_t是一样的"unsigned char".

arduino. Millis VS延迟

让我们只是在这个讨论开始时说 - "Don't Use delay()". This 会节省你的时间。阅读以了解为什么...

arduino. Milis()是一个中断驱动的功能,这意味着它永远 当您的代码正常工作时,在后台运行。中断用于 更新毫米()输出的值,以便在每毫秒之后 价值将增加一个。您可以访问Millis()的当前值 任何时候只需通过调用毫米()函数并将结果放入 您自己的无符号长变量(或者您可以将Millis()输出进行比较 another constant).

另一方面的函数延迟()不是中断驱动但只是 causes a "Do Nothing"循环执行浪费处理器时间 - 它没有 返回任何值。函数延迟()取决于中断驱动的输出 从Timer0。因此,延迟()无法在中断服务中使用 由于ISR内的例程是中断。

由于它不是中断驱动,因此没有其他代码可以运行 - 它只是 有效地阻止处理器在依靠a时做任何其他事情 delay time.

笔记: 以上讨论正在谈论主代码 操作 - 中断仍然中断主代码并操作e。定时器或I2C. 接口等。仍然有效。
笔记: Millis() 并不总是递增 one 由于在中断例程中计算定时的方式。 该链接将您带到本页中的Millis()的详细仿真。

arduino. Millis不准确

不它不是!好吧,它做得很好。

有两个原因:

  1. 时钟源 - 所有基于晶体振荡器的系统都是如此 但是一些arduino板使用谐振器,这些谐振器表现比a更差 crystal.
  2. 实施 - 一般标准晶体偏振频频率 对人类来说很容易读取e.g.16MHz不可分割的十进制 number so you can't获得精确的输出周期。 Arduino代码调整 使用校正算法的此问题。

原因一 - 时钟源

arduino. Millis()不准确,这是一个原因是Arduino 板有时安装了16MHz谐振器。这是一个廉价的振荡 大多数应用程序都可以的组件。它会漂移 温度,但总是大约为16MHz。

如果您正在寻找准确性,您需要一个带有水晶的Arduino 板(或使用晶体构成自己的裸骨版本)。你可以判断是否 您的谐振器仅具有三个引脚设备,而谐振器仅具有谐振器,而晶体 are two pin devices.

问题是复古贴合水晶(它可以完成!)到Arduino 板需要两种额外的组件使水晶正确地振荡 (需要电容负载)。这些是两个电容器,每个电容器都连接到 晶体的一个销和接地。它们的范围从12pf到33pf - 检查 对于制造商指定的正确电容器 - 或者只是使用夫妇 15pf。您当然还需要将晶体连接到时钟输入 微控制器(与谐振器相同的连接 - 但不是中间 ground one).

一个更好的解决方案 是使用外部RTC

晶体的准确性被指定为ppm,通常约为100ppm (32khz Watch Crystal可以到达20ppm - 对微控制器不多使用 除非您需要低功耗操作)。

如果您真的需要准确的时间戳,那么使用传动的计时 芯片(廉价的2PPM One是DS3232)。这不会输出直接的时钟 使用微控制器,以便您可以保留谐振器并使用 DS3232 作为准确的时间戳设备。

原因二 - 计时器0 implementation

第二个原因并不是真的那么Arduino Millis不准确(它 变得准确),但更多关于执行计时器的实现 聪明但会导致一个小抖动。毫秒计时器的中断 (在线中使用定时器0)使用预分频器将主时钟分为16MHz 但是计时器的输出通过少量(你不能划分a 16MHz时钟使用除以2分频器硬件进行精确毫秒 输出 - 最接近您可以获得的是1024us)。当错误得到错误时 校正因子用于调整定时器值。

因此,在长期内,Millis()计时器是准确的,但在短期内 可能少量少。

Millis()在Arduino工作如何

Millis()计时器的代码位置:

    C:/程序文件(x86)/ darduino/hardware/arduino/avr/cores/arduino/wiring.c

如果您有一个32位机器(上面的64位),则路径将是:

    C:/程序文件/ Arduino /硬件/ Arduino / Avr / Cores / Arduino / Wiring.c

Timer0中断时钟周期

定时器0是设置的,以便它具有64的预分频器。它是一个8位计时器 每256个计数溢出。因此,对于16MHz时钟,重复时间 定时器0是(1.0 / 16E6)* 256 * 64 = 0.001024,其中1024个,接近1ms但 not actually there.

Millis()操作

在每个中断1024us中,毫米()计时器递增。 由于1024US大于1000us,毫米()计时器太慢并且需要纠正。

这个想法是存储错误和 积累它直到它超越阈值,在此 毫秒计时器输出已更正。

    以便纠正1毫秒输出,
    需要更正之前的中断次数是:

        1000.0/24 = 41.66.

上述等式表示加起来的24us时段的数量 在41.66之后的1ms I.中断错误将是1ms。当然你 can't得到41.66个中断所以你必须等待以下 中断检测误差大于1000us。这将是 当发生了42个中断时。

算法的巧妙部分是误差累加器是 递增24每个中断(未执行该部门 - 即 只是让你看看这个想法)。当此变量大于41.66 * 24时 即42 * 24 = 1008然后纠正错误。

下一个真的,真的,算法的聪明部分是 错误变量未重置为零 - 您只需减去1ms值 (因为这是纠正的)留下了错误的最后一个值 在累加器中,这将是8个。那么这个错误就是 再次累积,并且在误差更大时再次调整毫米()计时器。

从下面的分析到米兰()计时器将是 连续纠正,不超过2ms的错误(参见下面的仿真和实际输出结果)。

您可以通过查看代码进一步探索这一点 如下所述。有一点要注意的是,这些值适合 BYTES,因为它们都是8的倍数(但这仅适用于16MHz和8MHz clocks):

    1024.0 / 8 = 128.0; 1024.>>图3是正好128 i.e.适合字节。

    1000.0 / 8 = 125.0; 1000>>图3是正好125 i.e.适合一个字节。

        24.0 / 8 = 3.0    ;       24 >>3正好是3 i.e.适合字节。

这些数字用于下面的代码。

arduino. Millis()计时器0代码操作

校正中使用了两个变量和几个宏 definitions:

ClockCECLESPERMICROSECOND. gives a 16MHz时钟16的结果。

另外两个宏是:

Clockcyclestomicroseconds(a) =( (a)/ clockcyclespermicrosecond)

microSecondstoclockcycles(a) =( (a)* clockcetspermicrosecond)

在线内部在线中进行以下定义:

miclieconds_per_timer0_overflow. =
    ClockCyclestomicroseconds(64 * 256)= 16384/16 = 1024

由于ClizeClepermicrosecond是16


定时器0在256个预定时钟之后预定64并溢出 在64 * 256时钟周期后触发中断。

这只是表明它是一种简单计算的长蜿蜒方式 确实具有泛型的优点,因此它意味着不同的时钟a 将发生不同的结果。但代码评论状态:

//每小时的小数毫秒数 溢出。我们向右转
//三个以将这些数字符合到一个字节。 (对于我们关心的时钟速度
//约 - 8和16 MHz - 这一并不是't lose precision.)

所以评论说明了小数时间计算(下面) 工作8和8MHz和16MHz。

以下计算适用于16MHz时钟。

米兰inc. = ( microSeconds_per_timer0_overflow / 1000)= 1.024

以后使用后面将1.024插入到代码中的使用点 事实上,当unsigned long递增时,这将是值 incremented by one.

在线中的评论代码位置 ):

//每小时的小数毫秒数 溢出。我们向右转
//三个以将这些数字符合到一个字节。 (对于我们关心的时钟速度
//约 - 8和16 MHz - 这一并不是't lose precision.)


Fract_inc. = ( miclieconds_per_timer0_overflow%1000>> 3 )
    = 24 >> 3 = 3 (16MHz)

Fract_max. =( 1000 >>3 )
    = 125

用于执行上述右移的原因是这样的数字 fit into a byte.

三个变量用于Millis值的校正和输出 (timer0_millis - 下面)。

无符号 long timer0_overflow_count - 仅用于微秒 calculation.

无符号 long timer0_millis. - the Millis()的值输出。

字节 timer0_fract

每次中断:

Timer0_millis增加 米兰inc. (或1) - 这是毫米()输出值。

Timer0_fract增加了 Fract_inc. (or by 3).

timer0_overflow_count增加一个 - 这是 不调整的Timer0中断计数。

如果必要的话,对Timer0_Millis进行校正 当累积的错误变得太大时。

中断代码(ISR) TIMER0

以下代码包含在中断服务例程中 执行毫秒更新,该更新更新了最后3个变量 全局。变量 timer0_millis. 是返回的价值 millis() function.

中断载体的分数调整:

// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
无符号  m = timer0_millis.;
无符号 char f = timer0_fract.;

m +=  米兰inc. ;
f +=  Fract_inc. ;
if (f >=  Fract_max. ) {
    f -=  Fract_max. ;
    m += 1;
}

timer0_fract. = f;
timer0_millis. = m;
timer0_overflow_count++;

在上面的代码中,m和f被定义为允许的局部变量 编译器使用更快的寄存器(检查其实际发生 检查输出汇编程序代码)。

分数动作是,如果timer0_fract比 Thefact_max(125)然后通过减去FRACT_MAX并增加TIMER0_MILLIS (>=自125起不到3的倍数。

因此,每次中断火灾时,都会添加3,直到累积 错误(timer0_fract)更大或等于125,它将是time0_fract时 第1达到126或42个中断呼叫。用时间段调用中断 因此,1024微秒为毫秒校正之前的时间 是42 * 1024 = 43008us。

因此,您将修正Arduino毫秒计时器 ~43ms.

由于Timer0中断运行慢毫秒计时器是 每〜43ms递增1

在校正1之后第一次绕循环留在Timer0_fract中。

第二次2留在Timer0_fract中。

因此,小数误差最终会得到纠正>125 times ~43ms.

TCL模拟

以下TCL程序模拟中断代码的操作 Timer 0:

proc sim_arduino_timer0 {} {

console show
set c 0

 set timer0_millis. 0
 set timer0_frac 0
 set  米兰inc.  1
 set  Fract_inc.  3
 set  Fract_max.  125
 set m 0
 set f 0

 set line ""

 for {set i 0} {$i<1100} {incr i} {

    puts "$m $f"

    set m [expr $m + $MILLIS_INC]
    set f [expr $f + $FRACT_INC]
       if {$f >= $FRACT_MAX} {
          set f [expr $f - $FRACT_MAX]
           在 cr m
       }
    }

  update idletasks

}

sim_arduino_timer0

其中一些输出它会衰退 is shown 下面(左是毫无毫升,右边是小数部分)。:


0 0
1 3
2 6
3 9
4 12
5 15
6 18
7 21
8 24
9 27
10 30
11 33
12 36
13 39
14 42
15 45
16 48
17 51
18 54
19 57
20 60
21 63
22 66
23 69
24 72
25 75
26 78
27 81
28 84
29 87
30 90
31 93
32 96
33 99
34 102
35 105
36 108
37 111
38 114
39 117
40 120
41 123
43 1
44 4
45 7 

第一次调整是毫米输出处于42和分数时 部分刚刚通过了125.代替预期的42次调整 输出43的输出代替i.E校正算法跳过42次和 因此,Millis()根本不会输出42的值。大约每42毫秒这个 再次进行校正。

Arduino 显示毫米和微量输出的程序

下一个程序显示Arduino Uno的实际输出。这是 实际硬件上的物理结果显示毫秒抖动 42 ms.

该程序采用当前毫米()和micros()计时器的样本 输出值尽可能快地发送到串行终端。

它以来输出多个结果,因为中断计时器是 异步到主循环代码i.e。你不 '知道它什么时候会 更改,因此要查看更改,您必须使循环更快地运行 毫秒计时器(因此终止输出的高波特率和更高的样本号2100)。

void setup() {
  Serial.begin(230400);
}

void loop() {
static 无符号  在 t c=0,stop=0;
unsigned  mil,mic;

// Note Reduce this parameter the more is done in the loop! 
// for 3~4 outputs per loop iteration // delayMicroseconds(50);
if (c<2100 && stop==0) { c++; mil = Millis() ; // Capture as close together as possible mic = micros(); Serial.print( mil ); Serial.print(" "); Serial.println( mic ); } else stop =1; }

下表显示了左侧的毫米()和右侧的micros()。
相关部分在这里(Millis()== 42的第一次调整):

40 41164
40 41604
41 42040
41 42480
41 42920 *** millis skips a beat here
43 43368 ***
43 43808
44 44244
44 44684
45 45132
45 45572
45 46016
46 46460
46 46892
47 47340

micros()值是4us 不准确的所以比Millis()好多了。观察过渡点 在42(预期值:42未在Millis()AT 全部)即它与模拟输出相同 which is reassuring!

您还可以看到Millis()输出正常出现 转换I.E.阅读Millis()在第41次变化意味着您应该阅读 从42.0到42.9,而是你得到41(最糟糕的价值就在之前 调整毫米()输出41ms和实际时间为42.9ms。

您将跳跃随着校正因子而添加,因此毫米()函数 从不输出42ms,而是作为下一个结果输出43 - 这带来了 Millis()输出与正确的时间转回对齐。这种纠正 过程重复毫米()正在运行。

然而,42的校正因子 n 中断纠正 Millis()输出到Millis()输出43.3,因此在长期内毫秒 定时器是准确的。调用围绕正确输出的振荡 jitter.

arduino. 的其他价值 Crystal Clock

代码(微秒延迟)的其他地方会谈以下内容 frequencies:

'假设1,8,12,16,20或24 MHz'

(24MHz时钟用于超频 - 做没有由此指定的东西 data sheet).

问题是:Millis()会准确吗?

下列 结果表明,对于大多数情况而言,毫米()输出将准确但不是 12,20和24MHz。您需要更改Arduino的操作 代码使Millis()输出准确的结果。

microdeconds每个timer0溢出:

(64 * 256.0)/ 1 = 16384 - 1MHz - 没有错误。 

(64 * 256.0)/ 2 = 8192 - 2MHz - 没有错误。 

(64 * 256.0)/ 4 = 4096 - 4MHz - 没有错误。 

(64 * 256.0)/ 8 = 2048 - 8MHz - 没有错误。  

(64 * 256.0)/ 12 = 1365.33 - 12MHz - Millis()会有错误。

(64 * 256.0)/ 16 = 1024 - 16MHz - 没有错误。

(64 * 256.0)/ 20 = 819.2 - 20MHz - Millis()会有错误。

(64 * 256.0)/ 24 = 682.66 - 24MHz - Millis()会有错误。

下面的计算是FRACT_INC(microSeconds_per_interrupt%1000)>> 3

频率(MHz)
Fract_inc增量
1
48
2
24
4
12
8
6
12
45(不准确的Millis O / P)。
16
3
20
102(不准确的Millis O / P)。
24
85(不准确的Millis O / P)。

注意:观察使用频率不是精确的频率时,如何爆炸 Timer0预分频器和溢出结果的因素。自预缩放者和定时器以来 使用8或16位,它遵循该方案,时钟频率必须是a Base2值I.E.1,2,4,8,16,32等

笔记: 在较低的水晶频率下,Fract_inc的值是 较大但是换档右值1000毫秒计算仍然相同 - 它的值为125 - 适合一个字节)。因此,抖动很远 使用较低频率即将更大。毫秒钟将更加纠正 经常。例如对于16MHz 125/3是41.6但是125/48是2.6 - 所以在16MHz时钟 每42毫秒校正每42毫秒,每3毫秒纠正。

What happens if 你很长时间使用Arduino Millis吗?

如果你决定 to use a "long" type 比较存储变量的定义,那么您正在使用签名 数量而不是MilliS()函数输出的数量。

如果您要使用计时器"long"并输出长使用的值 串行命令(或将整数质量转换为字符串的任何命令) such as:

serial.println(计时器);

...... 在计时器指定为长期和更新的情况下,可能是秒:

Timer = Millis()/ 1000;

然后在代码的操作中的某个点(当计时器到达时 中点)Millis()的无符号输出的最左侧位将变高 并且打印功能将解释该符号位。因此它将 输出负数和arduino millis()变为负(或似乎是 消极的)。对于签名计算,该值被解释为负数 打印功能可作为签名质量处理,因此输出A. negative number.

尝试Arduino中的代码

 UINT32_T.  ulong;
int32_t slong,minus1,plus1,s1;
void setup(void) {

    Serial.begin(115200);

    minus1 = -1;
    plus1 = 1;

    Serial.println("\n Observe plus 1");
    s1 = plus1;
    ulong = (unsigned ) s1;
    Serial.print(" signed plus 1 dec :");Serial.println(s1);
    Serial.print(" signed plus 1 hex :");Serial.println(s1,HEX);
    Serial.print(" unsigned plus 1 dec :");Serial.println(ulong);
    Serial.print(" unsigned plus 1 hex :");Serial.println(ulong,HEX);


    Serial.println("\n Observe minus 1");
    s1 = minus1;
    ulong = (unsigned ) s1;
    Serial.print(" signed dec :");Serial.println(s1);
    Serial.print(" signed hex :");Serial.println(s1,HEX);
    Serial.print(" unsigned dec :");Serial.println(ulong);
    Serial.print(" unsigned hex :");Serial.println(ulong,HEX);

    Serial.println("\n suppose millis() reaches unsigned value 0xffffffff-1");
    Serial.println(" Observe the signed value");
    s1 = () (0xffffffff-1);
    ulong = (unsigned ) s1;
    Serial.print(" signed minus 1 dec :");Serial.println(s1);
    Serial.print(" signed hex :");Serial.println(s1,HEX);
    Serial.print(" unsigned dec :");Serial.println(ulong);
    Serial.print(" unsigned hex :");Serial.println(ulong,HEX);

    Serial.println("\n Observe signed value of 0x7fffffff - no problem");
    s1 = () (0x7fffffff);
    ulong = (unsigned ) s1;
    ulong = (unsigned ) s1;
    Serial.print(" signed dec :");Serial.println(s1);
    Serial.print(" signed hex :");Serial.println(s1,HEX);
    Serial.print(" unsigned dec :");Serial.println(ulong);
    Serial.print(" unsigned hex :");Serial.println(ulong,HEX);

    Serial.println("\n Observe signed value of 0x80000000 (The sign bit)");
    s1 = () (0x80000000);
    ulong = (unsigned ) s1;
    ulong = (unsigned ) s1;
    Serial.print(" signed dec :");Serial.println(s1);
    Serial.print(" signed hex :");Serial.println(s1,HEX);
    Serial.print(" unsigned dec :");Serial.println(ulong);
    Serial.print(" unsigned hex :");Serial.println(ulong,HEX);
}

void loop(void) {
}

这是你的结果'll get:


 Observe plus 1
 signed dec :1
 signed hex :1
 unsigned dec :1
 unsigned hex :1

 Observe minus 1
 signed dec :-1
 signed hex :FFFFFFFF
 unsigned dec :4294967295
 unsigned hex :FFFFFFFF

 suppose millis() reaches unsigned value 0xffffffff-1
 Observe the signed value
 signed dec :-2
 signed hex :FFFFFFFE
 unsigned dec :4294967294
 unsigned hex :FFFFFFFE

 Observe signed value of 0x7fffffff - no problem
 signed dec :2147483647
 signed hex :7FFFFFFF
 unsigned dec :2147483647
 unsigned hex :7FFFFFFF

 Observe signed value of 0x80000000 (The sign bit)
 signed dec :-2147483648
 signed hex :80000000
 unsigned dec :2147483648
 unsigned hex :80000000

你可以看到符号位非常重要(左列最左侧)和如果 您使用签名类型您将获得负输出数字,甚至 虽然未签名的版本是正确的,但它具有预期的位值 - 或 hex value shown.

还显示了翻转点,使用签名长度可以直到你 达到2147483647(0x7fffffff)添加一个到那一个,你得到-2147483648 (0x80000000)。在日子方面,计时器似乎对〜 25天 然后在负输出中添加一个结果。 毫米()覆盖的天数的解释 这里 .

在处理时使用无符号长(UINT32_T)的简单方法 millis().

更多例子

如何使用Arduino Millis进行单次计时器

此代码仅在设定时间后执行一个串行输出操作动作 然后停下来。虽然使用Arduino Millis()允许其他操作继续 即,LED保持闪烁,但只输出一条消息。

#define LED 13

void setup(void) {

     Serial.begin(115200);
     Serial.println("Simple Scheduler");

     pinMode(LED,OUTPUT);
}

void loop(void){
static uint8_t tog=0,s1done=0;
static  UINT32_T.  ledtime=  Millis() ,s1=ledtime;

    // LED Flash
    if ( (millis()-ledtime) > 500) {
       ledtime =  Millis() ;

       tog = ~tog; // Invert
       if (tog) digitalWrite(LED,HIGH); else digitalWrite(LED,LOW);
    }

    // 3 second message - one shot
    if ( !s1done && (millis()-s1) > 3000) {
       s1 =  Millis() ;
       s1done = 1;

       Serial.println("-3- SECONDS ONE SHOT ONLY");
    }
} 

How to 使用Arduino Millis制作一个简单的调度程序

这个Arduino Millis的目的是制作一个简单的调度程序 算法在不同时间开始不同的动作。这只是一个简单的 示例,您可以找到传输操作的多任务调度程序 不同的任务保存变量,以便可以中断任务停止和 重启。还将有允许沟通的标志的概念 在任务之间。这个简单的例子绝对不是那种类型,但它可以是 useful nevertheless.

#define LED 13

void setup(void) {
     Serial.begin(115200);
     Serial.println("Simple Scheduler");

     pinMode(LED,OUTPUT);
}

void loop(void){
static uint8_t tog=0;
static  UINT32_T.  ledtime=  Millis() ,s1=ledtime,s2=s1,s3=s1,s4=s1;

    // LED Flash
    if ( (millis()-ledtime) > 500) {
       ledtime =  Millis() ;

       tog = ~tog; // Invert
       if (tog) digitalWrite(LED,HIGH); else digitalWrite(LED,LOW);
    }

    // 10 second message
    if ( (millis()-s1) > 10000) {
       s1 =  Millis() ;

       Serial.println("10 SECONDS");
    }

    // 5 second message
    if ( (millis()-s2) > 5000) {
       s2 =  Millis() ;

       Serial.println("five SECONDS");
    }

    // 3 second message
    if ( (millis()-s3) > 3000) {
       s3 =  Millis() ;

       Serial.println("-3- SECONDS");
    }

    // 2 second message
    if ( (millis()-s4) > 2000) {
       s4 =  Millis() ;

       Serial.println("*2* SECONDS");
    }

} 

使用Arduino Millis计划偏移的初始时间

提示: 避免同时发生的一切 初始条件从每个OTHE抵消。

您可以抵消每个计时器的开始时间,以便它们不是1000的倍数,因为如果 然后,它们会在同一时间和串行输出的情况下或多或少地发射 将生成,串行输出需要一点时间,从而改变 发生后续时间匹配的实际时间。

例如,您可以编写以下初始化(随机使用 offsets):

static  UINT32_T.  ledtime=millis(),s1=ledtime+66,s2=s1+90,s3=s1+187,s4=s1+231;

这意味着每个定时输出的起始时间偏离 彼此 - 只有开始时间 - 随后的重复时间将是 在代码中指定的重复时间 - 它们仍将偏移,以便它们会 没有发生在完全同时。

所以处理器不必做到 与每个超时的操作同时关联的动作。因此代码会 操作更顺利,不必做大加工Burp!


新的! Comments

让你说到你刚刚阅读的东西!留下下面的框中的评论。




隐私政策 | 接触 | 关于我

网站地图 | 使用条款


 ezoic. 报告此广告

访问我们的Facebook页面:

    点击这里



最近的文章

  1. 如何使用ADS1115

    使用ADS1115精度16位ADC进行教程进行低功耗。

    阅读更多

  2. arduino. 模拟输出...易模拟输出生成

    arduino. 模拟输出:如何创建最精确的PWM模拟输出以及如何创建模拟PWM正弦波。

    阅读更多

  3. 数号和等效的快速宏。加快代码!

    了解DigitalWrite()的工作原理......现在使用17倍宏宏!

    阅读更多

  4. TCS230颜色传感芯片:如何运作以及如何使用它。

    如何使用TCS230(/ TCS3200)彩色检测器芯片并轻松将其添加到您的任何项目中。

    阅读更多

  5. 如何使用ADXL345进行运动感测等。

    使用ADXL345 Acellerometer,您可以检测到16G!您还可以了解如何使用它来点击检测等。

    阅读更多

  6. HMC5883L 3轴数字MAGENTOMTER如何运作

    HMC5883L - 如何制作数字罗盘,了解HMC5883L和QMC5883L之间的差异以及它们是否兼容。

    阅读更多



读者 Comments

"I wanted to thank
你这么好
对于所有信息
你已经提供了
你的网站's

高超 极好的 ."

- 逃亡Potthath.

"This site really is
最好的和我最喜欢的。
我发现这里有很多很有用
项目和提示。"

- 米兰

Bursach.<at>gmail.com<

"Awesome site,
非常,非常容易和好
导航!"


-
Matt_tr. <at>
wolf359.cjb.net.


学习微控制器

"Interested in
微控制器?"

注册
免费7天指南:

自由 GUIDE : CLICK HERE


"I am a newbie to PIC
我想说
 how great your
网站一直在为我。"


- 戴夫

de_scott.<at>bellsouth.net

"Your site is a great
和完美的工作。
恭喜。"


- SURESH.

IntegratedInfosys.<at>
Yahoo.com.

"I couldn't find the correct
要定义的词语
你的网页。

非常有用,揭开,
诚实明确。

非常感谢
你的时间和作品。
问候。 "


- Anon.

回到顶部