项目1 基于Arduino 的物联网网关设计_第1页
项目1 基于Arduino 的物联网网关设计_第2页
项目1 基于Arduino 的物联网网关设计_第3页
项目1 基于Arduino 的物联网网关设计_第4页
项目1 基于Arduino 的物联网网关设计_第5页
已阅读5页,还剩72页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2相关知识34任务小结与练习1任务实施任务引入与目标Arduino开发环境搭建一、任务引入与目标任务目标任务1介绍Arduino语言的特点和程序结构,安装Arduino开发环境,用于项目1的ESP32物联网网关设计。任务引入ESP32是乐鑫科技开发的一款32位微控制器,它集成了Wi-Fi及蓝牙功能,非常适合作为物联网开发中的网关使用,当然也可以作为普通的单片机使用。项目1将ESP32作为物联网网关,首先就需要为ESP32搭建开发环境。二、相关知识什么是Arduino语言Arduino使用C/C++编写程序,其中C语言是一种面向过程的编程语言,C++是一种面向对象的编程语言。早期的Arduino核心库是使用C语言编写,后来引进了面向对象的思想,目前最新的Arduino核心库采用C语言与C++混合编写而成。通常我们说的Arduino语言,是指Arduino核心库文件提供的各种应用程序编程接口(ApplicationProgrammingInterface,API)的集合。这些API是对更底层的单片机支持库进行二次封装所形成的。传统开发方式中,开发者需要理清每个寄存器的含义及其之间的关系,然后配置多个寄存器来达到开发的目的。而Arduino程序使用了清楚明了的API替代繁杂的寄存器配置过程,例如以下代码:pinMode(25,OUTPUT);digitalWrite(25,HIGH);pinMode(25,OUTPUT)是设置引脚的模式,这里设定了引脚IO25为输出模式;而digitalWrite(25,HIGH)是让IO25引脚输出高电平数字信号。Arduino使用户不用再理会单片机中繁杂的寄存器配置,就能直观地编写Arduino程序让ESP32工作,在增强了程序可读性的同时,也提高了开发的效率。二、相关知识Arduino程序结构Arduino的程序结构与传统的C/C++结构不同,在Arduino程序中没有main函数,Arduino程序的基本结构由setup和loop两个函数组成。控制器通电或复位后,即会开始执行setup函数中的程序,该部分只会执行一次。通常我们会在setup函数中完成Arduino的初始化设置,如配置I/O口状态、初始化串口等操作。在setup函数中的程序执行完后,Arduino会接着执行loop函数中的程序。loop函数是一个死循环,其中的程序会不断地重复运行。通常我们会在loop函数中完成程序的主要功能,如驱动各种模块、采集数据等。除了Arduino之外,ESP32还可以使用哪些开发环境?所使用的编程语言是什么?课堂讨论三、任务实施实施设备安装了Windows操作系统的计算机。实施过程1.软件安装通过官网https://www.arduino.cc/en/software下载,如图1-1所示,然后点击“安装”即可;或者通过系统应用安装。图1-1Arduino官网下载页面三、任务实施2.ESP32内核包安装在文件→首选项,输入下面的开发板管理器网址之一,如图1-2所示。http://download.dfrobot.top/FireBeetle/package_esp32_index.json/dl/package_esp32_index.json图1-2Arduino的开发板管理器网址三、任务实施在打开的开发板管理器中,输入“ESP32”,点击“安装”,如图1-3所示。图1-3在Arduino开发板管理器中安装内核包3.外设库文件安装将4个库文件复制到Arduino安装目录的libraries文件夹下,如图1-4所示。或者在项目→加载库→管理库中,搜索外设库名安装,效果相同。图1-4安装外设库文件图1-3在Arduino开发板管理器中安装内核包三、任务实施4.离线安装如果ESP32内核包下载太慢或多次失败,可以离线下载安装。(1)离线加载内核包。如图1-5所示,进入内核包所在目录,以下面开发板管理器网址为例介绍:http://download.dfrobot.top/FireBeetle/package_esp32_index.json打开图15中框2所在目录,并找到staging—packages目录,清空目录。将离线压缩包粘贴到里面,如图1-6所示。图1-5查找Arduino安装目录图1-6在本地加载内核包三、任务实施(2)安装内核包。打开开发板管理器,搜索esp32,选择版本,点击“安装”即可,如图1-7所示。内核包因为已经下载好,所以可以快速安装。(3)espressif内核包。另一个开发板管理器网址(/dl/package_esp32_index.json)对应的离线包如图1-8所示。图1-7安装离线加载的内核包图1-8

