WangShuXian6 / blog

FE-BLOG
https://wangshuxian6.github.io/blog/
MIT License
46 stars 10 forks source link

Arduino #141

Open WangShuXian6 opened 2 years ago

WangShuXian6 commented 2 years ago

Arduino

https://www.arduino.cc/ https://docs.arduino.cc/learn/ 面向初学者的物联网 - 课程 https://github.com/microsoft/IoT-For-Beginners/

Arduino 是一款便捷灵活、方便上手的开源电子原型平台,包含硬件(各种型号的arduino板)和软件(arduino IDE).她适用于艺术家、设计师、爱好者和对于“互动”有兴趣的朋友们。 Arduino能通过各种各样的传感器来感知环境,通过控制灯光、马达和其他的装置来反馈、影响环境。板子上的微控制器可以通过Arduino的编程语言来编写程序,编译成二进制文件,烧录进微控制器 对Arduino的编程是利用 Arduino编程语言 (基于 Wiring)和Arduino开发环境(based on Processing)来实现的。基于Arduino的项目,可以只包含Arduino,也可以包含Arduino和其他一些在PC上运行的软件,他们之间进行通信 (比如 Flash, Processing, MaxMSP)来实现。. 你可以自己自己动手制作,也可以购买成品套装;Arduino所使用到的软件都可以免费下载. 硬件参考设计 (CAD 文件)也是遵循availableopen-source协议, 你可以非常自由地 根据你自己的要求去修改他们. 什么是我们常说的Arduino? 如今我们说的Arduino,是一套使用C++编写的单片机开发框架。目前非常多的主流MCU已经支持使用Arduino开发。

CP2102USB 驱动

https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers

驱动

打开目录菜单 Tools(工具) -> Board(开发板) 并选择相应的开发板, Arduino ide 1x 会根据用户选择的主板下载驱动安装,之后可以手动更新,或者安装其他驱动

安装驱动后选择正确的端口 如果端口不识别,需要重启系统 点击 Tools(工具) -> Port(端口) 菜单, 为您的开发板选择对应的端口(这个端口为上一 步在设备管理器中显示的串行端口)。在 windows 类似 COM6 。 Mac OS 用户,应当选 择类似 /dev/cu.SLAB_USBtoUART

uno 板需要安装 avr 驱动

合作商

openjumper (买过,较贵,质量好)

https://www.openjumper.com/home https://openjumper.cn/

https://openjumper.taobao.com/ https://shop555818949.taobao.com/

https://openjumper.cn/product-menu/ https://www.openjumper.com/doc

dfrobot (买过,较贵,质量好)

www.dfrobot.com.cn

https://www.dfrobot.com.cn/index.php

https://wiki.dfrobot.com.cn DFRobot官方产品资料库-

seeedstudio (买过,很贵,质量好)

https://www.seeedstudio.com/

https://seeedstudio.taobao.com/

https://wiki.seeedstudio.com/cn/ Seeed产品文档

质量良心商家

https://shop512532718.taobao.com/ 星原力科创 (买过,质量好,价格不贵,很适合)

WangShuXian6 commented 2 years ago

Arduino硬件

https://www.arduino.cc/en/hardware

Arduino UNO硬件

00004

image

1 支持USB接口传输数据及供电(不需额外电源)。

2 电压输入PowerJackDCIN接口,可单独使用,不需连接计算机的USB接口时,直接接上5V变压器,或是电池直接供电(故1、2只需选择其一即可)。

3 FTDIUSB芯片,通过该芯片即可跟计算机连接通信传递数据。

4 VoltageRegulator,稳压器,保持电压的稳定。

5 LED灯,用来显示传递接收的数据RX和传递出去的数据TX,当数据传输时LED灯都会闪烁,并且这两个LED灯和区域7的引脚0和引脚1是相连的。

6 LED灯,用来显示区域7的引脚13的电平:高电平或低电平。

7 数字引脚,由右到左分别是: 7-1 数字引脚0到数字引脚13,注意一下印刷内容,有些字前面有~符号,例如“~10”,这个表示它可以当成数字引脚10,也可以做PWM的数据输出。这个符号的意思是在这个板子上面,只有特别的引脚可以做PWM的数据输出。

7-2 GND,接地引脚。

7-3 AREF,是AD转换的参考电压输入端。英文全名是AnalogueREFerence,它可以让我们知道Arduino的参考电压。

8 RX<-0和TX->1,如果要做UART数据传输,想把数据传进Arduino,可通过TX->1 (引脚1);如果想做UART数据传输出去,就可以把引脚RX<-0(引脚0)接到另外一个硬件上面。需要注意的是,这两个引脚平常与USB连接线连接在一起,如果你要通过USB在这个板子上编程,请确定你的引脚0和引脚1上面没有任何接线,不然程序烧录会失败。

9 LED灯,用于显示电源状态。

10 Reset按键,用于复位系统。

11 ICSPHeader,英文的全名是In-circuitserialprogramming序列烧录方式,PIC烧录器烧录程序的方法,程序内存为Flash的版本使用方便的ICSP序列烧录方式。

12 Microcontroller,控制芯片。

13 模拟信号引脚:a0、a1、a2、a3、a4、a5。

14 电源控制引脚:

14-1 Vin(电源输入)。

14-2 GND(接地)。

14-3 GND(接地)。

14-4 5V(5V电源输出)。

14-5 3.3V(3.3V电源输出)。

14-6 RESET(重新执行程序)。

1. 电源(Power)

ArduinoUNO有三种供电方式: ● 通过USB接口供电,电压为5V; ● 通过DC电源输入接口供电,电压要求7~12V; ● 通过电源接口处5V或者VIN端口供电,5V端口处供电必须为5V,VIN端口处 供电为7~12V。

2.指示灯(LED)

ArduinoUNO带有4个LED指示灯,作用分别是: ● ON,电源指示灯。当Arduino通电时,ON灯会点亮。 ● TX,串口发送指示灯。当使用USB连接到计算机且Arduino向计算机传输数据 时,TX灯会点亮。 ● RX,串口接收指示灯。当使用USB连接到计算机且Arduino接收计算机传来的 数据时,RX灯会点亮。 ● L,可编程控制指示灯。该LED通过特殊电路连接到Arduino的13号引脚,当 13号引脚为高电平或高阻态时,该LED会点亮;当为低电平时,不会点亮。因 此可以通过程序或者外部输入信号来控制该LED的亮灭。

3.复位按键(Reset Button)

按下该按键可以使Arduino重新启动,从头开始运行程序。

4.存储空间(Memory)

Arduino的存储空间即是其主控芯片所集成的存储空间。也可以通过使用外设芯片的方式来扩展Arduino的存储空间。Arduino UNO的存储空间分三种: ● Flash,容量为32KB。其中0.5KB作为BOOT区用于储存引导程序,实现通过串 口下载程序的功能;另外的31.5KB作为用户储存的空间。相对于现在动辄几百 GB的硬盘,可能觉得32KB太小了,但是在单片机上,32KB已经可以存储很大 的程序了。 ● SRAM,容量为2KB。SRAM相当于计算机的内存,当CPU进行运算时,需要 在其中开辟一定的存储空间。当Arduino断电或复位后,其中的数据都会丢失。 ● EEPROM,容量为1KB。EEPROM的全称为电可擦写的可编程只读存储器,是 一种用户可更改的只读存储器,其特点是在Arduino断电或复位后,其中的数据 不会丢失。

5.输入/输出端口(Input/Output Port)

ArduinoUNO有14个数字输入/输出端口,6个模拟输入端口。其中一些带有特殊功能,这些端口如下: ● UART通信,为0(RX)和1(TX)引脚,被用于接收和发送串口数据。这两个 引脚通过连接到ATmega16U2来与计算机进行串口通信。 ● 外部中断,为2和3引脚,可以输入外部中断信号。 ● PWM输出,为3、5、6、9、10和11引脚,可用于输出PWM波。 ● SPI通信,为10(SS)、11(MOSI)、12(MISO)和13(SCK)引脚,可用于 SPI通信。 ● TWI通信,为A4(SDA)、A5(SCL)引脚和TWI接口,可用于TWI通信,兼 容IIC通信。 ● AREF,模拟输入参考电压的输入端口。 ● Reset,复位端口。接低电平会使Arduino复位。当复位键被按下时,会使该端口 接到低电平,从而使Arduino复位。

这块板子有如下功能

1~13为数字式输入/输出端。

0~5为模拟式输入/输出端。

支持USB接口传输数据及供电(不需额外电源)。

支持ICSP在线刻录功能。

支持TX/RX端子。

支持AREF端子。

支持3~6组PWM端子。

输入电压: 接上USB时无需供电。 5V~12VDC输入。 输出电压:5VDC输出。

采用AtmelATMega8/168/328单芯片。

Arduino大小尺寸:宽70mm×高54mm。

微处理器的特点。

ATMega168 RISC架构 16kbytes Flash 0.5kbytes EEPROM F.max 20MHz(20MIPS) Interrupts 26 PWMChannels 6 RTCYES 0.5kBytes EEPROM 1kbytes SRAM I/O 23Pins VCC 1.8~5.5V 10-bit ADC 6 16-bit Timers 1 Self Program Memory YES SPI + USART Watchdog YES UART 1

自制Arduino板子

