更多内容请访问:与华为官方共建的鸿蒙技术社区https://harmonyos.51cto.com标记:如果本文有超过10000次阅读,或者超过100个赞+收藏,我就发布鸿蒙版遥控信号灯等智能硬件文章!!本文涉及的源码及其他资源见附件!【ArduinoLab】关于智能硬件的实验网上绝对没有(我也贴过),都是作者一个人设计的。敬请期待后面的【鸿蒙实验室】系列文章和视频课程。本案例是Python、PyQT6和Arduino的组合。通过Arduino开发板控制3个LED(红黄绿)模拟红绿灯。点击PC端的3个??灯即可控制Arduino开发板和3个LED。您也可以点击“自动”按钮使信号灯自动变化。该系统完全模拟了真实信号灯的自动切换过程。首先红灯亮6秒(为了减少一个完整的变化周期的时间,信号灯不要亮太久),然后立即切换到绿灯,并持续亮6秒。接下来绿灯闪6次(1秒闪一次,一亮一灭),然后切换到黄灯,亮3秒,最后转红灯(亮6秒),完成一个信号周期。如果点击“停止”按钮,信号灯会自动停止切换,但会在完成一个信号周期后停止。视频演示见附件。1、需要准备哪些实验仪器设备?本次实验需要准备的设备如下:(1)PC一台,系统可以是Windows、macOS或Linux,需要安装Python环境、PyQt6、ArduinoIDE;(2)Arduino开发板一块,推荐UNO;(3)3颗LED,推荐红黄绿各一颗;(4)ESP8266Wi-Fi模块1个,用于联网;(5)10K电阻1个;(6)一块面包板,主要用于解决Arduino开发板接口不足的问题;(7)杜邦线有好几条,可以多准备一些(最好是多色的),反正很便宜。需要两种类型的杜邦电缆:公对公和公对母;2、ESP8266Wi-Fi模块与Arduino开发板连接玩物联网,其实涉及到硬件和软件。硬件主要涉及选型和连接,一般不涉及硬件设计和制作。本次实验的核心模块是ESP8266,是一款Wi-Fi模块,价格很便宜,国内价格在15-20元之间,有些宝有卖。第一步是使用杜邦线将ESP8266连接到Arduino开发板。程序上传到Arduino开发板,然后通过AT命令与ESP8266模块进行交互。ESP8266的外观如图1所示,该模块比其他大部分模块(如超声波模块、LED、按键等)都要复杂,一共有8个引脚,即8个引脚。ESP8288一般直接与Arduino开发板相连。Arduino开发板的外观如图2所示,引脚都是眼睛,需要多根公母杜邦线。现在回到图1中的8个引脚,其实在开发阶段,只需要连接其中的5个即可。刷固件的时候一般需要接6个pin(刷ESP8266固件的问题后面会写文章介绍)。需要接的5个管脚如下:(1)3.3v:接Arduino开发板的3.3v插孔,记住,一定要3.3v,不要接5v,否则需要另外买ESP8266,记住,记住,记住;(2)EN:同样需要接3.3v,但是Arduino开发板只有一个3.3v插口,所以需要使用面包板;(3)GND:接Arduino开发板的GND插孔(一般有3个,插任意一个GND插孔即可);(4)TX:一般接软串口,本例接8;(5)RX:一般接软串口,本例接9;3.模拟连接ESP8266与Arduino开发板在正式连接之前,最好使用Fritzing模拟连接,相当于画了一张草图,避免连接错误。连接后的效果如图3所示,这里需要说明一下,EN和3.3v都需要接到Arduino开发板的3.3v引脚上,但是Arduino开发板只有一个3.3v引脚,所以先将Arduino开发板的3.3v引脚通过杜邦线(图3中红线)连接到面包板,然后EN和3.3v通过杜邦线(两条橙色线)接入面包板,切记其中一条橙色线必须与红色线在同一列,另一条橙色线在另一列,并将这两列连接一个10K的电阻,以防止ESP8266的EN和3.3v两个引脚以免因直接连接而短路。注意一定要接电阻,推荐10K欧姆的电阻。4.连接3个LED就简单多了。LED如图4所示。较短(左)的引脚接地,较长(右)的引脚连接到数字引脚。本例中绿色、黄色、红色分别接7、6、5脚。由于Arduino开发板只有3个GND脚,而ESP8266已经占了一个,所以还是需要扩展GND脚面包板。基本原理是将GND通过杜邦线(本例中为黑色线)连接到面包板,然后将3个LED的GND端插入面包板上与黑色杜邦线同一列的其他插孔中杜邦线。最终效果如图5所示。5.在Arduino开发板上创建一个TCP服务器。ESP8266与Arduino交互通常有两种方式:(1)ESP8266作为服务器;(2)ESP8266作为客户端;我会写文章介绍。无论使用哪种方式,ESP8266都必须先联网。一般连接在家里的无线路由器,或者手机做的热点。设置ESP8266需要传递AT命令,AT命令实际上是一组解释执行的命令,类似于DOS命令。ESP8266出厂时的波特率为115200,所以AT指令必须按照这个波特率执行。在setup函数中使用如下代码设置波特率,执行AT命令连接路由器。#includeSoftwareSerialwifi(WIFI_RX,WIFI_TX);//RX,TXvoidsetup(){Serial.begin(9600);wifi.begin(115200);Serial.println("systemisready!");wifi.println("AT+CWMODE=3\r\n");//设置ESP8266的模式,3表示可以作为路由器模式(AP)为其他设备提供Wi-Fi上网,或者可以像普通设备建立TCP连接delay(500);wifi.println("AT+CIPMUX=1\r\n");delay(500);wifi.println("AT+CWJAP=\"routername\",\"routerpassword\"\r\n");//连接路由器,请修改自己的路由器明和路由器密码delay(500);wifi.println("AT+CIPSERVER=1,5000\r\n");//启动TCP服务,端口号为5000delay(500);}这里的wifi负责与软串口通信(通常硬串口主要用于刷固件),wifi.println函数用于执行AT命令。需要注意的是,每执行一条AT命令,都要等待一定的时间,这里是500毫秒。第一次通过后,除非重启Arduino开发板或重新上传程序,否则setup函数只会执行一次。以后可以去掉连接路由器的代码,因为ESP8266有记忆功能,这种配置性质的AT指令执行后会记录执行结果。因此,下次重启ESP8266模块时,无论是否执行AT指令,ESP8266都会自动连接路由器。但是其他的代码要保留,因为这些代码的执行结果不会被记录下来。当ESP8266模组重启后,需要重新执行这些AT命令来建立TCP服务。经测试,ESP8266在115200波特率下通过Wi-Fi传输数据时容易出现乱码,所以需要使用如下代码,将ESP8266模块的波特率强制改为9600,这样数据传输就很流畅了稳定的。wifi.println("AT+CIOBAUD=9600\r\n");在Arduino开发板上建立TCP服务器的完整代码如下:#include#defineWIFI_TX9#defineWIFI_RX8#defineLED_RED7#defineLED_YELLOW6#defineLED_GREEN5SoftwareSerialwifi(WIFI_RX,WIFI_TX);//RX,TXStringcommand="";//接收客户端发送的数据voidsetup(){//将5、6、7三个引脚设置为输出,以便输出高电平点亮LEDpinMode(LED_RED,OUTPUT);pinMode(LED_YELLOW,输出);pinMode(LED_GREEN,OUTPUT);//先将5、6、7三个引脚设置为低电平,默认LED熄灭digitalWrite(LED_RED,LOW);digitalWrite(LED_YELLOW,LOW);digitalWrite(LED_GREEN,LOW);Serial.begin(9600);wifi.begin(9600);//已经改为9600,所以这里通过9600波特率,客户端通过Wi-FI传输维护局Serial.println("systemisready!");wifi.println("AT+CWMODE=3\r\n");delay(500);wifi.println("AT+CIPMUX=1\r\n");delay(500);wifi.println("AT+CIPSERVER=1,4999\r\n");delay(500);}//这个函数会不断调用voidloop(){//从客户端(PC端)读取发送的数据while(wifi.available()>0){command+=char(wifi.read());delay(4);}//如果数据不为空,继续处理if(command!=""){//将接收到的命令输出到串口监视器连续剧.println(command);//命令会自动加上一个前缀+IPD,如果包含这个前缀,就是传递过来的命令if(command.indexOf("+IPD")>-1){if(command.indexOf("close_red")>-1){digitalWrite(LED_RED,LOW);//0灯灭Serial.println("close_red");}elseif(command.indexOf("close_yellow")>-1){digitalWrite(LED_YELLOW,LOW);//0熄灭Serial.println("close_yellow");}elseif(command.indexOf("close_green")>-1){digitalWrite(LED_GREEN,LOW);//0熄灭Serial.println("close_green");}elseif(command.indexOf("open_red")>-1){digitalWrite(LED_RED,HIGH);//1灯亮Serial.println("open_red");}elseif(command.indexOf("open_yellow")>-1){digitalWrite(LED_YELLOW,HIGH);//1灯亮Serial.println("open_yellow");}elseif(command.indexOf("open_green")>-1){digitalWrite(LED_GREEN,高的);//1灯亮Serial.println("open");}}command="";}}阅读这段代码并注意,这里有6个命令:close_red(红色LED关闭),open_red(红色LED打开),close_yellow(黄色LED关闭),open_yellow(黄色LED亮),close_green(绿色LED灭),open_green(绿色LED亮),只要command中包含6个命令串中的一个,就确定是client发出了command。然后使用ArduinoIDE上传程序(不要忘记选择开发板和端口)PS:如果要更改端口号,可以直接修改5000,然后需要重启Arduino开发板(当然,ESP8266也会重启),这样就会重启执行setup函数,重启TCP服务。6、编写Python程序这里,编写客户端程序,使用PyQt6编写UI,使用Python编写所有的业务逻辑。由于代码较多,只给出核心代码。基本原理是Python通过TCPSocketAPI连接到ESP8255中的TCPServer,然后不断发送上一节给出的6条命令。importTrafficLight1importsysimportsocketfromPyQt6.QtWidgetsimportQApplication,QMainWindow,QMessageBoxfromPyQt6importQtGuifromPyQt6.QtCoreimportQThread"""讲师:李宁(梦娜李宁)微信:unitymarvel微信公众号:极客原点B站:https://space.bilibili.com/4377"0线程类0,用于自动切换信号量close_all_light()#开始自动切换信号灯whileself.running:#红色信号灯开启6秒self.events.open_light("red")QThread.msleep(6000)self.events.close_light("red")QThread.msleep(200)#绿色信号灯亮5秒self.events.open_light("green")QThread.msleep(6000)#绿色信号灯闪烁5次count=0whilecount<5:self.events.close_light("green")QThread.msleep(500)self.events.open_light("green")QThread.msleep(500)count+=1self.events.close_light("green")QThread.msleep(200)#黄色信号灯显示2秒self.events.open_light("yellow")QThread.msleep(3000)self.events.close_light("yellow")QThread.msleep(200)self.events.close_all_light()print("退出自动运行状态")#包含UI事件类代码Events:def__init__(self,ui):self.ui=uiself.connected=False#是否与Arduino建立连接self.client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#声明协议类型,不写类型,使用默认self.workThread=WorkThread(self)defclose_all_light(self):self.close_light("red")QThread.msleep(200)self.close_light("yellow")QThread.msleep(200)self.close_light("green")QThread.msleep(200)#开启LED(color参数用于指定开启哪种颜色)defopen_light(self,color):ifself.connected:self.client.sendall(("open_"+color).encode())ifcolor=='red':self.ui.labelRedLight.setPixmap(QtGui.QPixmap(""))self.ui.labelRedLight.state="open"elifcolor=='yellow':self.ui.labelYellowLight.setPixmap(QtGui.QPixmap(""))self.ui.labelYellowLight.state="open"elifcolor=='green':self.ui.labelGreenLight.setPixmap(QtGui.QPixmap(""))self.ui.labelGreenLight.state="open"returnTrueelse:QMessageBox.warning(self.ui.centralwidget,"Warning","请先连接Arduino,再开灯")returnFalse#TurnofftheLED(颜色参数用于指定关闭哪种颜色)defclose_light(self,color):ifself.connected:self.client.sendall(("close_"+color).encode())ifcolor=='red':self.ui.labelRedLight.setPixmap(QtGui.QPixmap("close_light.png"))self.ui.labelRedLight.state="close"elifcolor=='yellow':self.ui.labelYellowLight.setPixmap(QtGui.QPixmap("close_light.png"))self.ui.labelYellowLight.state="close"elifcolor=='green':self.ui.labelGreenLight.setPixmap(QtGui.QPixmap("close_light.png"))self.ui.labelGreenLight.state="close"returnTrueelse:QMessageBox.warning(self.ui.centralwidget,"Warning","请先连接Arduino,然后关灯")returnFalse#点击红灯触发defred_light_mouse_press_event(self,event):ifui.labelRedLight.state=="open":self.close_light("red")elifui.labelRedLight.state=="close":self.open_light("red")#点击黄灯时触发defyellow_light_mouse_press_event(self,event):ifui.labelYellowLight.state="open":self.close_light("yellow")elifui.labelYellowLight.state=="close":self.open_light("yellow")#点击绿灯时触发defgreen_light_mouse_press_event(self,event):ifui.labelGreenLight.state="open":self.close_light("green")elifui.labelGreenLight.state=="close":self.open_light("green")#点击“连接”按钮时触发,用于链接TCPServerdefpushButton_connect_mouse_press_event(self,event):self.client.connect(('192.168.31.164',4999))self.connected=Trueself.ui.pushButtonConnect.setEnabled(False)QMessageBox.information(self.ui.centralwidget,"message","SuccessfullyconnectedtoArduino")#点击“自动"按钮触发,用于开启信号灯自动切换模式defpushButton_auto_mouse_press_event(self,event):self.workThread.running=Trueself.workThread.start()self.ui.pushButtonAuto.setEnabled(False)self.ui.pushButtonStop.setEnabled(True)#点击“停止”按钮触发,用于关闭信号灯自动切换模式defpushButton_stop_mouse_press_event(self,event):self.workThread.running.Autopushedton.setpushedon.True)self.ui.pushButtonStop.setEnabled(False)#用于初始化代码if__name__=='__main__':app=QApplication(sys.argv)ui=TrafficLight1.Ui_MainWindow()mainWindow=QMainWindow()ui.setupUi(mainWindow)事件=事件(ui)ui.labelRedLight.state=“关闭”ui.labelYellowLight.state=“关闭”ui.labelGreenLight.state=“关闭”ui.labelRedLight.mousePressEvent=events.red_light_mouse_press_eventui.labelYellowLight.mousePressEvent=events.yellow_light_mouse_press_eventui.labelGreenLight.mousePressEvent=事件.green_light_mouse_press_eventui.pushButtonConnect.mousePressEvent=事件.pushButton_connect_mouse_press_eventui.pushButtonAuto.mousePressEvent=事件.pushButton_auto_mouse_press_eventui.pushButtonStop.mousePressEvent=事件.pushButton_press_stop_eventmouseui.pushButtonStop.setEnabled(False)#设置所有组件的文字大小为30pxmainWindow.setStyleSheet("QWidget{font-size:30px}");mainWindow.show()app.exec()现在整个系统都完成了,享受我们的成果吧!wifi_leddemo(长).mp4.zip源码.txt.zip更多内容请访问:Harmonyos.51cto.com,与华为共建的鸿蒙技术社区