espressif内核包四、任务小结与练习任务小结任务1在计算机中搭建Arduino开发环境,并进行了相关配置。运行Arduino自带的示例程序,观察程序的结构和操作过程。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标ESP32的GPIO操作一、任务引入与目标任务目标任务2将学习ESP32的GPIO功能和相关函数,并通过GPIO初始化和GPIO数字输出函数,完成一个LED闪烁的例子。任务引入GPIO(GeneralPurposeInputOutput)是通用输入输出端口的简称,是ESP32作为微控制单元(MCU)使用时最基础的功能。用户可以利用GPIO功能,连接一些简单外设,实现检测和控制功能。二、相关知识ESP32资源图1-9是一款搭载了ESP32-WROOM-32D的开发板。ESP32的外围设备包括:10个电容传感GPIO、18个模数转换器(ADC)通道、2个数模转换器(DAC)、3个SPI接口、3个UART接口、2个I2C接口、16个脉冲宽度调制输出通道、2个I2S接口。具体引脚的标签可以查看所购置开发板的说明书。图1-9搭载了ESP32-WROOM-32D的开发板二、相关知识初始化GPIO函数语法:pinMode(pin,mode)作用:设置一个引脚(pin)作为GPIO时的I/O模式。参数:pin,引脚编号;mode,GPIO的I/O模式,取值有3种,分别是INPUT(数字输入)、OUTPUT(数字输出)和INPUT_PULLUP(数字输入,且使能引脚的内部上拉电阻)。语法:digitalWrite(pin,value)作用:设置一个数字输出引脚的输出电平值,即HIGH或LOW。参数:pin,引脚编号,此引脚必须在之前使用pinMode设置为OUTPUT模式;value,2个值,分别是LOW(输出低电平)、HIGH(输出高电平)。GPIO数字输出二、相关知识GPIO数字输入语法:intdigitalRead(pin)作用:读取一个数字输入引脚的电平值。返回:HIGH(高电平)或LOW(低电平)。参数:pin,引脚编号。三、任务实施实施设备部署了Arduino开发环境的计算机。实施过程1.打开示例程序打开示例程序Blink,如图1-10所示,另存到其他路径。图1-10Arduino中的示例Blink三、任务实施//thesetupfunctionrunsoncewhenyoupressresetorpowertheboardvoidsetup(){//initializedigitalpinLED_BUILTINasanoutput.pinMode(LED_BUILTIN,OUTPUT);}//theloopfunctionrunsoverandoveragainforevervoidloop(){digitalWrite(LED_BUILTIN,HIGH);//turntheLEDon(HIGHisthevoltagelevel)delay(1000);//waitforaseconddigitalWrite(LED_BUILTIN,LOW);//turntheLEDoffbymakingthevoltageLOWdelay(1000);//waitforasecond}Blink代码:三、任务实施//thesetupfunctionrunsoncewhenyoupressresetorpowertheboardvoidsetup(){//initializedigitalpinLED_BUILTINasanoutput.pinMode(25,OUTPUT);}//theloopfunctionrunsoverandoveragainforevervoidloop(){digitalWrite(25,HIGH);//turntheLEDon(HIGHisthevoltagelevel)delay(1000);//waitforaseconddigitalWrite(25,LOW);//turntheLEDoffbymakingthevoltageLOWdelay(1000);//waitforasecond}2.修改程序将程序中的引脚编号改为IO25,代码如下:三、任务实施3.硬件连接将LED的数据引脚接网关ESP32的IO25,GND对应连接。USB线的一头连接电脑USB接口,另一Micro-USB头接ESP32。4.运行测试开发板选择FireBeetle-ESP32,如果能正确识别端口,比如图1-9中的串口19(你的计算机不一定是这个号),如图1-11所示,就可以正常上传程序。如果识别不出来串口,则需要重新安装CP2102驱动。图1-11下载程序时选择开发板和配置端口三、任务实施点击“上传”按钮,按下boot键不松直到有上传进度,稍后显示上传成功,如图1-12所示。图1-12Arduino程序上传到ESP32成功观看实验结果,拍摄短视频上传到课程学习平台,要体现出:LED闪烁效果,程序中的引脚编号。四、任务小结与练习任务小结任务2通过GPIO初始化和GPIO数字输出函数,完成控制LED闪烁的功能。编写代码,实现LED闪烁:修改引脚编号;采用宏定义的方法,给引脚起别名。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标ESP32的串口功能一、任务引入与目标任务目标任务3将学习ESP32的串口功能和相关方法,并利用串口打印和读取串口数据的方法,编写一个工程,测试数据接收功能。任务引入任务2为ESP32编写了简单的LED控制程序,容易观察结果是否正确。如果是比较复杂的程序,当运行有问题时,该怎样调试呢?这就需要用到串口的打印输出功能,可以将程序运行过程的一些状态打印出来。当然串口还有数据输出和数据输入的功能,都是比较常用的。二、相关知识Arduino中UART协议在Arduino中,串行通信协议是一种常见的通信方式,通过一个或多个串口连接两个或多个设备。串行通信协议可以使用不同的协议和格式,最常见的是UART(通用异步收发器)协议。UART协议使用两个引脚进行通信:TX(发送)和RX(接收)。当设备1向设备2发送数据时,它将数据写入TX引脚,并且设备2会从其对应的RX引脚读取数据。这种通信通常是基于字节的,即一个字节一个字节地发送和接收。每个字节都由一个起始位、一个或多个数据位、一个可选的奇偶校验位和一个或多个停止位组成。在Arduino中,串口通信通常使用Serial库来实现。需要注意的是,在进行串行通信时,需要确保发送和接收端的波特率(数据传输速率)是相同的,否则可能会导致通信失败。波特率可以在初始化串口对象时设置。二、相关知识ESP32的串口ESP32共有3个UART端口,其中UART1用于Flash读/写,见表1-1。UART0在Arduino程序中的对象名是Serial,UART2在Arduino程序中的对象名是Serial2,对应的发送和接收引脚见表11。比较方便的安排是:用Serial进行打印调试,用Serial2与其他设备进行串口通信。串口名Arduino名TXRXUART0Serialpin1pin3UART1Serial1pin10pin9UART2Serial2pin17pin16图1-10Arduino中的示例Blink三、任务实施实施设备部署了Arduino开发环境的计算机。实施过程1.下载示例StringToInt程序如下:StringinString="";//stringtoholdinputvoidsetup(){//Openserialcommunicationsandwaitforporttoopen:Serial.begin(9600);while(!Serial){;//waitforserialporttoconnect.NeededfornativeUSBportonly}//sendanintro:Serial.println("\n\nStringtoInt():");Serial.println();}voidloop(){//Readserialinput:while(Serial.available()>0){intinChar=Serial.read();if(isDigit(inChar)){//converttheincomingbytetoacharandaddittothestring:inString+=(char)inChar;}三、任务实施//ifyougetanewline,printthestring,thenthestrings'value:if(inChar==\'n'){Serial.print("Value:");Serial.println(inString.toInt());Serial.print("String:");Serial.println(inString);//clearthestringfornewinput:inString="";}}}在setup初始化函数中,调用Serial对象的begin方法设置波特率为9600,注意与之连接的另一个设备的波特率要求一致。在loop循环函数中,调用Serial对象的available方法判断是否收到串口数据,是的话就读取数据。Serial对象的read方法每次只读一个字符(字节),通过While循环将串口缓冲区的所有数据全部读取,将其中满足数字格式的字符(如“2”)拼接为字符串inString。如果遇到结束符(换行符),则调用Serial的print和println方法打印调试信息。三、任务实施2.运行效果下载程序后,打开串口监视器,波特率设为9600,效果如图1-13所示。图1-13数据收发工作效果从电脑发送字符串"12"到ESP32的Serial串口,ESP32将接收的字符串转为数字后按照格式"Value:12"发送给电脑。如果电脑发送的字符串中不包含数字部分,则功能不能实现。四、任务小结与练习任务小结任务3编写一个工程,利用串口打印和读取串口数据的方法,测试数据接收功能。修改程序中的波特率为115200,观察串口监视器接收区工作情况;再设置串口监视器的波特率为115200,观察运行情况。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标串口接收事件处理一、任务引入与目标任务目标任务4将串口接收部分写成单独的处理函数,在loop函数中调用即可。需要约定接收字符串的结束符。任务引入任务3使用了Serial,做了相关配置,可以进行串口读写操作。但是处理过程全部放在loop函数中,不清晰。如果将串口接收部分写成单独的处理函数,会更加方便。二、相关知识串口初始化方法(以Serial对象为例)语法:Serial.begin(speed,config)参数:speed,波特率,一般取值9600、115200;config:设置数据位、校验位和停止位,默认SERIAL_8N1表示8个数据位,无校验位,1个停止位。返回值:无。如果对Serial2进行初始化,则只需要把对象名改为Serial2即可。下面介绍串口的常用方法,以Serial对象为例。如果Serial2使用这些方法,则只需要把对象名改为Serial2即可。串口打印方法(以Serial对象为例)语法:Serial.print(val)功能:串口输出数据,写入字符数据到串口。参数:val,打印的值,任意数据类型。与print方法类似的,还有println方法,会自动在打印的数据后面加上一个换行符。二、相关知识判断串口缓冲区的状态(以Serial对象为例)语法:Serial.available()功能:判断串口缓冲区的状态,返回从串口缓冲区读取的字节数。参数:无。返回值:可读取的字节数。读取串口数据(以Serial对象为例)语法:Serial.read()功能:读取串口数据,一次读一个字符,读完后删除已读数据。参数:无。返回值:返回串口缓存中第一个可读字节,当没有可读数据时返回-1,整数类型。三、任务实施实施设备部署了Arduino开发环境的计算机。实施过程1.硬件连接硬件只要用USB线将ESP32和计算机连接即可,如图1-14所示。图1-14任务4硬件连接示意图三、任务实施voidserialEvent(){while(Serial.available()){//getthenewbyte:charinChar=(char)Serial.read();//addittotheinputString:inputString+=inChar;//iftheincomingcharacterisanewline,setaflagsothemainloopcan//dosomethingaboutit:if(inChar==\'n'){stringComplete=true;}}}编写SerialEvent函数,调用Serial对象的available方法判断是否收到串口数据,是的话就读取数据。Serial对象的read方法每次只读一个字符(字节),通过While循环将串口缓冲区的所有数据全部读取,拼接为字符串inputString。如果遇到结束符(换行符),则将标志stringComplete设置为真(代表接收到完整字符串inputString),供接下来的loop函数查询判断。2.编写SerialEvent函数如果缓冲器有串口数据,则将其中的字符一个一个放入字符串inputString里。三、任务实施StringinputString="";//aStringtoholdincomingdataboolstringComplete=false;//whetherthestringiscompletevoidsetup(){//initializeserial:Serial.begin(9600);//reserve200bytesfortheinputString:inputString.reserve(200);}voidloop(){//printthestringwhenanewlinearrives:if(stringComplete){Serial.print(inputString);//clearthestring:inputString="";stringComplete=false;}serialEvent();}程序中定义了2个变量,inputString用于存放接收的字符串,stringComplete是接收完成的标志,在SerialEvent函数中已经介绍过。在setup函数中,调用Serial的begin方法,设置波特率为9600。在loop函数中,判断stringComplete是否为真(串口数据完成)。如果为真,则对inputString做进一步处理,最后清除inputString的值和stringComplete标志位。3.setup和loop函数三、任务实施4.运行效果下载程序后,打开串口监视器,设置波特率为9600。从串口监视器的发送区输入任意字符串发送,在接收区可观察到与发送内容相同的字符串,如图1-15所示。图1-15任务4运行效果四、任务小结与练习任务小结任务4将串口接收部分写成单独的处理函数serialEvent,当接收完毕后,在loop函数中调用即可,实现了串口数据的收发功能,程序结构清晰。用户如果想使用Serial2,则只需要将程序中的Serial对象名称修改为Serial2即可。修改程序中的波特率为115200,观察运行情况。实现大写变小写,Serial将计算机发来的字符串发回,但如果其中有大写字符,则将其转换为小写字符。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标Arduino程序中的JSON解析一、任务引入与目标任务目标任务5通过计算机向ESP32的串口发送满足JSON对象格式的字符串,ESP32收到后解析并控制LED灯。使用ArduinoJson库对接收的数据进行解析。任务引入通过serialEvent函数的设计,程序很清晰。接下来,我们思考怎样把解析过程变得清晰起来,可以用到JSON数据格式。这是一种跨语言的数据格式,C语言、Java、JavaScript都要使用,会贯穿于网关设计、APP设计和后端设计全过程。二、相关知识JSON对象数据格式JavaScript对象表示法(JavaScriptObjectNotation)是一种轻量级的文本数据交换格式。它独立于语言,具有自我描述性,容易被理解和使用。比如一个JSON对象:{"motor":{"left":100,"right":20},"servo":{"servo_a":90}}。其中,有两个成员(也是JSON对象),分别是motor、servo。JSON对象的成员是键值对,键和值之间用冒号分隔,键值对之间用逗号分隔。ArduinoJson库的构造类在Arduino中解析JSON数据,可以交给ArduinoJson库处理,但一定是从外到里一层层地获取。JsonBuffer作为ArduinoJson库的入口,负责处理整个JSON数据的内存管理以及构造解析工作,它包括两个实现类:二、相关知识(1)DynamicJsonBuffer,内存分配在heap区,无固定大小,可以自动增长所需空间,方法调用完自动回收;(2)StaticJsonBuffer,内存分配在stack区,有固定大小,大小值由开发者定义,方法调用完自动回收。JsonBuffer对象的方法(1)parseObject方法:功能是将字符串转换为JSON对象。能否转换成功,要看字符串本身是否满足JSON对象格式。(2)Success方法:判断JSON对象是否有效。很明显,parseObject方法后面应该有一个Success方法进行判断,然后进行解析才有意义。三、任务实施实施设备部署了Arduino开发环境的计算机。实施过程1.工程目标对一个成员的JSON对象解析工程名为OneKeyValue,串口接收符合JSON对象格式的字符串,通过ArduinoJson库进行解析。假如串口收到字符串{"LightStatus":1},点亮灯;收到字符串{"LightStatus":0},熄灭灯;收到其他字符串(不满足JSON对象格式),不处理。可见,JSON对象里只有一个成员,键(字段)是“LightStatus”。三、任务实施#include<ArduinoJson.h>StringinputString="";//aStringtoholdincomingdataboolstringComplete=false;//whetherthestringiscomplete//引脚定义#defineLIGHT25//产品标识符StringIdentifier="LightStatus";voidsetup(){//initializeserial:Serial.begin(9600);//reserve200bytesfortheinputString:inputString.reserve(200);pinMode(LIGHT,OUTPUT);}2.程序设计voidloop(){//printthestringwhenanewlinearrives:if(stringComplete){Serial.println(inputString);//解析,控制,约定Json格式:{"LightStatus":1},{"LightStatus":0}StaticJsonBuffer<200>jsonBuffer;JsonObject&root=jsonBuffer.parseObject(inputString);if(!root.success()){Serial.println("parseObject()failed");inputString="";stringComplete=false;return;}constchar*val=root[Identifier];三、任务实施if(val!=NULL){constuint16_tLightStatus=root[Identifier];if(LightStatus==1){digitalWrite(LIGHT,HIGH);}else{digitalWrite(LIGHT,LOW);}Serial.print("LightStatus:");Serial.println(LightStatus);}//clearthestring:inputString="";stringComplete=false;}serialEvent();}voidserialEvent(){while(Serial.available()){//getthenewbyte:charinChar=(char)Serial.read();//addittotheinputString:inputString+=inChar;//iftheincomingcharacterisanewline,setaflagsothemainloopcan//dosomethingaboutitif(inChar==\'n'){stringComplete=true;}}}三、任务实施我们下面主要分析loop函数中的解析过程:当串口接收到字符串inputString后,调用jsonBuffer对象的parseObject,将字符串转为JSON对象root,可能成功,也可能不成功。调用root对象的success方法,判断root是否是JSON对象:如果不是JSON对象,则没有必要进行解析了,清除inputString和标志后返回;如果是JSON对象,则执行接下来的解析过程。解析过程中,取出JSON对象“LightStatus”字段的值,如果非空,第二次取出后,根据值控制LED的亮和灭。在以上解析过程中,需要注意两点:一是先转换再解析,转换过程可能不成功;二是解析两次,避免未收到命令即解析值为NULL,但赋值为0,控制LED熄灭的错误操作。3.硬件连接LED灯的数据引脚连接IO25。下载线连接,因为ESP32开发板有USB转串口芯片CP2102,将USB口转为串口Serial,也就是说本任务中ESP32使用的是Serial。三、任务实施4.运行效果下载程序后,打开串口监视器,波特率为9600。计算机发送字符串:{"LightStatus":1}(后面加上换行符作为结束符),红灯点亮,并且串口监视器接收区显示:LightStatus:1,效果如图1-16所示。图1-16点亮红灯三、任务实施计算机发送字符串{"LightStatus":0}(后面加上换行符作为结束符),红灯熄灭,并且串口监视器接收区显示LightStatus:0,效果如图117所示。图117关闭红灯四、任务小结与练习任务小结任务5中通过计算机往ESP32的串口发送满足JSON对象格式的字符串,由一个成员构成。ESP32收到后,使用ArduinoJson库解析,并控制LED灯。计算机发送满足JSON对象格式的字符串,如{"Light":1}和{"Light":0},修改程序解析,观察结果。注意字符串后面加上换行符作为结束符,双引号是在英文输入法状态下输入的。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标多成员JSON对象的JSON解析一、任务引入与目标任务目标任务6对串口接收的JSON对象格式数据进行解析,串口收到的字符串可能是:针对1个灯的:{"RedStatus":1}或{"RedStatus":0},{"BlueStatus":1}或{"BlueStatus":0}。针对2个灯的:{"RedStatus":1,"BlueStatus":0}或{"RedStatus":1,"BlueStatus":1},{"RedStatus":0,"BlueStatus":0}或{"RedStatus":0,"BlueStatus":1}。我们只有通过合理的设计,才能避免类似这个错误:发送控制红灯命令时,蓝灯却熄灭了。任务引入任务5通过对由一个成员组成的JSON对象数据的解析,实现了对LED的控制。如果希望控制多个灯、多个设备,那就需要由多个成员组成的JSON对象数据。二、相关知识字符串对象使用字符串对象的好处是可以方便地进行字符串的拼接和处理。例如,要定义一个字符串对象并将其初始化为“HelloWorld!”,可以使用以下代码:StringmyString="HelloWorld!";注意,在使用字符串对象时需要注意内存的分配,因为字符串对象会动态分配内存。如果不小心使用了太多的字符串对象,则可能会导致内存耗尽而程序崩溃。字符数组使用字符数组定义字符串可以避免上述问题,但与字符串对象相比,它更难以操作和处理。例如,要定义一个字符数组并将其初始化为“HelloWorld!”,可以使用以下代码:charmyString[]="HelloWorld!";需要注意的是,字符数组的长度需要足够容纳所存储的字符串,而且在定义后无法动态调整大小。在Arduino中,可以使用字符串对象、字符数组或字符串指针来定义字符串。二、相关知识字符串指针在Arduino中,我们可以通过指针来定义字符串。这种方法与字符数组的方式类似,但使用指针可以更好地控制和操作内存。例如,要定义一个指向字符串常量“Hello

