Ariduino入门笔记——5. Arduino 默认函数(高级I/O)

青旅半醒 2023-01-19 04:35 114阅读 0赞

文章目录

  • 播放不同频率的方波信号 tone()
    • 函数原型:
    • 参数说明:
  • 停止播放信号 noTone()
    • 函数原型:
    • 参数说明:
  • 针脚测时 pulseIn()
    • 函数原型:
    • 参数说明:
    • 返回值
  • pulseInLong()
  • shiftIn()
    • 函数原型:
    • 参数说明:
    • 返回值
  • shiftOut()
    • 函数原型:
    • 参数说明:
    • 返回

如果想用Arduino播放音乐,或者声音,你就需要使用一些高级的IO功能。官方给出了数个高级IO编程的接口,我在这里把他们罗列出来,以方便使用。

播放不同频率的方波信号 tone()

在这里插入图片描述

这个函数将会产生一连串不同频率的信号(也就是声音)给指定的针脚,可以在任意Arduino引脚上产生指定频率(50%占空比)的方波1。可以定义时长,如果不定义时长,那么会持续播放旋律。对应针角可以连接到 压电式蜂鸣器(Piezo Buzzer),也可以连接到喇叭上。

不过需要注意的是,同一时间内只能产生一个信号。如果在一个针角上发送多个不同频率的信号,会出现信号抢占的问题,导致其他tone()无效。

根据官方描述,使用tone函数将干扰引脚3和11(Mega以外的板上)上的PWM输出。此外,也无法产生低于31Hz的信号。

函数原型:

  • tone(pin, frequency)
  • tone(pin, frequency, duration)

参数说明:

  • pin: 针脚号
  • frequency: 信号频率,数据类型: unsigned int.
  • duration: 持续时长 milliseconds (optional). 数据类型: unsigned long.

需要注意的地方: 如果打算在不同的针脚上发送信号,那么在发送信号前,为避免干扰,需要先 使用noTone停止之前的tone。

此外,在W3School的官网,我找到这样一个非常有意思的播放MIDI音乐的方式,这里是各个音高的频率定义。

  1. /************************************************* * Public Constants *************************************************/
  2. #define NOTE_B0 31
  3. #define NOTE_C1 33
  4. #define NOTE_CS1 35
  5. #define NOTE_D1 37
  6. #define NOTE_DS1 39
  7. #define NOTE_E1 41
  8. #define NOTE_F1 44
  9. #define NOTE_FS1 46
  10. #define NOTE_G1 49
  11. #define NOTE_GS1 52
  12. #define NOTE_A1 55
  13. #define NOTE_AS1 58
  14. #define NOTE_B1 62
  15. #define NOTE_C2 65
  16. #define NOTE_CS2 69
  17. #define NOTE_D2 73
  18. #define NOTE_DS2 78
  19. #define NOTE_E2 82
  20. #define NOTE_F2 87
  21. #define NOTE_FS2 93
  22. #define NOTE_G2 98
  23. #define NOTE_GS2 104
  24. #define NOTE_A2 110
  25. #define NOTE_AS2 117
  26. #define NOTE_B2 123
  27. #define NOTE_C3 131
  28. #define NOTE_CS3 139
  29. #define NOTE_D3 147
  30. #define NOTE_DS3 156
  31. #define NOTE_E3 165
  32. #define NOTE_F3 175
  33. #define NOTE_FS3 185
  34. #define NOTE_G3 196
  35. #define NOTE_GS3 208
  36. #define NOTE_A3 220
  37. #define NOTE_AS3 233
  38. #define NOTE_B3 247
  39. #define NOTE_C4 262
  40. #define NOTE_CS4 277
  41. #define NOTE_D4 294
  42. #define NOTE_DS4 311
  43. #define NOTE_E4 330
  44. #define NOTE_F4 349
  45. #define NOTE_FS4 370
  46. #define NOTE_G4 392
  47. #define NOTE_GS4 415
  48. #define NOTE_A4 440
  49. #define NOTE_AS4 466
  50. #define NOTE_B4 494
  51. #define NOTE_C5 523
  52. #define NOTE_CS5 554
  53. #define NOTE_D5 587
  54. #define NOTE_DS5 622
  55. #define NOTE_E5 659
  56. #define NOTE_F5 698
  57. #define NOTE_FS5 740
  58. #define NOTE_G5 784
  59. #define NOTE_GS5 831
  60. #define NOTE_A5 880
  61. #define NOTE_AS5 932
  62. #define NOTE_B5 988
  63. #define NOTE_C6 1047
  64. #define NOTE_CS6 1109
  65. #define NOTE_D6 1175
  66. #define NOTE_DS6 1245
  67. #define NOTE_E6 1319
  68. #define NOTE_F6 1397
  69. #define NOTE_FS6 1480
  70. #define NOTE_G6 1568
  71. #define NOTE_GS6 1661
  72. #define NOTE_A6 1760
  73. #define NOTE_AS6 1865
  74. #define NOTE_B6 1976
  75. #define NOTE_C7 2093
  76. #define NOTE_CS7 2217
  77. #define NOTE_D7 2349
  78. #define NOTE_DS7 2489
  79. #define NOTE_E7 2637
  80. #define NOTE_F7 2794
  81. #define NOTE_FS7 2960
  82. #define NOTE_G7 3136
  83. #define NOTE_GS7 3322
  84. #define NOTE_A7 3520
  85. #define NOTE_AS7 3729
  86. #define NOTE_B7 3951
  87. #define NOTE_C8 4186
  88. #define NOTE_CS8 4435
  89. #define NOTE_D8 4699
  90. #define NOTE_DS8 4978

