arduino延时最全解析。(完结)

2024-07-06

如有问题,可评论留言,制作不易,点个免费的赞和关注吧....

目录

1.阻塞式延时

1.1delay(ms); //延时多少毫秒

1.2.delayMicroseconds(Microseconds);//延时多少微秒

2.非阻塞延时

2.1millis()

2.2 micros();//返回程序自启动以来经过的微秒数

2.3 Timer 中断(硬件定时器);(推荐使用)

2.4 时钟模块延时

2.4.1实验现象

2.4.2 代码

单片机延时分为阻塞式延时和非阻塞式延时两种,Arduino也同样.

1.阻塞式延时

阻塞型延时是指程序在执行延时时,CPU处于等待状态,无法做其他事情。延时时间结束后,程序才会继续执行后续的指令。也就是整个代码卡主不动,只有延时结束后才正常运行

1.1delay(ms); //延时多少毫秒

delay() 函数接受一个 unsigned long 类型的参数。unsigned long 通常是 32 位无符号整数,Arduino IDE上,它的最大值是 4,294,967,295 毫秒(大约 49.7 天)

void setup() {

Serial.begin(115200);//串口初始化 115200波特率

}

void loop() {

delay(1000);//阻塞延时1000毫秒也就是1s

Serial.println("123");

delay(1000);

Serial.println("123");

}

上述demo你的程序会卡主不动实现1s执行一次指令的效果.

1.2.delayMicroseconds(Microseconds);//延时多少微秒

delayMicroseconds() 接受一个 unsigned int 类型的参数,Arduino 平台上,unsigned int 是 16 位无符号整数,因此它的最大值为 65535。也就是说这个函数只能延时65.535毫秒的延时.这点需要注意.

一般对某些传感器初始化延时的时候需要用微秒级别延时.

2.非阻塞延时

2.1millis()

返回程序自启动以来经过的毫秒数,不会阻塞程序,因此适用于非阻塞的时间控制。通常用来代替delay()实现更复杂的时间控制,避免程序停滞。

millis() 返回的是一个 unsigned long 类型的数值。unsigned long 类型在大多数 Arduino 平台上(如 AVR 系列 8 位微控制器)占用 4 字节,表示的数值范围是 0 到 4,294,967,295大约是 49.7 天。

demo:实现1s翻转一次板载LED灯的状态(主程序在不断打印,非阻塞延时)

unsigned long previousMillis = 0;

const long interval = 1000; // 1秒

void setup() {

pinMode(LED_BUILTIN, OUTPUT);

Serial.begin(115200);

}

void loop() {

unsigned long currentMillis = millis(); // 获取当前时间

Serial.println("123");

if (currentMillis - previousMillis >= interval) {

previousMillis = currentMillis; // 更新上次时间

digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // 切换LED状态

}

}

2.2 micros();//返回程序自启动以来经过的微秒数

返回自Arduino上电或复位以来经过的时间(微秒)。

它与millis()类似,但精度更高,适用于更精细的时间控制。

micros()的上线即大约 4,295 秒。

unsigned long previousMicros = 0;

const long interval = 1000000; // 1秒

void setup() {

pinMode(LED_BUILTIN, OUTPUT);

Serial.begin(115200);

}

void loop() {

unsigned long currentMicros = micros(); // 获取当前时间

Serial.println("123");

if (currentMicros - previousMicros >= interval) {

previousMicros = currentMicros; // 更新上次时间

digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // 切换LED状态

}

}

2.3 Timer 中断(硬件定时器);(推荐使用)

定时器延时更为常用,也能让你的代码更加清晰,为后续学习做基础。

关于定时器的相关内容,请看我之前的博客:一篇弄懂 TimerOne 操作arduino的定时器1-CSDN博客

这个demo和1.3.1 1.3.2的现象是一致的。

#include

volatile long ms_tick=0,ms_tick_flag=0;

void setup(void)

{

pinMode(13, OUTPUT);

Timer1.initialize(10);//精确度10us

Timer1.attachInterrupt(Interrupt_callback); // 定时器的中断回调函数

Serial.begin(115200);

}