World!”的指针,可以使用以下代码:constchar*myString="HelloWorld!";在这个例子中,我们使用了const关键字来指定myString指针所指向的字符串是一个常量,并且不允许修改。需要注意的是,当使用指针定义字符串时,必须确保所指向的内存不会被意外修改,否则可能会导致程序出现未知错误。因此,在使用指针定义字符串时,我们应该尽可能避免对它们进行写入操作。三、任务实施实施设备部署了Arduino开发环境的计算机。实施过程1.程序设计代码如下:#include<ArduinoJson.h>StringinputString="";//aStringtoholdincomingdataboolstringComplete=false;//whetherthestringiscomplete//引脚定义#defineLIGHT_RED25#defineLIGHT_BLUE26//产品标识符StringIdentifier1="RedStatus";StringIdentifier2="BlueStatus";voidsetup(){//initializeserial:Serial.begin(9600);//reserve200bytesfortheinputString:inputString.reserve(200);pinMode(LIGHT_RED,OUTPUT);pinMode(LIGHT_BLUE,OUTPUT);}三、任务实施voidloop(){//printthestringwhenanewlinearrives:if(stringComplete){Serial.println(inputString);//解析,控制,约定JSON格式//红灯:{"RedStatus":1},{"RedStatus":0}//蓝灯:{"BlueStatus":1},{"BlueStatus":0}//针对2个灯:{"RedStatus":1,"BlueStatus":1},{"RedStatus":0,"BlueStatus":0}StaticJsonBuffer<200>jsonBuffer;JsonObject&root=jsonBuffer.parseObject(inputString);2.程序设计if(!root.success()){Serial.println("parseObject()failed");inputString="";stringComplete=false;return;}constchar*val1=root[Identifier1];constchar*val2=root[Identifier2];if(val1!=NULL){constuint16_tRedStatus=root[Identifier1];if(RedStatus==1){digitalWrite(LIGHT_RED,HIGH);}else{digitalWrite(LIGHT_RED,LOW);}Serial.print("RedStatus:");Serial.println(RedStatus);}三、任务实施if(val2!=NULL){constuint16_tBlueStatus=root[Identifier2];if(BlueStatus==1){digitalWrite(LIGHT_BLUE,HIGH);}else{digitalWrite(LIGHT_BLUE,LOW);}Serial.print("BlueStatus:");Serial.println(BlueStatus);}//clearthestring:inputString="";stringComplete=false;}serialEvent();}voidserialEvent(){while(Serial.available()){//getthenewbyte:charinChar=(char)Serial.read();//addittotheinputString:inputString+=inChar;//iftheincomingcharacterisanewline,setaflagsothemainloopcan//dosomethingaboutitif(inChar==\'n'){stringComplete=true;}}}三、任务实施和任务5中的代码相比,本任务初始化、解析都是针对多个灯,但基本的逻辑是一样的。简要介绍一下:一是先转换再解析,转换过程可能不成功,程序中通过success方法判断root对象是否是JSON对象;二是解析两次,避免收到控制红灯命令时关闭蓝灯的误操作,也避免了收到控制蓝灯命令时关闭红灯的误操作。3.运行效果硬件方面,ESP32接三色灯的2个数据引脚即可,其中IO25接R引脚,IO26接B引脚。下载程序后,打开串口监视器,波特率为9600;发送不同的JSON数据,经解析和处理后,可以看到不同的颜色,如图1-18所示。图1-18不同颜色灯控制效果四、任务小结与练习任务小结任务6对串口接收的JSON对象格式数据进行解析,串口收到的字符串是由多个成员组成的,就可以用来控制多个灯。观察不同命令时LED的颜色变化。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标ESP32的Serial2操作一、任务引入与目标任务目标任务7实现串口设备A的按键按下后,通过Serial2发送控制命令给串口设备B。其中,A设备以JSON格式发送字符串,B设备接收解析后控制LED亮灭。任务引入前面几个任务都是针对Serial操作的,Serial比较适合用于程序打印调试信息。如果要进行与其他串口设备的串口通信,则使用Serial2串口是比较方便的。二、相关知识Arduino中的宏定义在Arduino中,宏定义是一种预处理指令,可以用来创建常量或简化代码。通过宏定义,程序员可以在程序中使用自定义的符号来代替常量或表达式。例如:#defineLED_PIN13该宏定义13为LED_PIN,这样我们就可以在程序中使用LED_PIN来代替数字13。如果我们要改变使用的引脚,则只需要修改这个宏定义,而不需要修改整个程序。强制类型转换在Arduino中,强制类型转换是将一种数据类型的值转换为另一种数据类型的值的过程。强制类型转换可以帮助我们在不同数据类型之间进行转换,并允许我们使用不同的算术和逻辑操作。比较常见的是C语言风格的强制类型转换,这种转换使用括号将要转换的值包围起来,并指定要转换的目标类型。例如:intx=10;floaty=(float)x;在这个例子中,我们将整数变量x强制转换为浮点数,并将结果存储在浮点型变量y中。三、任务实施实施设备部署了Arduino开发环境的计算机。实施过程1.硬件连接串口的引脚可以查看表1-2。引脚连接如下:Button_out———ESP32A_IO26

