【雕爷学编程】Arduino 手册之高级 I/O 函数 pulseIn()

在这里插入图片描述
在这里插入图片描述
什么是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高级 I/O 函数 pulseIn()
pulseIn()函数是一种用于读取数字引脚上的脉冲信号的函数。pulseIn()的作用是让Arduino根据指定的电平和超时时间,测量一个脉冲信号从开始到结束的持续时间,并返回该时间的微秒数。这样可以实现一些需要测量脉冲信号的功能,例如测量距离、速度、频率等。

pulseIn()的使用范围:
1)当需要读取一个数字引脚上的高电平或低电平的脉冲信号时,例如读取一个超声波传感器、一个霍尔传感器、一个红外接收器等。
2)当需要根据一个脉冲信号的持续时间来计算其他物理量时,例如根据一个超声波传感器返回的脉冲信号来计算距离、根据一个霍尔传感器返回的脉冲信号来计算转速、根据一个红外接收器返回的脉冲信号来识别编码等。
3)当需要与其他支持脉冲调制的设备或电路进行数据交换时,例如使用PWM协议来控制LED灯、舵机、电机等。

应用场景:
1)脉冲信号测量:当需要测量外部设备发送的脉冲信号的持续时间或间隔时间时,可以使用pulseIn()函数。这在测量传感器输出的脉冲宽度、计算脉冲频率或测量两个脉冲之间的时间间隔等应用中非常有用。
2)响应外部触发:通过使用pulseIn()函数,可以实现对外部触发事件的快速响应。当接收到特定脉冲信号时,可以通过pulseIn()函数测量脉冲的持续时间,并根据测量结果执行相应的操作,如控制其他设备、触发报警或记录数据等。
3)通信协议解析:某些通信协议(如红外线通信)可以使用脉冲信号进行数据传输。通过使用pulseIn()函数,可以测量接收到的脉冲信号的持续时间,从而解析和处理通信协议中的数据。

使用pulseIn()时,需要注意以下事项:
1)pulseIn()函数的第一个参数是要读取脉冲信号的数字引脚的编号,可以是任意一个数字引脚。第二个参数是要读取脉冲信号的电平,可以是HIGH(高电平)或LOW(低电平)。第三个参数是可选的,表示要读取脉冲信号的超时时间,单位是微秒,范围是0到4294967295,默认值是1000000(1秒)。
2)pulseIn()函数会根据指定的电平和超时时间,测量一个脉冲信号从开始到结束的持续时间,并返回该时间的微秒数。如果在超时时间内没有检测到完整的脉冲信号,则返回0。如果检测到多个连续的脉冲信号,则只返回第一个脉冲信号的持续时间。
3)pulseIn()函数只能用于已经设置为输入模式的数字引脚,否则会导致不可预测的结果。要设置数字引脚的模式,可以使用pinMode()函数。
4)pulseIn()函数会阻塞程序执行,直到检测到完整的脉冲信号或超时返回。因此,在使用pulseIn()函数时,需要注意不要影响其他功能或任务的正常运行。

以下是Arduino高级 I/O 函数pulseIn()的几个实际运用程序案例:

案例一:测量超声波传感器距离:

const int triggerPin = 2;
const int echoPin = 3;

void setup() {
    
    
  pinMode(triggerPin, OUTPUT);
  pinMode(echoPin, INPUT);
  Serial.begin(9600);
}

void loop() {
    
    
  digitalWrite(triggerPin, LOW);
  delayMicroseconds(2);
  digitalWrite(triggerPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggerPin, LOW);

  long duration = pulseIn(echoPin, HIGH); // 测量回声脉冲的持续时间

  // 将持续时间转换为距离
  float distance = duration * 0.034 / 2;

  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");

  delay(1000);
}

在此案例中,我们使用超声波传感器测量距离。通过触发超声波传感器发送脉冲信号,然后使用pulseIn()函数测量接收到的回声脉冲的持续时间。根据声音的传播速度和时间,可以计算出距离。

案例二:解析红外线遥控器信号:

const int irPin = 2;

void setup() {
    
    
  pinMode(irPin, INPUT);
  Serial.begin(9600);
}