void Interrupt_callback(void)

{

if(ms_tick_flag==0)

{

ms_tick++;

if(ms_tick>100000)//这里10*100000 也就是1s标志位置1.

{

ms_tick=0;

ms_tick_flag=1;

}

}

}

void loop(void)

{

Serial.println("123");

if(ms_tick_flag==1)

{

static boolean output = HIGH;

digitalWrite(13,output);

output =!output;

ms_tick_flag=0;

}

}

2.4 时钟模块延时

Arduino也可以使用时钟模块(如DS3231、DS1307等RTC模块)进行延时操作,通常用于实时计时和保持准确的时间,而不直接用于实现程序中的延时。不过时钟模块更多地是用于提供持续运行的时间信息,特别是在设备断电或重启后依然能够保持准确的时间。

2.4.1实验现象

以5s进行一次延时,其实理论上和millis()的原理类似,这里提供另外一个思路.

2.4.2 代码

// CONNECTIONS:

// DS1302 CLK/SCLK --> 5

// DS1302 DAT/IO --> 4

// DS1302 RST/CE --> 2

// DS1302 VCC --> 3.3v - 5v

// DS1302 GND --> GND

#include

ThreeWire myWire(4, 5, 2); // IO, SCLK, CE

RtcDS1302 Rtc(myWire);

RtcDateTime targetTime; // 用来记录目标延迟的时间

void setup()

{

Serial.begin(115200);

DS1302_init();

// 设置延迟时间目标为5秒后

targetTime = Rtc.GetDateTime(); // 获取当前时间

targetTime = targetTime + 5; // 在当前时间上加5秒作为目标时间

Serial.println("Target time set to: ");

printDateTime(targetTime); // 打印目标时间

}

void loop()

{

RtcDateTime now = Rtc.GetDateTime(); // 获取当前时间

// 检查是否到达目标时间

if (now >= targetTime)

{

Serial.println("5s定时时间到了");

// 设置新的延迟时间目标(比如再延迟5秒)

targetTime = now + 5;

}

// 不使用 delay(),而是进行其他处理

// 这里你可以放置其他代码来处理你的任务

}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)

{

char datestring[26];

snprintf_P(datestring,

countof(datestring),

PSTR("%02u/%02u/%04u %02u:%02u:%02u"),

dt.Month(),

dt.Day(),

dt.Year(),

dt.Hour(),

dt.Minute(),

dt.Second() );

Serial.print(datestring);

}

void DS1302_init()

{

Serial.print("compiled: ");

Serial.print(__DATE__);

Serial.println(__TIME__); // 打印系统编译时候的时间

Rtc.Begin();

RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__); // 将系统编译时的时间存入 ds1302 中

printDateTime(compiled);

Serial.println();

if (!Rtc.IsDateTimeValid())

{

Serial.println("RTC lost confidence in the DateTime!");

Rtc.SetDateTime(compiled); // 设置 RTC 时间为编译时的时间

}

if (Rtc.GetIsWriteProtected()) // 检测是否开启了写保护,如果开启,就关掉写保护

{

Serial.println("RTC was write protected, enabling writing now");

Rtc.SetIsWriteProtected(false);

}

if (!Rtc.GetIsRunning()) // 检测 RTC 是否运行,从现在开始

{

Serial.println("RTC was not actively running, starting now");

Rtc.SetIsRunning(true);

}

RtcDateTime now = Rtc.GetDateTime(); // 获取 RTC 当前时间

if (now < compiled)

{

Serial.println("RTC is older than compile time! (Updating DateTime)");

Rtc.SetDateTime(compiled); // 如果 RTC 时间早于编译时间,进行更新

}

else if (now > compiled)

{

Serial.println("RTC is newer than compile time. (this is expected)"); // RTC 时间更新正常

}

else if (now == compiled)

{

Serial.println("RTC is the same as compile time! (not expected but all is fine)"); // RTC 时间与编译时间一致

}

}