Button_GND———ESP32A_GNDButton_VCC———ESP32A_VCC

ESP32A_IO17———ESP32B_IO16ESP32A_IO16———ESP32B_IO17

ESP32A_GND———ESP32B_GNDLED_R———ESP32B_IO25

LED_GND———ESP32B_GND串口名Arduino名TXRXUART0Serialpin1(TXD0)pin3(RXD0)UART1Serial1pin10pin9UART2Serial2pin17pin16表1-2ESP32的串口引脚三、任务实施连接示意如图1-19所示。实物连接如图1-20所示。图1-19任务7硬件连接示意图图1-20任务7硬件连接实物图三、任务实施constintbuttonPin=26;//thenumberofthepushbuttonpinintbuttonState=0;//variableforreadingthepushbuttonstatusuint16_tLightStatus=0;voidsetup(){Serial.begin(9600);Serial2.begin(9600);pinMode(buttonPin,INPUT);}voidloop(){buttonState=digitalRead(buttonPin);}2.设备A程序(1)按键检测。在02-Button的示例程序基础上修改,代码如下:if(buttonState==HIGH){if(LightStatus==0){Serial2.print("{\"LightStatus\":0}\n");Serial.print("{\"LightStatus\":0}\n");LightStatus=1;}else{Serial2.print("{\"LightStatus\":1}\n");Serial.print("{\"LightStatus\":1}\n");LightStatus=0;}}三、任务实施下载运行,发现每按下一次,设备A的Serial会打印很多条内容,说明按下一次会检测到多次,如图1-21所示。这是什么原因呢?需要了解一下按键的知识,如图1-22所示。从按键按下之后输出电平的变化可知:对按键的检测,需要考虑干扰情况(需要延时再检测),再考虑按键长按的情况(需要等待释放)。图1-21打印按键检测结果图1-22按键电路输出电平变化情况三、任务实施constintbuttonPin=26;//thenumberofthepushbuttonpinintbuttonState=0;//variableforreadingthepushbuttonstatusuint16_tLightStatus=0;voidsetup(){Serial.begin(9600);Serial2.begin(9600);pinMode(buttonPin,INPUT);}(2)增加消抖和等待释放处理的按键检测。在上面分析的基础上,修改代码如下:voidloop(){//buttonState=digitalRead(buttonPin);if(digitalRead(buttonPin)==HIGH){delay(10);//延时消抖if(digitalRead(buttonPin)==HIGH){while(digitalRead(buttonPin));//等

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论