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
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 时间与编译时间一致
}
}