Arduino广受欢迎的原因之一是它开源,如果你也想要生产Arduino板子,可以在以下网址拿到PCB版的设计图,你可以自行生产,不用考虑Arduino版权问题,因为这是一个开源硬件项目,可以自行修改,但是修改后的硬件设计,必须在网络上公开。

如果你想获取Arduino的Eaglefile或是PCB的设计,可以到官方网站下载相关文档。

相关参考网站,都可以取得设计图:

http://Arduino.cc/en/Main/ArduinoBoardSerialSingleSided3

http://Arduino.cc/en/uploads/Main/Arduino-Diecimila-schematic.pdf

Arduino的Bootloader启动程序(也称启动载入器)。

正如我们所知,Arduino使用下面这些IC

ATMega168 ATMega328 ATMage2560 ATMega32u4

有没有我们去买一些现成的IC,自己烧录Arduino的可能?可以。如果你不是购买市面上现成的Arduino板子,而是自己买IC来制作Arduino系统,就要学会Bootloader的制作,笔者不建议花大钱去购置IC烧录器,我们可以直接使用另外一台Arduino硬件,做跳线完成烧录的动作。

要进行IC烧录,需准备一些硬件器材。

一个16MHz晶体。 一个10K的电阻。 两个18~22微法拉(陶瓷)电容器。 硬件接线图 使用Arduino板子,连接 ATMega168的硬件接线路图 00025 Bootloader的程序在哪里?事实上已整合到Arduino开发环境之中,只要打开Arduino开发工具,把Arduino的USB线和型号设置好,Bootloader的程序就开始工作了,Bootloader的程序主要是负责启动和运行Arduino程序。

Arduino MCU IC介绍

市面上有多个IC可以用来当成Arduino的MCU

ATMega8

http://www.atmel.com/devices/atmega8.aspx Arduino使用的是低功耗的Atmel公司的8位AVRRISC为基础的微处理器,这个IC有8KB的可编程Flash存储器、2KB的SRAM、512KEEPROM、6或8通道的10bit字节模数转换器。

这种微处理器支持16MHz和16MIPS,供电只需要2.7V~5.5V之间即可 00031

功能

功能 数值
Flash(Kbytes) 8Kbytes
引脚 32
Max.Operating Frequency执行速度 16MHz
CPU 8-bit AVR
Touch Channels 12
硬件QTouch Acquisition No
MaxI/OPins 23
Ext Interrupts 2
USB传输速率 No
USB接口 No

ATMega168

http://www.atmel.com/devices/atmega168.aspx 高性能、低功耗的Atmel公司的8位AVRRISC为基础的微处理器,集成了16KB ISP Flash存储器,512B EEPROM,1KB SRAM,8-channel/10-bit模数转换器(TQFP和QFN/MLF),debugWIRE功能可以让你在芯片上做测试,ATMega168 IC的造型见图2-4-2-1。该微处理器支持20MIPS吞吐量,20MHz电源需要在2.7V~5.5V之间。

00033

在一个单时钟周期指令执行时间(a single clock cycle),此微处理器速度可以达到每MHz接近1MIPS的吞吐量,并且有平衡功耗和处理速度。

功能

功能 数值 功能 数值
Flash(Kbytes) 16Kbytes HardwareQTouchAcquisition No
输入输出引脚数量 32 MaxI/OPins 23
Max.Operating Frequency 20MHz Ext Interrupts 24
CPU 8-bit AVR USB传输速率 No
Touch Channels 16 USB接口 No

绘图工具

面包板

免焊万用电路板(solderlessbreadboard),俗称面包板,内部是由一些长条形的磷青铜片组成,水平线由25个插孔组成,垂直线则是每5个插孔为一组。各插孔间可视需求,以0.6mm的单芯线加以连接组合。

使用方法,最上面的两排和最下面的两排,它们左右的每一个点,都是彼此连接,其他部份的五个点,都是上下连接。如果你有两根线想要连接在一起,只要把它接到连接的两个点上,面包板底下的接线接头,就会自动接在一起。 00051

使用电路板时,应避免将过粗的接线或元件引脚插入电路板插孔

WangShuXian6 commented 2 years ago

Arduino 常用函数参考

https://wiki.arduino.cn/?file=home-%E9%A6%96%E9%A1%B5

项目结构

setup loop main

setup()

Arduino控制器通电或复位后,即会开始执行setup() 函数中的程序,该部分只会执行一次。 通常我们会在setup() 函数中完成Arduino的初始化设置,如配置I/O口状态,初始化串口等操作。

示例程序

// 给13号引脚连接的设备设置一个别名“led”
int led = 13;

// 在板子启动或者复位重启后, setup部分的程序只会运行一次
void setup(){
  // 将“led”引脚设置为输出状态
  pinMode(led, OUTPUT);     
}

// setup部分程序运行完后,loop部分的程序会不断重复运行
void loop() 
{
  digitalWrite(led, HIGH);   // 点亮LED
  delay(1000);           // 等待一秒钟
  digitalWrite(led, LOW);   // 通过将引脚电平拉低,关闭LED
  delay(1000);           // 等待一秒钟
}

loop()

setup() 函数中的程序执行完后,Arduino会接着执行loop() 函数中的程序。而loop()函数是一个死循环,其中的程序会不断的重复运行。 通常我们会在loop() 函数中完成程序的主要功能,如驱动各种模块,采集数据等。

示例程序

// 给13号引脚连接的设备设置一个别名“led”
int led = 13;

// 在板子启动或者复位重启后, setup部分的程序只会运行一次
void setup(){
  // 将“led”引脚设置为输出状态
  pinMode(led, OUTPUT);     
}

// setup部分程序运行完后,loop部分的程序会不断重复运行
void loop() 
{
  digitalWrite(led, HIGH);   // 点亮LED
  delay(1000);           // 等待一秒钟
  digitalWrite(led, LOW);   // 通过将引脚电平拉低,关闭LED
  delay(1000);           // 等待一秒钟
}

Arduino程序main函数结构解析

在进行Arduino开发时,没有像传统C/C++程序使用入口函数main。实际上main函数存在于Arduino核心库中,且仍然是程序的入口。 在Arduino核心库中可见main.cpp文件,其内容如下:


#include <Arduino.h>

// Declared weak in Arduino.h to allow user redefinitions. int atexit(void ( /func*/ )()) { return 0; }

// Weak empty variant initialization function. // May be redefined by variant files. void initVariant() attribute((weak)); void initVariant() { }

void setupUSB() attribute((weak)); void setupUSB() { }

int main(void) { init();

initVariant();

if defined(USBCON)

USBDevice.attach();

endif

setup();

for (;;) {
    loop();
    if (serialEventRun) serialEventRun();
}

return 0;

}

>通过以上程序可见,Arduino程序中编写的setup和loop函数,都在main函数中调用了。
>loop的循环执行,是通过for循环实现的,且每次loop结束后,都会进行串口事件判断,也正是因为这种设计,串口事件不能实时响应。

