【雕爷学编程】Arduino 手册之时间函数 millis()

在这里插入图片描述
在这里插入图片描述
什么是Arduino?
Arduino 是一款开源的电子原型平台,它可以让你用简单的硬件和软件来创建各种创意的项目。无论你是初学者还是专家,Arduino 都能为你提供无限的可能性。你可以用 Arduino 来控制传感器、灯光、马达、机器人、物联网设备等等,只要你能想到的,Arduino 都能帮你实现。

如果你想了解更多关于 Arduino 的信息,你可以访问 Arduino 的官方网站,那里有丰富的资源和教程供你参考。你也可以加入 Arduino 的社区,和来自世界各地的爱好者、学生、设计师和工程师交流心得和经验。此外,你还可以使用 Arduino 的在线编程工具,在云端编写代码并上传到你的开发板上。

Arduino 是一个不断发展和创新的平台,它有着广泛的应用领域和潜力。这里希望本手册能激发你对 Arduino 的兴趣和热情,让你享受 Arduino 带来的创造力和乐趣

在这里插入图片描述

维基百科的定义
Arduino 是一个开源嵌入式硬件平台,用来供用户制作可交互式的嵌入式项目。此外 Arduino 作为一个开源硬件和开源软件的公司,同时兼有项目和用户社群。该公司负责设计和制造Arduino电路板及相关附件。这些产品按照GNU宽通用公共许可证(LGPL)或GNU通用公共许可证(GPL)许可的开源硬件和软件分发的,Arduino 允许任何人制造 Arduino 板和软件分发。 Arduino 板可以以预装的形式商业销售,也可以作为 DIY 套件购买。

Arduino 2005 年时面世,作为意大利伊夫雷亚地区伊夫雷亚互动设计研究所的学生设计,目的是为新手和专业人员提供一种低成本且简单的方法,以建立使用传感器与环境相互作用的装置。初学者和爱好者可用Arduino制造传感器、简单机器人、恒温器和运动检测器等装置。

Arduino 这个名字来自意大利伊夫雷亚的一家酒吧,该项目的一些创始人过去常常会去这家酒吧。 酒吧以伊夫雷亚的 Arduin(Arduin of Ivrea)命名,他是伊夫雷亚边疆伯爵,也是 1002 年至 1014 年期间的意大利国王。

在这里插入图片描述

十六、Arduino时间函数 millis()
millis()函数是一种用于获取Arduino开发板运行当前程序的时间的函数。millis()的作用是返回一个无符号长整型(unsigned long)的值,表示从开发板开始运行当前程序到调用该函数时经过的毫秒数。这个值会在大约50天后溢出(回到零),所以需要注意处理溢出的情况。使用millis()函数可以实现一些需要计时或延时的功能,而不影响程序的其他部分。

millis()的使用范围:
1)当需要获取程序运行的时间或执行某个代码段所花费的时间时,例如获取程序启动时间、计算代码执行效率、实现秒表功能等。
2)当需要实现非阻塞式的延时或定时功能时,例如让LED灯闪烁、控制舵机转动、发送定时信号等。
3)当需要实现多任务或伪并行的功能时,例如同时控制多个LED灯、读取多个传感器、响应多个事件等。

millis()的应用场景:
1)定时执行任务:通过结合millis()函数和条件判断,可以实现定时执行任务的功能。通过设置特定的时间间隔,可以按照预定的频率执行某些代码,例如定时采集传感器数据、控制执行器、更新显示等。
2)计时:millis()函数可以用于计算时间间隔。通过记录开始时间和结束时间,并使用millis()函数获取时间差,可以测量代码执行的时间、操作的持续时间等。
3)延时:与delay()函数相比,millis()函数可以实现更精确的延时控制。通过记录开始时间和延时时间,可以在延时期间执行其他代码,并使用millis()函数检查是否到达预定的延时时间。

使用millis()时,需要注意以下事项:
1)millis()函数返回的值是无符号长整型(unsigned long),如果使用较小的数据类型(如int)进行运算,可能会导致逻辑错误。即使使用有符号长整型(long),也可能会遇到错误,因为其最大值是无符号长整型的一半。
2)millis()函数返回的值会在大约50天后溢出(回到零),所以在进行时间比较或计算时,需要考虑溢出的情况。一种常用的方法是使用无符号长整型进行减法运算,然后判断结果是否小于期望的时间间隔。
3)millis()函数不会受到微控制器定时器的重新配置的影响,所以可以保证其准确性。不同的Arduino核心可能使用不同的定时器来生成millis(),例如“Arduino AVR Boards”和“Arduino megaAVR Boards”核心使用Timer0,“Arduino ARM (32-bits) Boards”和“Arduino SAMD (32-bits ARM Cortex-M0+) Boards”核心使用SysTick定时器。