void loop() {
    
    
  int duration = pulseIn(irPin, HIGH); // 测量红外线脉冲的持续时间

  // 根据持续时间判断遥控器按下的按键
  if (duration >= 1000 && duration <= 2000) {
    
    
    Serial.println("Power button pressed");
  } else if (duration >= 2000 && duration <= 3000) {
    
    
    Serial.println("Volume up button pressed");
  } else if (duration >= 3000 && duration <= 4000) {
    
    
    Serial.println("Volume down button pressed");
  }

  delay(100);
}

在此案例中,我们使用红外线接收器接收红外线遥控器的信号。通过使用pulseIn()函数测量接收到的脉冲信号的持续时间,我们可以解析遥控器按下的按键。根据持续时间的不同范围,可以判断出不同的按键操作。

案例三:计算频率:

const int inputPin = 2;

void setup() {
    
    
  pinMode(inputPin, INPUT);
  Serial.begin(9600);
}

void loop() {
    
    
  unsigned long pulseDuration = pulseIn(inputPin, HIGH); // 测量脉冲的持续时间

  // 计算频率
  float frequency = 1000000.0 / pulseDuration;

  Serial.print("Frequency: ");
  Serial.print(frequency);
  Serial.println(" Hz");

  delay(1000);
}

在此案例中,我们使用pulseIn()函数测量输入引脚上的脉冲信号的持续时间,并通过计算来计算频率。通过将脉冲持续时间的倒数除以1秒,我们可以得到频率的值。

案例四:使用pulseIn()函数读取一个霍尔传感器KY-003,从而测量转速。具体的电路图和代码如下:

// 定义两个常量DATA_PIN、CLOCK_PIN,表示分别连接到霍尔传感器的数据引脚和时钟引脚
#define DATA_PIN 2
#define CLOCK_PIN 3

// 定义一个全局变量count,表示霍尔传感器检测到的磁场变化次数,并初始化为0
volatile int count = 0;

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

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

  // 设置一个中断函数,当DATA_PIN引脚从高电平变为低电平时,调用countPulse函数
  attachInterrupt(digitalPinToInterrupt(DATA_PIN), countPulse, FALLING);
}

void loop() {
    
    
  // 定义一个局部变量rpm,表示转速,并初始化为0
  int rpm = 0;

   // 禁用中断,以防止数据被修改
   noInterrupts();

   // 根据count的值和时间间隔,计算转速(假设每转一圈有4次磁场变化)
   rpm = count * 15;

   // 将count的值重置为0
   count = 0;

   // 启用中断,以继续检测磁场变化
   interrupts();

   // 通过串口输出转速
   Serial.println(rpm);

   // 等待1000毫秒
   delay(1000);
}

// 定义一个中断函数countPulse,用于增加count的值
void countPulse() {
    
    
  count++;
}

案例五:使用pulseIn()函数读取一个超声波传感器HC-SR04,从而测量距离。

// 定义两个常量TRIG_PIN、ECHO_PIN,表示分别连接到超声波传感器的触发引脚和回响引脚
#define TRIG_PIN 9
#define ECHO_PIN 10