我在原来的示例代码基础上,做了一些修改,你可以自己执行看看是什么效果:

  1. int melody[] = {
  2. NOTE_C4, NOTE_D4, NOTE_E4, NOTE_C4,
  3. NOTE_C4, NOTE_D4, NOTE_E4, NOTE_C4,
  4. NOTE_E4, NOTE_F4, NOTE_G4,
  5. NOTE_E4, NOTE_F4, NOTE_G4,
  6. NOTE_G4, NOTE_A4, NOTE_G4, NOTE_F4,
  7. NOTE_E4, NOTE_C4,
  8. NOTE_G4, NOTE_A4, NOTE_G4, NOTE_F4,
  9. NOTE_E4, NOTE_C4,
  10. NOTE_D4, NOTE_G3, NOTE_C4, 0,
  11. NOTE_D4, NOTE_G3, NOTE_C4, 0,
  12. };
  13. // note durations: 4 = quarter note,
  14. // 8 = eighth note, etc.:
  15. int noteDurations[] = {
  16. 4, 4, 4, 4,
  17. 4, 4, 4, 4,
  18. 4, 4, 2,
  19. 4, 4, 2,
  20. 4, 4, 4, 4,
  21. 2, 2,
  22. 4, 4, 4, 4,
  23. 2, 2,
  24. 4, 4, 4, 4,
  25. 4, 4, 4, 4
  26. };
  27. void setup() {
  28. // put your setup code here, to run once:
  29. // iterate over the notes of the melody:
  30. for (int thisNote = 0; thisNote < 34; thisNote++) {
  31. // to calculate the note duration, take one second
  32. // divided by the note type.
  33. //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
  34. int noteDuration = 1000/noteDurations[thisNote];
  35. tone(5, melody[thisNote],noteDuration);
  36. //pause for the note's duration plus 30 ms:
  37. delay(noteDuration +30);
  38. }
  39. noTone(5);
  40. }
  41. void loop() {
  42. // put your main code here, to run repeatedly:
  43. }

注意一下你的喇叭连接的接口号,看看有什么有趣的。

停止播放信号 noTone()

这个函数是用来停止由tone所激发的方波信号。

函数原型:

noTone(pin)

参数说明:

pin: 针脚、管脚号

针脚测时 pulseIn()

根据官方描述,如果定义的值是高电平,当某针脚从低电平变成高电平的那一刻开始计时,一直到针脚重新从高电平变成低电平,返回此过程的微秒时间(microseconds),或者说是脉冲持续时间。

有什么用呢?

比方说,这种功能对于需要测距的时候,就可以派上用场。比如说:

超声波发射器向某一方向发射超声波,在发射的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。声波在空气中的传播速度为340m/s,根据计时器记录的时间t,就可以计算出发射点距障碍物的距离s,即: s = 340 m / s × t / 2 s=340m/s \times t / 2 s=340m/s×t/2 。2