以下是Arduino时间函数millis()的三个实际运用程序案例:

案例一:使用millis()函数实现LED灯闪烁,而不使用delay()函数。具体的电路图和代码如下:

// 定义一个常量LED_PIN,表示连接到LED灯的数字引脚
#define LED_PIN 13

// 定义一个常量INTERVAL,表示LED灯闪烁的时间间隔(单位毫秒)
#define INTERVAL 500

// 定义一个全局变量previousMillis,表示上一次LED灯切换状态的时间,并初始化为0
unsigned long previousMillis = 0;

// 定义一个全局变量ledState,表示LED灯的当前状态,并初始化为LOW
int ledState = LOW;

void setup() {
    
    
  // 将LED_PIN引脚设为输出模式
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
    
    
  // 定义一个局部变量currentMillis,表示当前时间,并调用millis()函数获取其值
  unsigned long currentMillis = millis();

   // 判断当前时间与上一次切换状态的时间之差是否大于等于闪烁间隔
   if (currentMillis - previousMillis >= INTERVAL) {
    
    
     // 如果是,则更新上一次切换状态的时间为当前时间
     previousMillis = currentMillis;

     // 判断LED灯的当前状态是否为LOW
     if (ledState == LOW) {
    
    
       // 如果是,则将其设为HIGH
       ledState = HIGH;
     } else {
    
    
       // 否则,将其设为LOW
       ledState = LOW;
     }

     // 将LED灯的状态写入LED_PIN引脚
     digitalWrite(LED_PIN, ledState);
   }
}

案例二:使用millis()函数实现舵机转动,而不使用delay()函数。具体的电路图和代码如下:

// 引入Servo库,用于控制舵机
#include <Servo.h>

// 定义一个常量SERVO_PIN,表示连接到舵机的数字引脚
#define SERVO_PIN 9

// 定义一个常量INTERVAL,表示舵机转动的时间间隔(单位毫秒)
#define INTERVAL 1000

// 定义一个全局变量previousMillis,表示上一次舵机转动的时间,并初始化为0
unsigned long previousMillis = 0;

// 定义一个全局变量servoAngle,表示舵机的当前角度,并初始化为0
int servoAngle = 0;

// 创建一个Servo对象,用于控制舵机
Servo servo;

void setup() {
    
    
  // 将Servo对象与SERVO_PIN引脚关联
  servo.attach(SERVO_PIN);
}

void loop() {
    
    
  // 定义一个局部变量currentMillis,表示当前时间,并调用millis()函数获取其值
  unsigned long currentMillis = millis();

   // 判断当前时间与上一次转动的时间之差是否大于等于转动间隔
   if (currentMillis - previousMillis >= INTERVAL) {
    
    
     // 如果是,则更新上一次转动的时间为当前时间
     previousMillis = currentMillis;

     // 判断舵机的当前角度是否为180度
     if (servoAngle == 180) {
    
    
       // 如果是,则将其设为0度
       servoAngle = 0;
     } else {
    
    
       // 否则,将其增加10度
       servoAngle += 10;
     }

     // 将舵机的角度写入Servo对象
     servo.write(servoAngle);
   }
}

案例三:使用millis()函数实现秒表功能,而不使用delay()函数。

// 定义两个常量START_PIN、STOP_PIN,表示分别连接到开始按钮和停止按钮的数字引脚
#define START_PIN 2
#define STOP_PIN 3

// 定义一个全局变量startTime,表示秒表开始计时的时间,并初始化为0
unsigned long startTime = 0;

// 定义一个全局变量stopTime,表示秒表停止计时的时间,并初始化为0
unsigned long stopTime = 0;

// 定义一个全局变量running,表示秒表是否正在运行,并初始化为false
boolean running = false;

void setup() {
    
    
  // 将START_PIN、STOP_PIN两个引脚设为输入模式,并启用上拉电阻
  pinMode(START_PIN, INPUT_PULLUP);
  pinMode(STOP_PIN, INPUT_PULLUP);

  // 初始化串口通信,波特率为9600
  Serial.begin(9600);
}