## 数字输入输出
[pinMode](https://wiki.arduino.cn/?file=001-%E6%95%B0%E5%AD%97%E8%BE%93%E5%85%A5%E8%BE%93%E5%87%BA/001-pinMode)
[digitalWrite](https://wiki.arduino.cn/?file=001-%E6%95%B0%E5%AD%97%E8%BE%93%E5%85%A5%E8%BE%93%E5%87%BA/002-digitalWrite)
[digitalRead](https://wiki.arduino.cn/?file=001-%E6%95%B0%E5%AD%97%E8%BE%93%E5%85%A5%E8%BE%93%E5%87%BA/003-digitalRead)

### `pinMode(pin, mode)`
>在使用输入或输出功能前,你需要先通过pinMode() 函数配置引脚的模式为输入模式或输出模式。

#### 参数
>参数pin为指定配置的引脚编号
>参数mode为指定的配置模式
>通常可用模式有三种:
INPUT 输入模式
OUTPUT 输出模式
INPUT_PULLUP 输入上拉模式

#### 示例程序
```ino
/*
  Blink
等待一秒钟,点亮LED,再等待一秒钟,熄灭LED,如此循环
*/

// 在大多数Arduino控制板上 13号引脚都连接了一个标有“L”的LED灯
// 给13号引脚连接的设备设置一个别名“led”
int led = 13;

// 在板子启动或者复位重启后, setup部分的程序只会运行一次
void setup(){
  // 将“led”引脚设置为输出状态
  pinMode(led, OUTPUT);     
}

// setup部分程序运行完后,loop部分的程序会不断重复运行
void loop() 
{
  digitalWrite(led, HIGH);   // 点亮LED
  delay(1000);           // 等待一秒钟
  digitalWrite(led, LOW);   // 通过将引脚电平拉低,关闭LED
  delay(1000);           // 等待一秒钟
}

digitalWrite(pin, value)

之前我们在Blink程序中使用到了pinMode(13, OUTPUT),即是把13号引脚配置为输出模式。 配置成输出模式后,你还需要使用digitalWrite() 让其输出高电平或者是低电平。

参数

参数pin为指定输出的引脚编号; 参数value为你要指定输出的电平 使用HIGH指定输出高电平,或是使用LOW指定输出低电平。

示例程序

/*
  Blink
等待一秒钟,点亮LED,再等待一秒钟,熄灭LED,如此循环
*/

// 在大多数Arduino控制板上 13号引脚都连接了一个标有“L”的LED灯
// 给13号引脚连接的设备设置一个别名“led”
int led = 13;

// 在板子启动或者复位重启后, setup部分的程序只会运行一次
void setup(){
  // 将“led”引脚设置为输出状态
  pinMode(led, OUTPUT);     
}

// setup部分程序运行完后,loop部分的程序会不断重复运行
void loop() 
{
  digitalWrite(led, HIGH);   // 点亮LED
  delay(1000);           // 等待一秒钟
  digitalWrite(led, LOW);   // 通过将引脚电平拉低,关闭LED
  delay(1000);           // 等待一秒钟
}

其他说明

Arduino中输出的低电平为0V,输出的高电平为当前Arduino的工作电压。 例如Arduino UNO的工作电压为5V,其高电平输出也是5V;Arduino Uno工作电压为3.3V,所以高电平输出也就是3.3V。

digitalRead(pin)

在使用输入或输出功能前,你需要先通过pinMode() 函数配置引脚的模式为输入模式或输出模式。

参数

参数pin为指定读取状态的引脚编号。

返回值

返回值为获取到的信号状态,1为高电平,0为低电平。

示例程序

/*
通过2号引脚连接的按键,控制13号引脚连接的LED
*/

// 设置各引脚别名
const int buttonPin = 2;     // 连接按键的引脚
const int ledPin =  13;      // 连接LED的引脚

// 变量定义
int buttonState = 0;         // 存储按键状态的变量

void setup() {
  // 初始化LED引脚为输出状态
  pinMode(ledPin, OUTPUT);      
  // 初始化按键引脚为输入状态
  pinMode(buttonPin, INPUT);     
}

void loop(){
  // 读取按键状态并存储在变量中
  buttonState = digitalRead(buttonPin);

  // 检查按键是否被按下
  // 如果按键按下,那buttonState应该为高电平
  if (buttonState == HIGH) {     
    // 点亮LED
    digitalWrite(ledPin, HIGH);  
  } 
  else {
    // 熄灭LED
    digitalWrite(ledPin, LOW); 
  }
}

模拟输入输出

analogRead analogWrite

analogRead(pin)

模拟输入引脚是带有ADC(Analog-to-Digital Converter,模数转换器)功能的引脚。 它可以将外部输入的模拟信号转换为芯片运算时可以识别的数字信号,从而实现读入模拟值的功能。 模拟输入功能需要使用analogRead() 函数。

参数

参数pin是指定要读取模拟值的引脚,被指定的引脚必须是模拟输入引脚。 如analogRead(A0),即是读取A0引脚上的模拟值。

返回值

Arduino Uno模拟输入功能有10位精度,即可以将0~5V的电压信号转换为0~1023的整数形式表示。

示例程序

/*
光敏电阻检测环境光
http://www.arduino.cn/
*/

void setup()
{
  // 初始化串口
  Serial.begin(9600);
}
void loop() 
{
// 读出当前光线强度,并输出到串口显示
  int sensorValue = analogRead(A0);
  Serial.println(sensorValue);
  delay(1000);
}

analogWrite(pin,value)

使用analogWrite() 函数实现PWM输出功能。 在Arduino Uno中,提供PWM功能的引脚为3、5、6、9、10、11。

analogWrite()analogRead() 函数内部,已经完成了引脚的初始化,因此不用在Setup() 函数中进行初始化操作。

参数

参数pin是指定要输出PWM波的引脚; 参数value指定是PWM的脉冲宽度,范围为0~255

示例程序

/*
Fading
通过analogWrite() 函数实现呼吸灯效果
*/

int ledPin = 9;    // LED连接在9号引脚上

void setup()  { 
  // Setup部分不进行任何处理
} 

void loop()  { 
  // 从暗到亮,以每次加5的形式逐渐亮起来
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    // 输出PWM
    analogWrite(ledPin, fadeValue);         
    // 等待30ms,以便观察到渐变效果
    delay(30);                            
  } 

  // 从亮到暗,以每次减5的形式逐渐暗下来
  for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    // 输出PWM
    analogWrite(ledPin, fadeValue);         
    // 等待30ms,以便观察到渐变效果
    delay(30);                            
  } 
}

高级输入输出

tone pulseIn 外部中断

调声函数

tone() 主要用于Arduino连接蜂鸣器或扬声器发声。

tone()可以让指定引脚产生一个占空比为50%的指定频率的方波。

语法

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

参数

pin: 需要输出方波的引脚 frequency: 输出的频率,unsigned int型 duration: 方波持续的时间,单位毫秒。如果没有该参数,Arduino将持续发出设定的音调,直到你改变发声频率或者使用noTone() 函数停止发声。

noTone(pin)

停止指定引脚上的方波输出。

语法

noTone(pin)

参数

pin:需要停止方波输出的引脚

示例程序

/*
Melody

Plays a melody 
This example code is in the public domain.
http://arduino.cc/en/Tutorial/Tone
*/

#include "pitches.h"

// 记录曲子的音符
int melody[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};

// 音符持续时间  4为四分音符, 8为八分音符
int noteDurations[] = {
  4, 8, 8, 4,4,4,4,4 };

void setup() {
  // 遍历整个曲子的音符
  for (int thisNote = 0; thisNote < 8; thisNote++) {

// noteDurations[]数组中存储的是音符的类型
// 我们需要将其换算为音符持续时间,方法如下:
    // 音符持续时间=1000ms / 音符类型
    // 例如,四分音符=1000 / 4,8分音符 = 1000/8
    int noteDuration = 1000/noteDurations[thisNote];
    tone(8, melody[thisNote],noteDuration);

    // 为了能辨别出不同的音调,你需要在两个音调间设置一定的延时
    // 增加30%延时时间是比较合适的
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // 停止发声
    noTone(8);
  }
}

void loop() {
  // 程序并不重复,因此这里为空
}

时间控制

时间运行 延时函数

串口通信

begin print read 其他函数 软串口

EEPROM

写数据 读数据 清除数据

USB驱动库

模拟键盘 模拟鼠标

Arduino数据手册

Arduino_Uno Arduino_Mega Arduino_Leonardo Arduino_Due Arduino_Zero

WangShuXian6 commented 2 years ago

Arduino

通过串口监视器 查看打印数据

在 Arduino 工具栏选择:工具-》串口监视器 Hello.ino


void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}

void loop() { // put your main code here, to run repeatedly: Serial.println("test"); delay(1000); }


>编译后上传,串口监视器将每隔一秒打印一行 ‘test’

>注意,上传程序时,如果出现端口被占用,需要关闭其他的编辑器,同时只能有一个编辑器与端口通信。或者重启插拔usb。
WangShuXian6 commented 2 years ago

Arduino IDE

Arduino的开发环境以AVR-GCC和其他一些开源软件为基础,采用C编写 Arduino开发环境使用的语法与C/C++相似,非常容易使用

Arduino vscode

vscode-arduino 扩展

https://github.com/microsoft/vscode-arduino

安装后需要配置 arduino ide 路径,mac系统当前只能将ide安装在系统盘的Applications目录

配置 vscode 路径

默认修改工作区配置,即当前项目。 可以修改用户配置,即全局配置,所有项目

在 Mac 上:

{
"arduino.path": "/Applications", 
"arduino.commandPath": "Contents/MacOS/Arduino"
}

在 Ubuntu 上:

{
"arduino.path": "/snap/bin", 
"arduino.commandPath": "arduino"
}

配置 includePath

按F1运行“Arduino: Initialize”命令,VS Code將建立如下的c_cpp_propertise.json內容 .vscode/c_cpp_properties.json

{
"configurations": [
{
"name": "Arduino Uno",
"includePath": [
"${workspaceFolder}/**",
"/Applications/Arduino.app/Contents/Java/tools/**",
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/**",
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/avr/include/**",
"~/Documents/Arduino/libraries/**"
],
"forcedInclude": [
"/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h"
],
"defines": [
"USBCON",
"ARDUINO=10809"
],
"intelliSenseMode": "clang-x64",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}

配置

image

选择 arduino 编译器,可以从arduino上查看 例如 uno 板 avrispmkii

选择 主板型号 例如 arduino uno

选择 端口 例如 /dev/tty.usbserial-14341320 可以从arduino 上查看

选择监视器 查看调试输出 部分Arduino vscode版本插件可能无法直接查看 ,需要screen + 端口 手动开启

screen /dev/cu.SLAB_USBtoUART 115200
WangShuXian6 commented 2 years ago

数字输出点亮和熄灭LED灯

目标

1、数字信号输出的概念 2、如何使用数字输出功能实现LED灯的点亮控制 3、如何使用数字输出功能实现LED灯的熄灭控制 4、实现LED灯每隔1秒进行闪烁

实验材料

Arduino UNO开发板 LED发光模块 配套USB数据线 配套杜邦线若干 Arduino IDE软件

image

内容

数字信号

数字信号指幅度的取值是离散的,幅值表示被限制在有限个数值之内, 二进制码就是一种数字信号,二进制码受噪声的影响小,易于有数字电路进行处理,所以得到了广泛的应用。 image

LED

LED是发光二极管的简称,可以将电能转化为光能, 发光二极管具有单向导通的特性,即只允许电流从正极流向负极,所以使用时主要正负极不要接反, 熄灭与点亮为数字输出,分别有两种状态,低电平与高电平,数值为0或者1, LED灯的点亮需要将输出设置为高电平,熄灭则为低电平。

基础案例1

点亮LED灯,LED灯点亮为数字输出管脚3,需要将输出设置为高电平。

Arduino UNO开发板与LED发光模块接线图

image

接线方式

Arduino UNO开发板 <------> LED发光模块 3V3/5V <------> VCC GND <------> GND D3 <------> IN

程序实现代码

void setup(){
  pinMode(3, OUTPUT);//定义3号数字管脚类型为输出
}
void loop(){
  digitalWrite(3,HIGH);//将3号数字管脚设置为高电平
}

基础案例2

LED灯熄灭,LED灯熄灭为数字输出管脚3,需要将输出设置为低电平。

程序实现代码

void setup(){
  pinMode(3, OUTPUT);//定义3号数字管脚类型为输出
}
void loop(){
  digitalWrite(3,LOW);//将3号数字管脚设置为低电平
}

基础案例3

让LED灯点亮1秒,然后熄灭1秒,如此往复。 image

程序实现代码

void setup(){
  pinMode(3, OUTPUT);//定义3号数字管脚类型为输出
}
void loop(){
  digitalWrite(3,HIGH);//将3号数字管脚设置为高电平
  delay(1000);//延迟1秒,在这1秒钟,LED灯状态保持不变,即点亮状态
  digitalWrite(3,LOW);//将3号数字管脚设置为低电平
  delay(1000);//延迟1秒,在这1秒钟,LED灯状态保持不变,即熄灭状态
}

pinMode()

说明:通过pinMode()函数,你可以将Arduino的引脚配置为以下三种模式:

1、输出(OUTPUT)模式

2、输入(INPUT)模式

3、输入上拉(INPUT_PULLUP)模式 (仅支持Arduino 1.0.1以后版本) 在输入上拉(INPUT_PULLUP)模式中,Arduino将开启引脚的内部上拉电阻,实现上拉输入功能,一旦将引脚设置为输入(INPUT)模式,Arduino内部上拉电阻将被禁用。

设置Arduino引脚为输出(OUTPUT)模式

当引脚设置为输出(OUTPUT)模式时,引脚为低阻抗状态, 这意味着Arduino可以向其它电路元器件提供电流, 也就是说,Arduino引脚在输出(OUTPUT)模式下可以点亮LED或者驱动电机(如果被驱动的电机需要超过40mA的电流,Arduino将需要三极管或其它辅助元件来驱动他们)。

设置Arduino引脚为输入(INPUT)模式

当引脚设置为输入(INPUT)模式时,引脚为高阻抗状态(100兆欧), 此时该引脚可用于读取传感器信号或开关信号。

注意:当Arduino引脚设置为输入(INPUT)模式或者输入上拉(INPUT_PULLUP)模式,请勿将该引脚与负压或者高于5V的电压相连,否则可能会损坏Arduino控制器。

设置Arduino引脚为输入上拉(INPUT_PULLUP)模式

在数字电路中,上拉电阻(英语:Pull-up resistors)是当某输入端口未连接设备或处于高阻抗的情况下,一种用于保证输入信号为预期逻辑电平的电阻元件。 他们通常在不同的逻辑器件之间工作,提供一定的电压信号。

Arduino 微控制器自带内部上拉电阻,如果你需要使用该内部上拉电阻,可以通过pinMode()将引脚设置为输入上拉(INPUT_PULLUP)模式。

注意:当Arduino引脚设置为输入(INPUT)模式或者输入上拉(INPUT_PULLUP)模式,请勿将该引脚与负压或者高于5V的电压相连,否则可能会损坏Arduino控制器。

上拉电阻的作用

在上拉电阻所连接的导线上,如果外部组件未启用,上拉电阻将“微弱地”将输入电压信号“拉高”。

当外部组件未连接时,对输入端来说,外部“看上去”就是高阻抗的,这时,通过上拉电阻可以将输入端口处的电压拉高到高电平,

如果外部组件启用,它将取消上拉电阻所设置的高电平, 通过这样,上拉电阻可以使引脚即使在未连接外部组件的时候也能保持确定的逻辑电平。

digitalWrite()

说明:将数字引脚写HIGH(高电平)或LOW(低电平)

如果该引脚通过pinMode()设置为输出模式(OUTPUT),您可以通过digitalWrite()语句将该引脚设置为HIGH(5伏特)或LOW(0伏特/GND)。

如果该引脚通过pinMode()设置为输入模式(INPUT),当您通过digitalWrite()语句将该引脚设置为HIGH时,这与将该引脚将被设置为输入上拉(INPUT_PULLUP)模式相同。

请注意: 比起其它数字引脚,数字引脚13由于内部串联了一个LED并焊接了一个限流电阻,所以该引脚比其他引脚更不易用来实现数字输入功能, 如果将数字引脚13设置为输入上拉(INPUT_PULLUP)模式,该引脚将会悬在1.7伏特而不是正常的高电平5伏特,如果必须使用引脚13做为数字输入,请将该引脚配合外部下拉电阻使用。

语法

digitalWrite(pin, value)

参数

pin:引脚号码

value: HIGHLOW


delay()

delay()函数可用于暂停程序运行,暂停时间可以由delay()函数的参数进行控制,单位是毫秒(1秒钟=1000毫秒)

语法

delay(ms)

参数

ms: 暂停时间,该时间单位是毫秒( unsigned long型数据)

返回值

返回值:无

WangShuXian6 commented 2 years ago

数字输入按钮控制LED灯

目标

1、数字输入的使用 2、If条件判断 3、比较关系运算符的应用 4、按钮控制LED灯的点亮和熄灭

实验材料

Arduino UNO开发板 LED发光模块 按钮模块 配套USB数据线 配套杜邦线若干 Arduino IDE软件

image

内容

按钮模块为数字输入模块,默认为弹起状态,电平状态为低电平,按下后向UNO板输出高电平信号。

案例

按钮控制LED灯的点亮和熄灭

流程图

image

Arduino UNO开发板与LED发光模块、按钮模块接线图

image

接线方式

Arduino UNO <------> 按钮开关模块 5V <------> VCC GND <------> GND D7 <------> OUT

Arduino UNO <------> LED模块 5V <------> VCC GND <------> GND D6 <------> IN

程序实现代码

void setup(){
  pinMode(7, INPUT);   //定义7号数字管脚类型为输入
  pinMode(6, OUTPUT);  //定义6号数字管脚类型为输出
}
void loop(){
  if (digitalRead(7) == HIGH) {  //读取7号数字输入管脚,如果为高电平,即按钮被按下
    digitalWrite(6,HIGH);  //将6号数字管脚设置为高电平

  } else {                //否则,即按钮未被按下
    digitalWrite(6,LOW);  //将6号数字管脚设置为低电平
  }
}

HIGH =1 LOW =0

重构版本


int LED_PIN = 6;
int TOGGLE_PIN = 7;

void setup() { Serial.begin(9600); pinMode(TOGGLE_PIN, INPUT); pinMode(LED_PIN, OUTPUT); printf("start"); }

void loop() { int togglePin = digitalRead(TOGGLE_PIN); Serial.println(togglePin); int led = togglePin == HIGH ? HIGH : LOW; digitalWrite(LED_PIN, led); }

***

## `digitalRead()`

>读取数字引脚的 HIGH(高电平)或 LOW(低电平)。

### 语法

>`digitalRead(pin)`

### 参数

>pin:被读取的引脚号码

### 返回值

>[HIGH](http://www.taichi-maker.com/homepage/reference-index/arduino-code-reference/high/) 或 [LOW](http://www.taichi-maker.com/homepage/reference-index/arduino-code-reference/low/)

## `if…else`

>通过`if…else`语句,用户可以让Arduino判断某一个条件是否达到,并且根据这一判断结果执行相应的程序。

### 结构

If(表达式1){ 语句块1 }else{ 语句块2 }

>上述结构表示:如果 “表达式1” 的条件得到满足则执行”语句块1″,否则Arduino将执行”语句块2″。
![image](https://user-images.githubusercontent.com/30850497/189871791-abf60cb8-822e-4be2-b5a9-5fc912871711.png)

## 关系运算符

>比较运算符用于和 [if](http://www.taichi-maker.com/homepage/reference-index/arduino-code-reference/if/) 联合使用,测试某一条件是否达到,例如测试Arduino的某一个引脚输入值是否达到设定数值。

>`==` 是比较运算符,不要把赋值符号(单个等号)和比较运算符(双等号)相互混淆。

>举例

x == y (x 等于 y) x != y (x 不等于 y) x < y (x 小于 y) x > y (x 大于 y) x <= y (x 小于等于 y) x >= y (x 大于等于 y)

WangShuXian6 commented 2 years ago

布尔变量实现状态提示灯

目标

1、创建布尔型变量 2、布尔运算符的使用 3、按一下按钮,LED灯亮,再按一下,LED灯熄灭

实验材料

Arduino UNO开发板 LED发光模块 按钮模块 配套USB数据线 配套杜邦线若干 Arduino IDE软件

image

内容

按一下按钮,LED灯亮,再按一下,LED灯熄灭,依次循环实现

Arduino UNO开发板与LED发光模块、按钮模块接线图

image

接线方式

Arduino UNO <------> 按钮开关模块 5V <------> VCC GND <------> GND D7 <------> OUT Arduino UNO <------> LED模块 5V <------> VCC GND <------> GND D6 <------> IN

程序实现代码

volatile boolean item; //创建布尔型变量item
void setup(){
  item = true;    //item赋值为ture,即真
  pinMode(7, INPUT);  //定义7号数字管脚类型为输入
  pinMode(6, OUTPUT);  //定义6号数字管脚类型为输出
}
void loop(){
  if (digitalRead(7) == HIGH && item)   //读取7号数字输入管脚,如果为高电平,且item为ture,即真
 {  
    delay(200);      //200ms延迟用于按键消抖
    digitalWrite(6,HIGH);               //将6号数字管脚设置为高电平
    item = false;                      // item赋值为false,即假
  } else if (digitalRead(7) == HIGH && !item)    //读取7号数字输入管脚,如果为高电平,且item为非ture,即假
{
    delay(200);       //200ms延迟用于按键消抖
    digitalWrite(6,LOW);     //将6号数字管脚设置为高电平
    item = true;         //item赋值为ture,即真
  }
 }

**

volatile – 易变变量

volatile这个关键字是变量修饰符,常用在变量类型的前面,以告诉编译器和接下来的程序怎么对待这个变量。

声明一个volatile变量是编译器的一个指令,(编译器是一个将你的C/C++代码转换成机器码的软件,机器码是arduino上的Atmega芯片能识别的真正指令。)

具体来说,该指令指示编译器从RAM而非存储寄存器中读取变量,存储寄存器是程序存储和操作变量的内存区域。

当一个变量的控制和改变可能来自程序代码以外的环境,比如在使用Arduino的中断功能时,ISR(中断服务程序)中所涉及的变量需要被声明为volatile易变变量。

boolean

布尔型变量是有两种逻辑状态的变量,它包含两个值:true(真)或 false(假)(每个布尔变量占用一个字节的内存)。

如果在表达式中使用了布尔型变量,那么将根据变量值的真假而赋予整型值1或0,要把一个整型变量转换成布尔型变量,

如果该变量的整型值为0,则其布尔型值为假;反之如果整型值为非0,则其布尔型值为真,

布尔型变量在运行时通常用做标志,比如进行逻辑测试以改变程序流程。

true false 常量

在Arduino内有两个常量用来表示真和假:true和 false。

false

false被定义为数值0(零)。

true

true通常被定义为数值1,但true具有更广泛的定义, 在布尔含义(boolean sense)里任何非零整数都是true, 所以在布尔含义内 -1,2 和 -200 等非零数值都被定义为ture。

注意:true和false常量需要全部小写,这与HIGH,LOW,INPUT和OUTPUT常量是不同的。

WangShuXian6 commented 2 years ago

PWM模拟输出实现LED呼吸灯

目标

1、整数类型int和变量的使用 2、PWM及模拟输出 3、for循环的使用 4、呼吸灯的制作

实验材料

Arduino UNO开发板 LED发光模块 配套USB数据线 配套杜邦线若干 Arduino IDE软件

image

内容

模拟信号

模拟信号是指信息参数在给定范围内表现为连续的信号, 或在一段连续的时间间隔内,其代表信息的特征量可以在任意瞬间呈现为任意数值的信号。 image

模拟输出与PWM调制

模拟信号输出的电压值在0~5V变化,但Arduino UNO板的输出端口都是数字端口,仅能输出高(5V)和低(0V)两种电压值,所以ArduinoUNO板无法输出真正的模拟信号, Arduino程序内建的模拟输出是通过PWM(Pulse Width Modulation)脉冲宽度调制的方法,用高低电平不断切换的数字脉冲信号来模拟模拟信号,

脉冲周期及占空比

在讲解PWM之前要先了解两个概念:脉冲周期及占空比。

脉冲周期:相邻两次脉冲之间的时间间隔,周期的倒数即脉冲频率。

占空比:在一次脉冲周期内高电平持续时间与脉冲周期的比值。

PWM实际是通过高低电平的快速切换来实现模拟信号的输出效果的,在一个脉冲周期内,若占空比为50%,则相当于灯全亮半个周期,之后灯熄灭半个周期。

Arduino的PWM信号脉冲周期仅有0.002s,即每秒500个脉冲周期, 由于人眼的视觉残留效果,呈现出的视觉效果相当于50%的亮度,而此时PWM等效输出电压V=5V×占空比=5V×50%=2.5V。

image

Arduino UNO板数字引脚支持PWM功能的口有6个,分别是3、5、6、9、10、11,当然这些口也可以当普通的数字输出使用, Arduino的PWM支持256级输出,也就是我们可以设置模拟值的范围在0-255,其中255就是表示100%的PWM输出。

案例

通过模拟输出PWM控制LED灯,改变其亮度,达到呼吸效果

Arduino UNO开发板与LED发光模块接线图

image

接线方式

Arduino UNO开发板 <------> LED发光模块 3V3/5V <------> VCC GND <------> GND D3 <------> IN

程序实现代码

应用for循环+1执行循环内的程序

image

应用for循环-1执行循环内的程序

image

void setup(){
}
void loop(){
  for (int i = 0; i <= 255; i ++)    //循环语句,控制PWM亮度的增加
{
    analogWrite(3,i);       //对引脚3写入i的数值
    delay(10);               //当前亮度维持的时间是10ms
  }
  for (int i = 255; i >= 0; i--) {    //循环语句,控制PWM亮度的减小
    analogWrite(3,i);
    delay(10);               //当前亮度维持的时间是10ms
  }
}

for

for语句用于重复执行一段语句块,通常会使用一个增量计数器递增和终止循环,for语句对于任何需要重复的操作是非常有用的。

结构

for(表达式1;表达式2;表达式3){
语句块
}

以上程序的执行过程如下: 1) 先求解表达式1。 2) 求解表达式2,若其值为真(非0),则执行括号中的语句块,否则将结束循环。 3) 每一次执行完语句块,Arduino将求解表达式3。 4) 重复执行步骤 2) 和 3),直到循环结束。 注意:表达式1仅在第一次循环时求解,以后都不会再执行,可以认为这是一个初始化语句。 for循环的执行过程可用下图表示: image

analogWrite

将一个模拟数值写进Arduino引脚,这个操作可以用来控制LED的亮度, 或者控制电机的转速, Arduino每一次对引脚执行analogWrite()指令,都会给该引脚一个固定频率的PWM信号,PWM信号的频率大约为490Hz。

在Arduino UNO控制器中,5号引脚和6号引脚的PWM频率为980Hz, 在一些基于ATmega168和ATmega328的Arduino控制器中,analogWrite()函数支持以下引脚: 3, 5, 6, 9, 10, 11。

在Arduino Mega控制其中,该函数支持引脚 2 – 13 和 44 – 46,使用ATmega8的Arduino控制器中,该函数只支持引脚 9, 10, 11。

在调用analogWrite()函数前,您无需使用pinMode()函数来设置该引脚。

语法

analogWrite(pin, value)

参数

pin:被读取的模拟引脚号码 value:0到255之间的PWM频率值, 0对应off, 255对应on

Int

整数是基本数据类型,整数数据类型占用2字节,整数的范围为-32,768到32,767( -2^15 ~(2^15)-1)。 整数类型使用2的补码方式存储负数,最高位通常为符号位,表示数的正负,其余位被“取反加1”。 Arduino可处理负数计算,但是对整数类型数值进行右移位运算符时,可能会产生不可预料的编译结果。

语法

int var = val; var – 变量名 val – 赋给变量的值

提示

当变量数值过大而超过整数类型所能表示的范围时(-32,768 到 32,767),变量值会“回滚”

int x
x = -32,768;
x = x – 1; // x 现在是 32,767。
x = 32,767;
x = x + 1; // x 现在是 -32,768。

=赋值运算符(单个等号)

把等号右边的值存储到等号左边的变量中。 在C语言中单个等号被称为赋值运算符,它与在代数课中的意义不同,后者象征等式或相等,赋值运算符告诉Arduino将等号右边的数值或表达式计算结果存入等号左边的变量中。 赋值运算符(单个=号)左边的变量要足够大到容纳赋值运算符右面的值,如果不够大,存储在该变量中的值将是错误的。 不要混淆单个等号的赋值运算符( = )和双等号的关系运算符( == ),关系运算符用于关系运算符两边的表达式是否相等。 返回值 无

i++i--

复合运算符 i++相当于i = i + 1 i-- 相当于 i = i – 1

WangShuXian6 commented 2 years ago

串口读取数据

目标

1、掌握打印和打印换行的使用 2、使用FOR循环语句演示如何使用不同的格式向Arduino IDE程序的串口监视器发送数据

实验材料

Arduino UNO开发板 配套USB数据线 Arduino IDE软件

image

内容

使用FOR循环语句演示如何使用不同的格式向Arduino IDE程序的串口监视器发送数据

serial(串行通信)

串行端口用于Arduino和个人电脑或其他设备进行通信,所有Arduino控制器都有至少一个串行端口(也称为UART或者USART),个人电脑可以通过USB端口与Arduino的引脚0(RX)和引脚1(TX) 进行通信,所以当Arduino的引脚0和引脚1用于串行通信功能时,Arduino的引脚0和引脚1是不能做其他用的,也可以通过Arduino开发环境软件中的串口监视器来与Arduino 控制器进行串口通信,你只需要点击Arduino IDE软件中的“串口监视器”按钮就可以打开串口监视器。

Serial(串行通信)函数

--|-- available |获取从串口读取有效的字节数(字符) begin |将串行数据传输速率设置为位/秒(波特) end |停用串行通信,使RX和TX引脚用于一般输入和输出 find |从串行缓冲器中读取数据 findUntil | 从串行缓冲区读取数据,直到找到一个给定的长度或字符串终止位 flush | 等待超出的串行数据完成传输 peek |返回传入的串行数据的下一个字节(字符),而不是进入内部串行缓冲器调取 print | 以人们可读的ASCII文本形式打印数据到串口输出 println |打印数据到串行端口,输出人们可识别的ASCII码文本并回车(ASCII,或\r)及换行(ASCII10,或\n) parselnt |查找传入的串行数据流中的下一个有效的整数 parseFloat | 命令从串口缓冲区返回第一个有效的浮点数 read | 读取传入的串口的数据 readBytes | 从串口读取字符到一个缓冲区 readBytesUntil |将字符从串行缓冲区读取到一个数组 write |写入二级制数据到串口

print()

以人类可读的ASCII码形式向串口发送数据,该函数有多种格式,整数的每一数位将以ASCII码形式发送,浮点数同样以ASCII码形式发送,默认保留小数点后两位,字节型数据将以单个字符形式发送,字符和字符串会以其相应的形式发送,例如:

Serial.print(78) 发送 “78” Serial.print(1.23456) 发送 “1.23” Serial.print(‘N’) 发送 “N” Serial.print(“Hello world.”) 发送 “Hello world.” 此指令也可以通过附加参数来指定数据的格式,这个允许的值为:BIN (binary二进制), OCT (octal八进制), DEC (decimal十进制), HEX (hexadecimal十六进制),对于浮点数,该参数可以指定小数点的位数。例如: Serial.print(78, BIN) 发送 “1001110” Serial.print(78, OCT) 发送 “116” Serial.print(78, DEC) 发送 “78” Serial.print(78, HEX) 发送 “4E” Serial.println(1.23456, 0) 发送 “1” Serial.println(1.23456, 2) 发送 “1.23” Serial.println(1.23456, 4) 发送 “1.2346”

语法
Serial.print(val)
Serial.print(val, format)
参数

val: 要发送的数据(任何数据类型) format: 指定数字的基数(用于整型数)或者小数的位数(用于浮点数)

返回值

size_t (long): print()返回发送的字节数(可丢弃该返回值)

println()

以人类可读的ASCII码形式向串口发送数据,类似print()指令,但是有换行。

语法
Serial.println(val)
Serial.println(val, format)
参数

val: 要发送的数据(任何数据类型) format: 指定数字的数据形式或小数的位数(用于浮点数)

返回值

size_t (long): println()返回发送的字节数(可丢弃该返回值)

示例程序

int x = 0;    // 定义整型变量X为0
 void setup() {
  Serial.begin(9600);      // 打开串口通讯
} 
void loop() {  
  Serial.println("NO");       // 打印文字标志
  Serial.print("Format");       // 打印文字标志
  Serial.print("\t");         //空格    
  Serial.print("DEC");       // 打印文字标志
  Serial.print("\t");      
  Serial.print("HEX");       // 打印文字标志
  Serial.print("\t");  
  Serial.print("OCT");     // 打印文字标志
  Serial.print("\t");
  Serial.print("BIN");      // 打印文字标志
  Serial.print("\t");
  Serial.println("");    //换行
  for(x=0; x< 64; x++){    
    //通过不同格式显示
    Serial.print(x);       // 输出ASCII编码的十进制数字,与"DEC"相同
    Serial.print("\t");   
    Serial.print(x, DEC);  // 输出ASCII编码的十进制数字
    Serial.print("\t");    
    Serial.print(x, HEX);  // 输出ASCII编码的十六进制数字
    Serial.print("\t");    
    Serial.print(x, OCT);  // 输出ASCII编码的八进制数字
    Serial.print("\t");   
    Serial.println(x, BIN);  // 输出ASCII编码的二进制数字,然后换行                          
    delay(500);            //延迟500毫秒
  }
  Serial.println("");      // 再次换行
}

运行结果

程序运行后,串口监视器显示结果如下: image

WangShuXian6 commented 2 years ago

模拟输入串口读取可调电位器模拟值

WangShuXian6 commented 2 years ago

开关可调电位器多程序嵌套实验案例

WangShuXian6 commented 2 years ago

智能声控灯实验案例

目标

1、串口打印读取声音传感器的模拟输入数字 2、声音传感器控制点亮LDE灯,当声音较大时LED灯亮起,声音较小时LED灯保持熄灭状态

实验材料

Arduino UNO开发板 声音传感器模块 LED发光模块 配套USB数据线 配套杜邦线若干 Arduino IDE软件 image

内容

声音传感器控制点亮LDE灯,当声音较大时LED灯亮起,声音较小时LED灯熄灭。

接线图

image

接线方式

Arduino UNO <------> 声音传感器模块 5V <------> VCC GND <------> GND A1 <------> OUT Arduino UNO <------> LED发光模块 5V <------> VCC GND <------> GND D7 <------> IN

串口打印读取声音传感器模块的模拟输入值

程序实现代码

void setup(){
  Serial.begin(9600);
}
void loop(){
  Serial.println(analogRead(A1));  //串口监视器打印显示声音传感器的模拟输入值
  delay(1000);   //延迟等待1秒
}

声音传感器控制点亮LDE灯,当声音较大时LED灯亮起2秒,声音较小时LED灯保持熄灭状态。

程序实现代码

void setup(){
pinMode(7, OUTPUT);  ///定义7号数字管脚类型为输出
}
void loop(){
if (analogRead(A1) > 100) {   //声音传感器模拟输入数值大于100
digitalWrite(7,HIGH);    //7号数字输出管脚为高电平,LED灯被点亮
delay(2000);   //延迟等待2秒
} else {
digitalWrite(7,LOW);  //7号数字输出管脚为低电平,LED灯保持熄灭状态
}
}
int LED_PIN = 7;
int SOUND_PIN = A1;
int SOUND_LIGHT = 100;

void setup()
{
    Serial.begin(9600);
    // pinMode(SOUND_PIN, INPUT);
    pinMode(LED_PIN, OUTPUT);
    printf("start");
}

void loop()
{
    int sound = analogRead(SOUND_PIN);
    Serial.println(sound);
    int led = sound > SOUND_LIGHT ? HIGH : LOW;

    int delayTime = sound > SOUND_LIGHT ? 2000 : 1;
    digitalWrite(LED_PIN, led);
    delay(delayTime);

    // Serial.println(analogRead(SOUND_PIN));
    // if (analogRead(SOUND_PIN) > 100)
    // {                                //声音传感器模拟输入数值大于100
    //     digitalWrite(LED_PIN, HIGH); // 6号数字输出管脚为高电平,LED灯被点亮
    //     delay(2000);                 //延迟等待2秒
    // }
    // else
    // {
    //     digitalWrite(LED_PIN, LOW); // 6号数字输出管脚为低电平,LED灯保持熄灭状态
    // }
}

analogRead()

用于从Arduino的模拟输入引脚读取数值, Arduino控制器有多个10位数模转换通道,这意味着Arduino可以将0-5伏特的电压输入信号映射到数值0-1023。 换句话说,我们可以将5伏特等分成1024份,0伏特的输入信号对应着数值0,而5伏特的输入信号对应着1023。

Arduino控制器读取一次模拟输入需要消耗100微秒的时间(0.0001秒)。控制器读取模拟输入的最大频率是每秒10,000次。

注意:在模拟输入引脚没有任何连接的情况下,用analogRead()指令读取该引脚,这时获得的返回值为不固定的数值,这个数值可能受到多种因素影响,如将手靠近引脚也可能使得该返回值产生变化。

语法

analogRead(pin)

参数

pin:被读取的模拟引脚号

返回值

0到1023之间的值

WangShuXian6 commented 2 years ago

智能光控灯实验案例

目标

实现光敏传感器控制点亮LDE灯,当没有光照时LED灯亮起,有光照时LED灯熄灭。

实验材料

Arduino UNO开发板 光敏传感器模块 LED发光模块 配套USB数据线 配套杜邦线若干 Arduino IDE软件

image

内容

接线图

image

接线方式

Arduino UNO <------> 光敏传感器模块 5V <------> VCC GND <------> GND A0 <------> A0 Arduino UNO <------> LED发光模块 5V <------> VCC GND <------> GND D7 <------> IN

串口打印读取光敏传感器模块的模拟输入值

光线越亮,读取值越小 有光照约200 没有光照约1000 程序实现代码

void setup(){
Serial.begin(9600);
}
void loop(){
Serial.println(analogRead(A0));  //串口监视器打印显示光敏传感器的模拟输入值
delay(1000);   //延迟等待1秒
}

光敏传感器控制点亮LDE灯,当没有光照时LED灯亮起,有光照时LED灯熄灭。

程序实现代码


int LED_PIN = 6;
int LIGHT_PIN = A0;
int MIN_LIGHT = 500;

void setup() { Serial.begin(9600); // pinMode(SOUND_PIN, INPUT); pinMode(LED_PIN, OUTPUT); printf("start"); }

void loop() { int light = analogRead(LIGHT_PIN); Serial.println(light); int led = light > MIN_LIGHT ? HIGH : LOW;

int delayTime = light > MIN_LIGHT ? 2000 : 1;
digitalWrite(LED_PIN, led);
// delay(delayTime);

}

WangShuXian6 commented 2 years ago

认识蜂鸣器门铃制作

目标

1、蜂鸣器的使用 2、音阶对应表 3、门铃的制作

实验材料

Arduino UNO开发板 蜂鸣器模块 按钮模块 配套USB数据线 配套杜邦线若干 Arduino IDE软件 image

内容

按键

数字输入模块,默认为弹起状态,电平状态为低电平,按下后向UNO板输出高电平信号。

蜂鸣器

数字输出模块,收到高电平信号发出蜂鸣声,收到低电平信号则静音。

案例

按钮控制蜂鸣器,按钮按下时蜂鸣器响起,松开时蜂鸣器关闭

流程图

image

接线图

image

接线方式

Arduino UNO <------> 按钮开关模块 5V <------> VCC GND <------> GND D7 <------> OUT Arduino UNO <------> 蜂鸣器模块 5V <------> VCC GND <------> GND D8 <------> IO

程序实现代码

void setup(){
  pinMode(7, INPUT);  //定义7号数字管脚类型为输入
  pinMode(8, OUTPUT);  //定义8号数字管脚类型为输出
}
void loop(){
  if (digitalRead(7) == HIGH) {    //读取7号数字输入管脚,如果为高电平,即按钮被按下
    tone(8,131);   //蜂鸣器8号管脚响起C调do的低音
  } else {
    noTone(8);    //否则,即按钮未被按下,蜂鸣器8号管脚不响
  }
}
int AUDIO_PIN = 8;
int BUTTON_PIN = 7;

void setup()
{
    Serial.begin(9600);
    pinMode(AUDIO_PIN, OUTPUT);
    pinMode(BUTTON_PIN, INPUT_PULLUP);
    noTone(AUDIO_PIN);
    printf("start");
}

void loop()
{
    int isPress = digitalRead(BUTTON_PIN) == HIGH;
    if (isPress)
    {
        tone(AUDIO_PIN, 131);
    }else{
        noTone(AUDIO_PIN);
    }

    Serial.println("loop");
}

七个音阶do re mi fa so la si对应1 2 3 4 5 6 7

蜂鸣器音符音频对应表

image

WangShuXian6 commented 2 years ago

七个基准音的播放

目标

1、掌握数组的使用方法 2、实现蜂鸣器每隔1秒依次响起一个基准音

实验材料

Arduino UNO开发板 蜂鸣器模块(频率可控) 配套USB数据线 配套杜邦线若干 Arduino IDE软件

image

内容

七个基准音(do、re、mi、fa、sol、la、si),这七个基准音对应的频率数组为:1046.5,1174.7,1318.5,1396.9,1568,1760,1975.5。

接线图

image

接线方式

Arduino UNO <------> 蜂鸣器模块 5V <------> VCC GND <------> GND D8 <------> IO

程序实现代码

float Reference_Note[]={1046.5,1174.7,1318.5,1396.6,1568,1760,1975.5}; //创建一个浮点型的Reference_Note基准音数组
void setup(){
  pinMode(8, OUTPUT);   //定义8号数字管脚类型为输出
}
void loop(){
  for (int i = 1; i <= 7; i++) {   //通过循环语句8号管脚蜂鸣器每隔1秒依次响起一个基准音
    tone(8,Reference_Note[(int)(i - 1)]);
    delay(1000);
  }
  noTone(8);
}

array 数组

数组是一种可通过索引号访问的同类型变量集合。

创建数组

下面的方法都可以用来创建(声明)数组。

int Ints[6];
int P[] = {2, 4, 8, 3, 6};
int SensVals[6] = {2, 4, -8, 3, 2};
char message[6] = "hello";

在以上示例中

Ints数组是一个在声明时没有初始化数据的数组。 P数组在声明时没有明确大小。Arduino编译器将会计算该数组所包含的元素数量,并将适当大小的内存空间分配给该数组。 当然,你也可以明确告知Arduino你所创建的数组大小,SensVals就是一个例子。 请注意,当初始化一个char类型的数组时,你需要多分配一个元素空间给该数组。这么做的原因是为了字符数组有足够的空间容纳末尾的终止符。如上面例子中的message数组中包含的元素为hello五个英文字母,但是我们在初始化时必须给该数组6个元素空间。额外的元素空间是为了存储字符结尾的终止符。

使用数组

要想把数据放入内存,必须先要分配内存空间。放入4个整数,就得分配4个int类型的内存空间:

int a[4];

这样,就在内存中分配了4个int类型的内存空间,并为它们起了一个名字,叫a。 我们把这样的一组数据的集合称为数组(Array),它所包含的每一个数据叫做数组元素(Element),所包含的数据的个数称为数组长度(Length),例如int a[4];就定义了一个长度为4的整型数组,名字是a。 数组中的每个元素都有一个序号,这个序号从0开始,而不是从我们熟悉的1开始,称为下标(Index)。使用数组元素时,指明下标即可,形式为: arrayName[index] arrayName 为数组名称,index 为下标。例如,a[0] 表示第0个元素,a[3] 表示第3个元素

需要注意的是:

1) 数组中每个元素的数据类型必须相同,对于int a[4];,每个元素都必须为 int。 2)数组长度 length 最好是整数或者常量表达式,例如 10、204 等,这样在所有编译器下都能运行通过;如果 length 中包含了变量,例如 n、4m 等,在某些编译器下就会报错。 3) 访问数组元素时,下标的取值范围为 0 ≤ index < length,过大或过小都会越界,导致数组溢出,发生不可预测的情况,请大家务必要引起注意。

数组的初始化

可以在定义数组的同时赋值:

int a[4] = {20, 345, 700, 22};

{ }中的值即为各元素的初值,各值之间用,间隔。 对数组赋初值需要注意以下几点: 1) 可以只给部分元素赋初值。当{ }中值的个数少于元素个数时,只给前面部分元素赋值。例如:

int a[10]={12, 19, 22 , 993, 344};

表示只给 a[0] ~ a[4] 这5个元素赋值,而后面5个元素自动赋0值。 当赋值的元素少于数组总体元素的时候,剩余的元素自动初始化为 0:对于short、int、long类型数据,就是整数0;对于char类型数据,就是字符 ‘\0’;对于float、double类型数据,就是小数0.0。 我们可以通过下面的形式将数组的所有元素初始化为 0:

int a[10] = {0};
char c[10] = {0};
float f[10] = {0};

由于剩余的元素会自动初始化为0,所以只需要给第0个元素赋0值即可。

示例:

void setup() {

  Serial.begin(9600);

  int a[6] = {299, 34, 92, 100}; // 定义数组

  for(int i=0; i<6; i++){ //串口监视器输出数组元素

    Serial.print("a[");

    Serial.print(i);

    Serial.print("] =");

    Serial.println(a[i]);

    Serial.println("");

  }  

}

void loop() {

}

运行结果:

image

WangShuXian6 commented 2 years ago

NRF24L01 2.4G无线模块的使用

https://nrf24.github.io/RF24/classRF24.html https://github.com/nRF24/RF24

目标

利用NRF24L01 2.4G无线模块进行数据的传输

注意,接触不良将导致偶尔接受不到数据,或偶尔发送数据失败,应该使用母对母杜邦线来连接传感器与主板来避免接触问题

警告:电压为3.3v,高于3.3v将立刻烧毁传感器

实验材料

Arduino UNO开发板2 NRF24L01 2.4G无线模块2 配套USB数据线*2 配套杜邦线若干 Arduino IDE软件

image image image image

内容

利用NRF24L01 2.4G无线模块进行数据的传输,在一块Arduino UNO 上发送“Hello World”,在另一块Arduino UNO 上接收“Hello World”。

接线图

接线方式

Arduino UNO <------> NRF24L01 2.4G无线模块 3.3V <------> VCC GND <------> GND 8 <------> CSN 7 <------> CE
13 <------> SCK 11 <------> MOSI 12 <------> MISO

需要用到NRF24L01 2.4G无线模块的第三方库文件,文件名为“RF24-master”。 下载链接:https://pan.baidu.com/s/1xXNj1K_O52nSVrIhFCKxTQ 提取码:j6y6

或者官方仓库下载

下载后安装库文件

文件下载后无需解压,点击Arduino IDE菜单栏项目—加载库—添加.ZIP库... image

选择RF24-master文件 image

程序实现代码

发送端程序 Sender.ino

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>   //NRF24L01 2.4G无线模块的库文件
RF24 radio(7, 8); //创建一个RF24的对象CE=7, CSN=8
const byte address[6] = "00001";  //创建一个数组,建立发送机地址,或者说两个模块将用于通信的“管道”
void setup() {
  radio.begin();    //初始化radio对象
  radio.openWritingPipe(address);  //使用radio.openWritingPipe()函数设置的发送机地址
  radio.setPALevel(RF24_PA_MIN);  //设置功率放大器级别,将其设置为最小值
  radio.stopListening();  // 使用radio.stopListening()函数将模块设置为发送机
}
void loop() {
  const char text[] = "Hello World";  //创建一个字符数组,并为其分配消息”Hello World”
  radio.write(&text, sizeof(text)); //使用radio.write()函数将消息发送给接收机,text是要发送的字符变量,
// sizeof(text))设置了我们要从text变量中获取的字节数
  delay(1000);  //延迟等待1秒
}

接收端程序 Receiver.ino

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>   //NRF24L01 2.4G无线模块的库文件
RF24 radio(7, 8);   //创建一个RF24的对象CE=7, CSN=8
const byte address[6] = "00001";  //创建一个数组,建立接收机地址,或者说两个模块将用于通信的“管道”
void setup() {
  Serial.begin(9600);
  radio.begin();   //初始化radio对象
  radio.openReadingPipe(0, address);   //使用radio.openReadingPipe()函数设置的接收机地址
  radio.setPALevel(RF24_PA_MIN);   //设置功率放大器级别,将其设置为最小值
  radio.startListening();    // 使用radio..startListening()将模块设置为接收机
}
void loop() {
  if (radio.available()) {  //判断是否有要接收的数据
    char text[32] = "";   //创建一个由32个元素组成的数组
    radio.read(&text, sizeof(text));  //读取数据,并将其存储到text变量中
    Serial.println(text);  //打印变量text的数据,即接收到的数据
    delay(1000);  //延迟等待1秒
  }
}

程序上传后点击接收方的串口监视器进行查看,每隔1秒出现“Hello World”字样

image

每次发送一次数据,接收端可以接收到一次数据,可以通过开发版重启按纽测试

send

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>   //NRF24L01 2.4G无线模块的库文件
RF24 radio(7, 8); //创建一个RF24的对象CE=7, CSN=8
const byte address[6] = "00001";  //创建一个数组,建立发送机地址,或者说两个模块将用于通信的“管道”
void setup() {
Serial.begin(9600);
delay(2000);
radio.begin();    //初始化radio对象
radio.openWritingPipe(address);  //使用radio.openWritingPipe()函数设置的发送机地址
radio.setPALevel(RF24_PA_MIN);  //设置功率放大器级别,将其设置为最小值
radio.stopListening();  // 使用radio.stopListening()函数将模块设置为发送机
//
//    const char text[] = "Hello World";  //创建一个字符数组,并为其分配消息”Hello World”
//    bool report = radio.write(&text, sizeof(text)); //使用radio.write()函数将消息发送给接收机,text是要发送的字符变量,
//    Serial.println(report);
}
void loop() {
Serial.println("send");
const char text[] = "Hello World";  //创建一个字符数组,并为其分配消息”Hello World”
bool report = radio.write(&text, sizeof(text)); //使用radio.write()函数将消息发送给接收机,text是要发送的字符变量,如果禁用自动确认,则任何传输尝试也将返回 true(即使未收到有效负载)。
Serial.println(report);
// sizeof(text))设置了我们要从text变量中获取的字节数
delay(5000);  //延迟等待1秒
}

receiver

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>   //NRF24L01 2.4G无线模块的库文件
RF24 radio(7, 8);   //创建一个RF24的对象CE=7, CSN=8
const byte address[6] = "00001";  //创建一个数组,建立接收机地址,或者说两个模块将用于通信的“管道”
void setup() {
Serial.begin(9600);
delay(2000);
Serial.println("receiver setup");
radio.begin();   //初始化radio对象
radio.openReadingPipe(0, address);   //使用radio.openReadingPipe()函数设置的接收机地址
radio.setPALevel(RF24_PA_MIN);   //设置功率放大器级别,将其设置为最小值
radio.startListening();    // 使用radio..startListening()将模块设置为接收机
}
void loop() {
//Serial.println("receiver loop");
if (radio.available()) {  //判断是否有要接收的数据
//Serial.println("get");
char text[32] = "";   //创建一个由32个元素组成的数组
radio.read(&text, sizeof(text));  //读取数据,并将其存储到text变量中
Serial.println(text);  //打印变量text的数据,即接收到的数据
//delay(1000);  //延迟等待1秒
}
}

const常量

const关键字代表常量 (Constant)。它用于修改变量性质,使其变为只读状态。常量可以像任何相同类型的其他变量一样使用,但不能改变其数值。也就是说,常量的数值在建立时一旦确定以后,如果在后续的程序中尝试改变常量数值,那么程序编译时将会报错。 const关键字定义的常量与其他变量遵守相同的规则。由于使用#define定义常量具有缺陷 ,所以用 const 关键字定义常量更加好一些。

示例

const float pi = 3.14;
float x;
void setup()
{
   x = pi * 2;    // 常量可用于数学运算
   pi = 7;        // 注意!常量数值不能改变。这句程序将报错。
}
void loop()
{
}

#DEFINE 或 CONST

您可以使用 const 或 #define 创建数字或字符串常量。但要创建arrays数组常量,只能使用const定义。

byte(字节)

byte类型变量可存储8位无符号数,其存储数值范围是 0 – 255。 byte类型变量在控制LED时显得格外有用,因为Arduino控制LED亮度或色彩时常常使用的数值是在0-255之间。

示例程序

byte b;  //创建byte类型变量b
void setup() {
Serial.begin(9600);
}
void loop() {
b++;
Serial.print("b = ");
Serial.println(b);
delay(100);
}

变量b的数值会从0开始逐1递增,在b的数值达到255时,当变量b再次执行b++操作后,变量b的数值将会复位到0,然后再次逐1递增,程序将会依次往复循环。

打开串口监视器,查看结果 image

指针运算符:&

& 取地址运算符: 它返回其操作数(即一个变量)在内存中的实际地址。 C语言中提供了地址运算符&来获取变量的地址,其一般形式为: &变量名; 假设有整数型变量a,那么&a表示变量a的地址。再假设我们还有一个指向整型变量的指针变量p,如要把变量a的地址赋予指针变量p可以用以下方式。

int a; //建立整数型变量a
int* p; //建立整数指针变量p
p=&a; //将变量a的地址赋予指针变量p
WangShuXian6 commented 2 years ago

NRF24L01 2.4G无线模块之按钮点亮LED灯

目标

利用NRF24L01 2.4G无线模块,按钮远程控制点亮LED灯

实验材料

Arduino UNO开发板2 NRF24L01 2.4G无线模块2 LED发光模块 按钮开关模块 配套USB数据线*2 配套杜邦线若干 Arduino IDE软件 image

内容

利用NRF24L01 2.4G无线模块,在一块Arduino UNO主板上按下按钮,另一块Arduino UNO主板上的LED灯被点亮5秒,5秒后再次熄灭。

接线图

image

接线方式

Arduino UNO1 <------> NRF24L01 2.4G无线模块1 3.3V <------> VCC GND <------> GND 8 <------> CSN 7 <------> CE
13 <------> SCK 11 <------> MOSI 12 <------> MISO Arduino UNO2 <------> NRF24L01 2.4G无线模块2 3.3V <------> VCC GND <------> GND 8 <------> CSN 7 <------> CE
13 <------> SCK 11 <------> MOSI 12 <------> MISO Arduino UNO2 <------> 按钮开关模块 5V <------> VCC GND <------> GND 2 <------> OUT Arduino UNO1 <------> LED发光模块 5V <------> VCC GND <------> GND 4 <------> IN

程序实现代码

发送端程序 Sender.ino

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>   //NRF24L01 2.4G无线模块的库文件
RF24 radio(7, 8);   //创建一个RF24的对象CE=7, CSN=8
const byte address[6] = "00001";  //创建一个数组,建立发送机地址,或者说两个模块将用于通信的“管道”
void setup() {
  pinMode(2, INPUT);   //初始化2号引脚为输入
  radio.begin();    //初始化radio对象
  radio.openWritingPipe(address);  //使用radio.openWritingPipe()函数设置的发送机地址
  radio.setPALevel(RF24_PA_MIN);  //设置功率放大器级别,将其设置为最小值
  radio.stopListening();  // 使用radio.stopListening()函数将模块设置为发送机
}
void loop() {
  if (digitalRead(2) == 1) {   //如果2号引脚为高电平,即按钮被按下
    const char text =  'a'; //创建一个字符数组,并为其分配消息a
    radio.write(&text, sizeof(text)); //使用radio.write()函数将消息发送给接收机,text是要发送的字符变量,
    // sizeof(text))设置了我们要从text变量中获取的字节数
    delay(1000);  //延迟等待1秒 不可以省略延迟,否则会在短时间内发送多次无线信号 导致 接受方多次收到信号而多次亮灯
  }
}

接收端程序 Receiver.ino

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>   //NRF24L01 2.4G无线模块的库文件
RF24 radio(7, 8);   //创建一个RF24的对象CE=7, CSN=8
const byte address[6] = "00001";  //创建一个数组,建立接收机地址,或者说两个模块将用于通信的“管道”
void setup() {
  pinMode(4, OUTPUT);   //初始化4号引脚为输出
  Serial.begin(9600);
  radio.begin();   //初始化radio对象
  radio.openReadingPipe(0, address);   //使用radio.openReadingPipe()函数设置的接收机地址
  radio.setPALevel(RF24_PA_MIN);   //设置功率放大器级别,将其设置为最小值
  radio.startListening();    // 使用radio..startListening()将模块设置为接收机
}
void loop() {
  if (radio.available()) {  //判断是否有要接收的数据
    char text = 0;      //创建一个空的字符变量text
    radio.read(&text, sizeof(text));  //读取数据,并将其存储到text变量中
    Serial.println(text);  //打印变量text的数据,即接收到的数据
    delay(1000);  //延迟等待1秒
    if (text == 'a') {   //如果接收到的数据是a,那么LED被点亮5秒,5秒后熄灭
      digitalWrite(4, HIGH);
      delay(5000);
      digitalWrite(4, LOW);
    } else {
      digitalWrite(4, LOW);
    }
  }
}