需要注意的是,这个函数可用于测量的时间范围是 10微秒(1000 微秒 = 1 毫秒 = 1/1000秒),到3分钟。另外,根据官方描述,如果使用了超时参数,那么可以更快的返回结果

函数原型:

  • pulseIn(pin, value)
  • pulseIn(pin, value, timeout)

参数说明:

pin: 读取返回值信息的管脚号
value: 希望读取的脉冲信号类型: HIGH(高电平) or LOW(低电平).
timeout (optional): 等待获得脉冲信号开始的时间,默认是1秒。比方说当前的信号是低电平,希望读取的是高电平,如果在设定的等待时间里,检测到了高电平,则开始计时。

返回值

如果检测到了信号,返回信号持续的时间。如果超时,那么返回的数据是0.

  1. int pin = 7;
  2. unsigned long duration;
  3. void setup() {
  4. Serial.begin(9600);
  5. pinMode(pin, INPUT);
  6. }
  7. void loop() {
  8. duration = pulseIn(pin, HIGH);
  9. Serial.println(duration);
  10. }

pulseInLong()

根据官方描述,这个函数是一个对pulseIn来说,对擅长处理更长脉冲时间的函数。此外,对于检测中断的场景也比pulseIn更为得心应手。检测有效时常和pulseIn一样,但是对于长脉冲数据,精度会有问题。

所以对短脉冲信号的处理,可以只使用pulseIn,而对于长脉冲信号,推荐使用pulseInLong。由于参数基本一致,所以这里不做过多说明。

shiftIn()

将一个字节的数据通过移位的方式逐位输入。数据可以从最高位(最左位)或从最低位(最右位)输入。在输入数据时,Arduino首先在时钟引脚输出高电平,然后通过数据输入引脚读取一位数据,读取结束后时钟引脚将被Arduino设置为低电平。

如果与Arduino进行数据通讯的设备是在时钟引脚脉冲信号上升沿发送数据,请确保在调用shiftIn()前,应先通过digitalWrite(clockPin, LOW)语句,将时钟引脚设置为LOW。这样做是为了确保数据读取准确无误。

以上介绍的方法使用软件实现数据输出操作。如果想要通过硬件方法输出数据,请参阅Arduino的SPI库函数。通过硬件方法输入数据更加快捷,但Arduino只有几个特定引脚可用于使用硬件方法输入数据3。

函数原型:

byte incoming = shiftIn(dataPin, clockPin, bitOrder)

参数说明:

  • dataPin – 数据引脚,数据输入
  • clockPin – 时钟引脚
  • bitOrder – 移位顺序 ( 高位先入 或 低位先入)

返回值

从 dataPin 中读取的值,数据类型为 byte.

shiftOut()

将一个字节的数据通过移位输出的方式逐位输出。数据可以从最高位(最左位)或从最低位(最右位)输出。在输出数据时,当一位数据写入数据输出引脚时,时钟引脚将输出脉冲信号,指示该位数据已被写入数据输出引脚等待读取。

如果读取数据的设备是在Arduino的时钟引脚脉冲信号上升沿读取Arduino的输出数据,请确保在调用shiftOut()输出数据前,应先通过digitalWrite(clockPin, LOW)语句,将时钟引脚设置为LOW。这样做是为了确保数据读取准确无误。

以上介绍的方法使用软件实现数据输出操作。如果想要通过硬件方法输出数据,请参阅Arduino的SPI库函数。通过硬件方法输出数据更加快捷,但Arduino只有几个特定引脚可用于使用硬件方法输出数据。

函数原型:

shiftOut(dataPin, clockPin, bitOrder, value)

参数说明:

dataPin – 数据引脚
clockPin – 时钟引脚
bitOrder – 移位顺序 ( 高位先出 或 低位先出)
val – 输出的数据

返回


  1. https://www.w3cschool.cn/arduino/arduino\_tone\_library.html ↩︎
  2. https://blog.csdn.net/qq\_31077649/article/details/72581968 ↩︎
  3. http://www.taichi-maker.com/homepage/reference-index/arduino-code-reference/shiftin ↩︎

发表评论

表情:
评论列表 (有 0 条评论,114人围观)

还没有评论,来说两句吧...

相关阅读