void setup() {
    
    
  // 将TRIG_PIN引脚设为输出模式,将ECHO_PIN引脚设为输入模式
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

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

void loop() {
    
    
  // 定义两个局部变量duration和distance,表示脉冲信号的持续时间和距离,并初始化为0
  long duration = 0;
  int distance = 0;

   // 将TRIG_PIN引脚设为低电平,等待2微秒
   digitalWrite(TRIG_PIN, LOW);
   delayMicroseconds(2);

   // 将TRIG_PIN引脚设为高电平,持续10微秒,即发送一个超声波脉冲
   digitalWrite(TRIG_PIN, HIGH);
   delayMicroseconds(10);

   // 将TRIG_PIN引脚设为低电平,等待回响信号
   digitalWrite(TRIG_PIN, LOW);

   // 调用pulseIn()函数,从ECHO_PIN引脚读取一个高电平的脉冲信号,并设置超时时间为10000微秒,返回值赋给duration
   duration = pulseIn(ECHO_PIN, HIGH, 10000);

   // 根据duration的值和声速(340m/s),计算距离(单位厘米),并除以2(因为是来回的距离)
   distance = duration * 0.034 / 2;

   // 通过串口输出距离
   Serial.print("Distance: ");
   Serial.print(distance);
   Serial.println(" cm");

   // 等待100毫秒
   delay(100);
}

案例六:使用pulseIn()函数读取一个红外接收器VS1838B,从而识别红外遥控编码。

// 定义一个常量IR_PIN,表示连接到红外接收器的数据引脚
#define IR_PIN 4

// 定义一个数组codes,表示红外遥控上每个按键对应的编码(NEC协议)
unsigned long codes[] = {
    
    
  0xFFA25D, // 按键POWER
  0xFFE21D, // 按键MODE
  0xFF629D, // 按键MUTE
  0xFF22DD, // 按键PLAY/PAUSE
  0xFF02FD, // 按键REWIND
  0xFFC23D, // 按键FORWARD
  0xFFE01F, // 按键EQ
  0xFFA857, // 按键VOL-
  0xFF906F, // 按键VOL+
  0xFF9867, // 按键RPT
  0xFFB04F, // 按键U/SD
};

// 定义一个数组keys,表示红外遥控上每个按键对应的字符
char keys[] = {
    
    
  'P', // 按键POWER
  'M', // 按键MODE
  'U', // 按键MUTE
  'S', // 按键PLAY/PAUSE
  '<', // 按键REWIND
  '>', // 按键FORWARD
  'E', // 按键EQ
  '-', // 按键VOL-
  '+', // 按键VOL+
  'R', // 按键RPT
  'D', // 按键U/SD
};

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

void loop() {
    
    
  // 定义一个局部变量code,表示从红外接收器读取的编码,并初始化为0
  unsigned long code = 0;

   // 调用readIR函数,从IR_PIN引脚读取一个红外编码,返回值赋给code
   code = readIR(IR_PIN);

   // 判断code的值是否为0,如果是,则表示没有检测到红外信号,继续下一次循环
   if (code == 0) {
    
    
     return;
   }

   // 定义一个局部变量key,表示按下的按键对应的字符,并初始化为空字符
   char key = '\0';

   // 循环遍历codes数组中的每个编码
   for (int i = 0; i < sizeof(codes) / sizeof(codes[0]); i++) {
    
    
     // 判断code的值是否等于codes数组中的某个编码,如果是,则将keys数组中对应的字符赋给key,并跳出循环
     if (code == codes[i]) {
    
    
       key = keys[i];
       break;
     }
   }

   // 判断key的值是否为空字符,如果是,则表示没有识别到有效的按键,继续下一次循环
   if (key == '\0') {
    
    
     return;
   }

   // 通过串口输出按下的按键对应的字符
   Serial.println(key);

   // 等待500毫秒,防止抖动和重复读取
   delay(500);
}

// 定义一个函数readIR,用于从指定的引脚读取一个红外编码(NEC协议)
unsigned long readIR(int pin) {
    
    
  // 定义一个局部变量value,表示要返回的编码,并初始化为0
  unsigned long value = 0;

   // 定义一个局部变量duration,表示脉冲信号的持续时间,并初始化为0
   unsigned int duration = 0;

   // 等待引脚上的信号从高电平变为低电平,即开始接收数据
   while (digitalRead(pin) == HIGH);

   // 等待引脚上的信号从低电平变为高电平,并测量持续时间(单位微秒)
   duration = pulseIn(pin, HIGH);

   // 判断持续时间是否在9000微秒左右(误差范围为200微秒),如果不是,则表示不是有效的起始信号,返回0
   if (duration < 8800 || duration > 9200) {
    
    
     return 0;
   }

   // 等待引脚上的信号从高电平变为低电平,并测量持续时间(单位微秒)
   duration = pulseIn(pin, LOW);

   // 判断持续时间是否在4500微秒左右(误差范围为200微秒),如果不是,则表示不是有效的起始信号,返回0
   if (duration < 4300 || duration > 4700) {
    
    
     return 0;
   }

   // 循环32次,每次读取一个位数据,并将其存入value中
   for (int i = 0; i < 32; i++) {
    
    
     // 等待引脚上的信号从低电平变为高电平,并测量持续时间(单位微秒)
     duration = pulseIn(pin, HIGH);

     // 判断持续时间是否在560微秒左右(误差范围为200微秒),如果不是,则表示该位数据为0,否则为1
     if (duration < 340 || duration > 780) {
    
    
       value = value << 1;
     } else {
    
    
       value = value << 1 | 1;
     }

     // 等待引脚上的信号从高电平变为低电平,准备读取下一位数据
     while (digitalRead(pin) == HIGH);
   }

   // 返回编码值
   return value;
}

在这里插入图片描述

猜你喜欢

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