void loop() {
    
    
  // 定义一个局部变量startButtonState,表示开始按钮的当前状态,并读取START_PIN引脚的值赋给它
  int startButtonState = digitalRead(START_PIN);

   // 定义一个局部变量stopButtonState,表示停止按钮的当前状态,并读取STOP_PIN引脚的值赋给它
   int stopButtonState = digitalRead(STOP_PIN);

   // 判断开始按钮是否被按下(即START_PIN引脚为低电平)
   if (startButtonState == LOW) {
    
    
     // 如果是,则判断秒表是否正在运行
     if (running == false) {
    
    
       // 如果不是,则将秒表设为运行状态,并调用millis()函数获取当前时间赋给startTime
       running = true;
       startTime = millis();
     }
   }

   // 判断停止按钮是否被按下(即STOP_PIN引脚为低电平)
   if (stopButtonState == LOW) {
    
    
     // 如果是,则判断秒表是否正在运行
     if (running == true) {
    
    
       // 如果是,则将秒表设为停止状态,并调用millis()函数获取当前时间赋给stopTime
       running = false;
       stopTime = millis();
     }
   }

   // 判断秒表是否正在运行
   if (running == true) {
    
    
     // 如果是,则通过串口输出当前时间与开始时间之差(单位秒),保留两位小数
     Serial.print("Elapsed time: ");
     Serial.print((millis() - startTime) / 1000.0, 2);
     Serial.println(" s");
   } else {
    
    
     // 否则,通过串口输出停止时间与开始时间之差(单位秒),保留两位小数
     Serial.print("Elapsed time: ");
     Serial.print((stopTime - startTime) / 1000.0, 2);
     Serial.println(" s");
   }
}

案例四:定时LED闪烁:

const int ledPin = 13;
unsigned long previousMillis = 0;
const unsigned long interval = 1000;

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

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

  if (currentMillis - previousMillis >= interval) {
    
    
    previousMillis = currentMillis;

    // 在特定时间间隔内交替改变LED的状态
    if (digitalRead(ledPin) == LOW) {
    
    
      digitalWrite(ledPin, HIGH);
    } else {
    
    
      digitalWrite(ledPin, LOW);
    }
  }
}

在此案例中,使用millis()函数实现了定时LED闪烁的功能。通过记录上一次LED状态改变的时间(previousMillis)和设定的时间间隔(interval),在当前时间与上一次时间间隔超过设定值时,改变LED的状态。

案例五:延时执行任务:

const unsigned long delayTime = 5000; // 延时时间为5秒

void setup() {
    
    
  Serial.begin(9600);
  Serial.println("Start");
}

void loop() {
    
    
  static unsigned long startTime = millis(); // 记录开始时间

  if (millis() - startTime >= delayTime) {
    
    
    Serial.println("Delayed task executed");
    // 执行延时任务的代码

    startTime = millis(); // 重置开始时间
  }

  // 其他代码
}

在此案例中,使用millis()函数实现了延时执行任务的功能。通过记录开始时间(startTime)和设定的延时时间(delayTime),当当前时间与开始时间间隔超过延时时间时,执行延时任务的代码,并重置开始时间。

案例六:计时器:

unsigned long startTime;
unsigned long endTime;
bool timerRunning = false;

void startTimer() {
    
    
  startTime = millis();
  timerRunning = true;
}

void stopTimer() {
    
    
  endTime = millis();
  timerRunning = false;
}

void printElapsedTime() {
    
    
  if (timerRunning) {
    
    
    unsigned long elapsedTime = millis() - startTime;
    Serial.print("Elapsed time: ");
    Serial.print(elapsedTime);
    Serial.println(" ms");
  } else {
    
    
    unsigned long elapsedTime = endTime - startTime;
    Serial.print("Elapsed time: ");
    Serial.print(elapsedTime);
    Serial.println(" ms");
  }
}

void setup() {
    
    
  Serial.begin(9600);
  startTimer(); // 启动计时器
}

void loop() {
    
    
  // 执行其他代码

  if (millis() >= 10000) {
    
     // 在特定时间后停止计时器
    stopTimer();
    printElapsedTime();
  }
}

在此案例中,使用millis()函数实现了计时器的功能。通过startTimer()函数记录开始时间,stopTimer()函数记录结束时间,printElapsedTime()函数根据计时器状态打印经过的时间。在设置的时间(这里是10秒)后停止计时器,并打印经过的时间。

这些案例展示了millis()函数在Arduino中的实际应用,包括定时执行任务、延时执行任务和计时器功能。通过灵活运用millis()函数,可以实现更多与时间相关的功能和控制。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41659040/article/details/132641053