# 16. Arduino 编程最佳实践 ## 16.1 远程IO控制器 此项目通过阿里云 IoT Studio ,建立一个控制界面,用于控制IO扩展板的 8路继电器,读取每个输入通道的状态。 项目功能: - Edge101WE 主板叠加 IO扩展板,通过阿里云IoT上传输入通道数据。并接阿里云下发的继电器控制指令,控制继电器。 - IoT Studio 建立Web操作界面,可控制每一路继电器。 - 具备阿里OTA功能。 ### 1、创建云端产品以及设备 ![image-20210701164028921](./pictures/image15_1_1.png) ![image-20210701164437213](./pictures/image15_1_2.png) ![image-20210701164713295](./pictures/image15_1_3.png) ![image-20210702084826657](./pictures/image15_1_4.png) ![image-20210702090023408](./pictures/image15_1_5.png) ![image-20210705091632472](./pictures/image15_1_30.png) ![image-20210702090145185](./pictures/image15_1_6.png) ![image-20210702090537449](./pictures/image15_1_7.png) ### 2、Web应用 **接下来,我们根据此设备开发一个Web应用,访问网址:https://www.aliyun.com/product/iotstudio** ![image-20210702091240361](./pictures/image15_1_8.png) ![image-20210702091437352](./pictures/image15_1_9.png) ![image-20210702092148354](./pictures/image15_1_10.png) ![image-20210702092403009](./pictures/image15_1_11.png) ![image-20210702093126532](./pictures/image15_1_12.png) ![image-20210702093908989](./pictures/image15_1_13.png) ![image-20210702094114020](./pictures/image15_1_14.png) ![image-20210702094407691](./pictures/image15_1_15.png) ![image-20210702094734206](./pictures/image15_1_16.png) ![image-20210702095013249](./pictures/image15_1_17.png) ![image-20210702095338658](./pictures/image15_1_18.png) ![image-20210702095611985](./pictures/image15_1_19.png) ![image-20210702103336515](./pictures/image15_1_20.png) ![image-20210705151346066](./pictures/image15_1_31.png) ![image-20210702132448768](./pictures/image15_1_21.png) ![image-20210702135153761](./pictures/image15_1_22.png) **浏览器访问此链接,到这里我们就搭建完成一个Web应用了** ![image-20210705151448288](./pictures/image15_1_23.png) ### 3、OTA 远程升级设置 **接下来我们来搭建OTA功能,本系统采用的是自动升级,系统连接网络接上云端后,会自动上传固件版本号,若固件版本低于升级包的版本,将会进行空中升级。** ![image-20210702172803377](./pictures/image15_1_24.png) ![image-20210702173932999](./pictures/image15_1_25.png) ![image-20210702175614311](./pictures/image15_1_28.png) ![image-20210702180120078](./pictures/image15_1_29.png) ### 4、例程代码 ```c++ /*! * @file relayOTA.ino * * @brief Simulate esp32 as a bedroom light and use Aliyun as a cloud platform. * @n Subscribe to the relay control topic, which is the relay that can control the extension board in the cloud, and report the status of the 8-way input channel of the extension board * @n Aliyun OTA * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) * @licence The MIT License (MIT) * @author [Yangfeng](feng.yang@dfrobot.com) * @version V1.0 * @date 2021-06-24 * @get from https://www.dfrobot.com */ #include #include #include #include "DFRobot_Iot.h" #include "HttpsOTAUpdate.h" #include "DFRobot_IOExpension.h" /*Configure the WiFi name and password*/ const char * WIFI_SSID = "++++++++"; const char * WIFI_PASSWORD = "++++++++"; /*Configure the device certificate information*/ String ProductKey = "++++++"; String ClientId = "1234";/*The custom ID*/ String DeviceName = "++++++"; String DeviceSecret = "++++++"; /*Configure the domain name and port number*/ String ALIYUN_SERVER = "iot-as-mqtt.cn-shanghai.aliyuncs.com"; uint16_t PORT = 1883; /*Topics to be reported and subscribed to*/ const char * subTopic = "/sys/${ProductKey}/${DeviceName}/thing/service/property/set"; const char * subTopic1 = "/ota/device/upgrade/${ProductKey}/${DeviceName}"; const char * pubTopic1 = "/ota/device/inform/${ProductKey}/${DeviceName}"; const char * pubTopic = "/sys/${ProductKey}/${DeviceName}/thing/event/property/post"; static const char *server_certificate = "-----BEGIN CERTIFICATE-----\r\n" "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \ "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \ "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \ "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \ "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \ "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \ "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \ "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \ "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \ "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \ "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \ "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \ "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \ "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \ "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \ "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \ "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \ "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \ "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \ "-----END CERTIFICATE-----"; static HttpsOTAStatus_t otastatus; DFRobot_IOExpension IOExpension(DFRobot_IOExpension_ADDR_H); DFRobot_Iot myIot; WiFiClient espClient; PubSubClient client(espClient); bool interruptFlag = false; static void inputGetStatus(); static void interEvent(); void HttpEvent(HttpEvent_t *event) { switch(event->event_id) { case HTTP_EVENT_ERROR: Serial.println("Http Event Error"); break; case HTTP_EVENT_ON_CONNECTED: Serial.println("Http Event On Connected"); break; case HTTP_EVENT_HEADER_SENT: Serial.println("Http Event Header Sent"); break; case HTTP_EVENT_ON_HEADER: Serial.printf("Http Event On Header, key=%s, value=%s\n", event->header_key, event->header_value); break; case HTTP_EVENT_ON_DATA: break; case HTTP_EVENT_ON_FINISH: Serial.println("Http Event On Finish"); break; case HTTP_EVENT_DISCONNECTED: Serial.println("Http Event Disconnected"); break; } } void connectWiFi(){ Serial.print("Connecting to "); Serial.println(WIFI_SSID); WiFi.begin(WIFI_SSID,WIFI_PASSWORD); while(WiFi.status() != WL_CONNECTED){ delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.print("IP Adderss: "); Serial.println(WiFi.localIP()); } void callback(char * topic, byte * payload, unsigned int len){ Serial.print("Recevice ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < len; i++){ Serial.print((char)payload[i]); } Serial.println(); StaticJsonDocument<300> jsonBuffer; auto error = deserializeJson(jsonBuffer, (char *)payload); if (error){ Serial.println("parseObject() failed:"); Serial.println(error.f_str()); } if( strcmp(topic,subTopic1)==0){ String str = jsonBuffer["data"]["url"]; if(str.compareTo("null")!=0){ String version0 =jsonBuffer["data"]["version"] ; String a = "\""; String version = a+version0+a; Serial.println(version); Serial.println(str); HttpsOTA.onHttpEvent(HttpEvent); Serial.println("Starting OTA"); HttpsOTA.begin(const_cast(str.c_str()) , server_certificate); Serial.println("Please Wait it takes some time ..."); while(1){ otastatus = HttpsOTA.status(); if(otastatus == HTTPS_OTA_SUCCESS) { client.publish(pubTopic1,("{\"id\":"+ClientId+",\"params\":{\"version\":"+version+",\"module\":\"esp32\"}}").c_str()); Serial.printf("Firmware written successfully. Current version information: %s . To reboot device, call API ESP.restart() or PUSH restart button on device",version0); Serial.println("Auto restart after 3 seconds"); for(uint8_t i=0;i<2;i++){ delay(1000); Serial.print("."); } delay(1000); Serial.println("."); ESP.restart(); } else if(otastatus == HTTPS_OTA_FAIL) { Serial.println("Firmware Upgrade Fail"); break; } } } }else if( strcmp(topic,subTopic)==0){ String param = jsonBuffer["params"]; if(strstr(param.c_str(), "relay_1") != NULL){ const bool relay_1 = jsonBuffer["params"]["relay_1"]; IOExpension.setRelayStatus(/*channel= */1,/*mode=*/relay_1); } if(strstr(param.c_str(), "relay_2") != NULL){ const bool relay_2 = jsonBuffer["params"]["relay_2"]; IOExpension.setRelayStatus(/*channel= */2,/*mode=*/relay_2); } if(strstr(param.c_str(), "relay_3") != NULL){ const bool relay_3 = jsonBuffer["params"]["relay_3"]; IOExpension.setRelayStatus(/*channel= */3,/*mode=*/relay_3); } if(strstr(param.c_str(), "relay_4") != NULL){ const bool relay_4 = jsonBuffer["params"]["relay_4"]; IOExpension.setRelayStatus(/*channel= */4,/*mode=*/relay_4); } if(strstr(param.c_str(), "relay_5") != NULL){ const bool relay_5 = jsonBuffer["params"]["relay_5"]; IOExpension.setRelayStatus(/*channel= */5,/*mode=*/relay_5); } if(strstr(param.c_str(), "relay_6") != NULL){ const bool relay_6 = jsonBuffer["params"]["relay_6"]; IOExpension.setRelayStatus(/*channel= */6,/*mode=*/relay_6); } if(strstr(param.c_str(), "relay_7") != NULL){ const bool relay_7 = jsonBuffer["params"]["relay_7"]; IOExpension.setRelayStatus(/*channel= */7,/*mode=*/relay_7); } if(strstr(param.c_str(), "relay_8") != NULL){ const bool relay_8 = jsonBuffer["params"]["relay_8"]; IOExpension.setRelayStatus(/*channel= */8,/*mode=*/relay_8); } /*Publish the state of the relay*/ String tempMseg = "{\"id\":" + ClientId + ",\"params\":"+param+",\"method\":\"thing.event.property.post\"}"; char sendMseg[tempMseg.length()]; strcpy(sendMseg, tempMseg.c_str()); client.publish(pubTopic, sendMseg); } } void ConnectAliyun(){ while (!client.connected()){ Serial.print("Attempting MQTT connection..."); /*A device connected to the cloud platform based on an automatically calculated username and password*/ if (client.connect(myIot._clientId, myIot._username, myIot._password)){ Serial.println("connected"); client.subscribe(subTopic); client.subscribe(subTopic1); } else{ Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void setup(){ Serial.begin(115200); while(!Serial); IOExpension.begin(); IOExpension.setRelayStatus(/*channel= */1,/*mode=*/0); IOExpension.setRelayStatus(/*channel= */2,/*mode=*/0); IOExpension.setRelayStatus(/*channel= */3,/*mode=*/0); IOExpension.setRelayStatus(/*channel= */4,/*mode=*/0); IOExpension.setRelayStatus(/*channel= */5,/*mode=*/0); IOExpension.setRelayStatus(/*channel= */6,/*mode=*/0); IOExpension.setRelayStatus(/*channel= */7,/*mode=*/0); IOExpension.setRelayStatus(/*channel= */8,/*mode=*/0); /* connect WIFI */ connectWiFi(); /*Initializes Alinyun's configuration to automatically calculate user name and password*/ myIot.init(ALIYUN,ALIYUN_SERVER,ProductKey,ClientId,DeviceName,DeviceSecret,PORT); client.setServer(myIot._mqttServer,PORT); /*Set the callback function that executes when a subscription is received*/ client.setCallback(callback); /*Connect to the Aliyun*/ ConnectAliyun(); /*Report firmware version information*/ client.publish(pubTopic1,("{\"id\":"+ClientId+",\"params\":{\"version\":\"V1.0\",\"module\":\"esp32\"}}").c_str()); /*Reports the status of relays and input channels*/ client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"relay_1\":0,\"relay_2\":0,\"relay_3\":0,\"relay_4\":0,\"relay_5\":0,\"relay_6\":0,\"relay_7\":0,\"relay_8\":0},\"method\":\"thing.event.property.post\"}").c_str()); client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"INPUT_1\":0,\"INPUT_2\":0,\"INPUT_3\":0,\"INPUT_4\":0,\"INPUT_5\":0,\"INPUT_6\":0,\"INPUT_7\":0,\"INPUT_8\":0},\"method\":\"thing.event.property.post\"}").c_str()); } uint8_t statusLast,statusNow; void loop(){ if(!client.connected()){ ConnectAliyun(); } client.loop(); statusNow = IOExpension.readInputStauts(); if(statusNow!=statusLast){ inputGetStatus(statusNow); statusLast = statusNow; } delay(500); } static void inputGetStatus(uint8_t status) { bool switch_1,switch_2,switch_3,switch_4,switch_5,switch_6,switch_7,switch_8; if(status & SWITCH_COUNTER_1){ switch_1 = 1; } else{ switch_1 = 0; } if(status & SWITCH_COUNTER_2){ switch_2 = 1; } else{ switch_2 = 0; } if(status & SWITCH_COUNTER_3){ switch_3 = 1; } else{ switch_3 = 0; } if(status & SWITCH_COUNTER_4){ switch_4 = 1; } else{ switch_4 = 0; } if(status & SWITCH_COUNTER_5){ switch_5 = 1; } else{ switch_5 = 0; } if(status & SWITCH_COUNTER_6){ switch_6 = 1; } else{ switch_6 = 0; } if(status & SWITCH_COUNTER_7){ switch_7 = 1; } else{ switch_7 = 0; } if(status & SWITCH_COUNTER_8){ switch_8 = 1; } else{ switch_8 = 0; } client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"INPUT_1\":"+switch_1+",\"INPUT_2\":"+switch_2+",\"INPUT_3\":"+switch_3+",\"INPUT_4\":"+switch_4+",\"INPUT_5\":"+switch_5+",\"INPUT_6\":"+switch_6+",\"INPUT_7\":"+switch_7+",\"INPUT_8\":"+switch_8+"},\"method\":\"thing.event.property.post\"}").c_str()); } ``` ## 16.2 工业脉冲计数器和OEE有效产能统计系统 工业场景中脉冲计数器通常连接接近开关、光电开关、霍尔开关等传感器用于对工业现场进行计数,也可以外接按钮进行人工按键计数。 可实现一次感应计一个数、一次感应计多个数、多次感应计一个数。实现自动复位和手动复位。可设定报警输出。意外断电可继续计数。 项目功能: - 使用DFRobot的光电传感器和 I2C 数码管模块实现一个包装机工业计数器,当包装好的货物通过传送带时,光电传感器检测后记录数量,并通过数码管显示出来。 - 主板意外断电后可继续计数。 - 外接一个清零开关,当按下超过5秒后,计数值清零。 - 通过阿里云显示当天是否开机、开机的时间长度、包装数量。 - 可通过阿里云OTA进行程序升级。 Gravity: 8位数码管显示模块: https://www.dfrobot.com.cn/goods-2602.html 工业级背景抑制光电传感器: https://www.dfrobot.com.cn/goods-3111.html ### 一、搭建云平台 #### 1、创建本次产品以及设备 首先访问阿里云首页(https://www.aliyun.com/)并登录自己的账号,进入自己的控制台。 ![image-20210707150510014](./pictures/image15_2_1.png) ![image-20210707151349563](./pictures/image15_2_2.png) ![image-20210707151944362](./pictures/image15_2_3.png) ![image-20210707152022970](./pictures/image15_2_4.png) 接下来,我们就开始来创建一个产品和设备 ![image-20210707152222495](./pictures/image15_2_5.png) ![image-20210707152454166](./pictures/image15_2_6.png) 创建好产品后我们先来为产定义物理模型 ![image-20210707153043568](./pictures/image15_2_7.png) ![image-20210707153212561](./pictures/image15_2_8.png) ![image-20210707153358434](./pictures/image15_2_9.png) 这里我们创建两个功能,一个用来记录系统开机时间,一个用来记录包装数量。 ![image-20210707155332045](./pictures/image15_2_10.png) ![image-20210707155934799](./pictures/image15_2_11.png) ![image-20210707160227452](./pictures/image15_2_12.png) 接下来我们为此产品创建一个设备 ![image-20210707160535866](./pictures/image15_2_13.png) ![image-20210707160606874](./pictures/image15_2_14.png) 这里保存设备证书信息,并写入代码中 ![image-20210707160732784](./pictures/image15_2_15.png) ![image-20210707160942692](./pictures/image15_2_16.png) 到这里,我们就可以将设备证书填写到代码中,并且修改配网信息,运行一次程序,使得云端设备激活。 #### 2、创建一个Web应用 访问链接 https://www.aliyun.com/product/iotstudio ![image-20210707164842280](./pictures/image15_2_17.png) ![image-20210707164955449](./pictures/image15_2_18.png) ![image-20210707165048249](./pictures/image15_2_19.png) ![image-20210707165136845](./pictures/image15_2_20.png) 执行完上步骤后自动跳转到此界面 ![image-20210707165345264](./pictures/image15_2_21.png) 执行完上步骤后自动跳转到此界面 ![image-20210707165625522](./pictures/image15_2_22.png) ![image-20210707170452066](./pictures/image15_2_23.png) ![image-20210707170528148](./pictures/image15_2_24.png) ![image-20210707170714804](./pictures/image15_2_25.png) ![image-20210707170919510](./pictures/image15_2_26.png) 关联好产品和设备后,我们回到Web应用编辑界面 ![image-20210707171029842](./pictures/image15_2_27.png) ![image-20210707171227756](./pictures/image15_2_28.png) ![image-20210707173202179](./pictures/image15_2_29.png) 根据自己的喜好配置一些界面可以使其更加美观,当编辑好界面后,点击“发布“。 ![image-20210707174312379](./pictures/image15_2_30.png) ![image-20210707174453834](./pictures/image15_2_31.png) 访问刚刚记录的链接,到这里我们就可以实时观察系统的包装数量和系统开机时间长度了。 ![image-20210707174542280](./pictures/image15_2_32.png) #### 3、OTA升级任务的创建 ![image-20210707175612579](./pictures/image15_2_33.png) ![image-20210707180017350](./pictures/image15_2_34.png) 创建一次升级任务 ![image-20210707180116738](./pictures/image15_2_35.png) ![image-20210707180328594](./pictures/image15_2_36.png) ![image-20210707183200091](./pictures/image15_2_37.png) ![image-20210707183327053](./pictures/image15_2_38.png) 到这里我们就创建好了一次升级任务,在升级任务作用的时间内,设备上线并且符合升级要求,将会进行自动升级。 升级完成样式如图。 ![image-20210707183728391](./pictures/image15_2_39.png) ### 二、例程 ```c++ # include "DFRobot_LedDisplayModule.h" #include "DFRobot_IOExpension.h" #include #include #include #include "DFRobot_Iot.h" #include "HttpsOTAUpdate.h" //#define CONNECT_ALIYUN /*Configure the WiFi name and password*/ const char * WIFI_SSID = "++++++++"; const char * WIFI_PASSWORD = "++++++++"; /*Configure the device certificate information*/ String ProductKey = "++++++"; String ClientId = "1234";/*The custom ID*/ String DeviceName = "++++++"; String DeviceSecret = "++++++"; /*Configure the domain name and port number*/ String ALIYUN_SERVER = "iot-as-mqtt.cn-shanghai.aliyuncs.com"; uint16_t PORT = 1883; /*Topics to be reported and subscribed to*/ const char * subTopic = "/sys/${ProductKey}/${DeviceName}/thing/service/property/set"; const char * subTopic1 = "/ota/device/upgrade/${ProductKey}/${DeviceName}"; const char * pubTopic1 = "/ota/device/inform/${ProductKey}/${DeviceName}"; const char * pubTopic = "/sys/${ProductKey}/${DeviceName}/thing/event/property/post"; static const char *server_certificate = "-----BEGIN CERTIFICATE-----\r\n" "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \ "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \ "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \ "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \ "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \ "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \ "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \ "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \ "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \ "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \ "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \ "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \ "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \ "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \ "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \ "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \ "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \ "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \ "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \ "-----END CERTIFICATE-----"; static HttpsOTAStatus_t otastatus; DFRobot_Iot myIot; WiFiClient espClient; uint32_t valLast = 0; uint8_t userKey = 38; volatile int keyUpTime,keyDownTime,keyTime; static uint8_t errnum; bool interruptFlag = false; DFRobot_LedDisplayModule LED(Wire, 0xE0); DFRobot_IOExpension IOExpension(DFRobot_IOExpension_ADDR_H); PubSubClient client(espClient); #define MODE_A 0 #define MODE_B 1 #define MODE_C 2 int mode; int counterValue = 0; void ISR_FALLING() { keyDownTime = millis (); attachInterrupt(digitalPinToInterrupt(38),ISR_RISING,RISING); } void ISR_RISING() { keyUpTime = millis (); keyTime = keyUpTime - keyDownTime; if(keyTime>= 5000){ interruptFlag = true; keyTime = 0; }else{ keyDownTime = keyUpTime; } attachInterrupt(digitalPinToInterrupt(38),ISR_FALLING,FALLING); } void HttpEvent(HttpEvent_t *event) { switch(event->event_id) { case HTTP_EVENT_ERROR: Serial.println("Http Event Error"); break; case HTTP_EVENT_ON_CONNECTED: Serial.println("Http Event On Connected"); break; case HTTP_EVENT_HEADER_SENT: Serial.println("Http Event Header Sent"); break; case HTTP_EVENT_ON_HEADER: Serial.printf("Http Event On Header, key=%s, value=%s\n", event->header_key, event->header_value); break; case HTTP_EVENT_ON_DATA: break; case HTTP_EVENT_ON_FINISH: Serial.println("Http Event On Finish"); break; case HTTP_EVENT_DISCONNECTED: Serial.println("Http Event Disconnected"); break; } } void connectWiFi(){ Serial.print("Connecting to "); Serial.println(WIFI_SSID); WiFi.begin(WIFI_SSID,WIFI_PASSWORD); while(WiFi.status() != WL_CONNECTED){ delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.print("IP Adderss: "); Serial.println(WiFi.localIP()); } void callback(char * topic, byte * payload, unsigned int len){ Serial.print("Recevice ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < len; i++){ Serial.print((char)payload[i]); } Serial.println(); StaticJsonDocument<300> jsonBuffer; auto error = deserializeJson(jsonBuffer, (char *)payload); if (error){ Serial.println("parseObject() failed:"); Serial.println(error.f_str()); } if( strcmp(topic,subTopic1)==0){ String str = jsonBuffer["data"]["url"]; if(str.compareTo("null")!=0){ String version0 =jsonBuffer["data"]["version"] ; String a = "\""; String version = a+version0+a; Serial.println(version); Serial.println(str); HttpsOTA.onHttpEvent(HttpEvent); Serial.println("Starting OTA"); HttpsOTA.begin(const_cast(str.c_str()) , server_certificate); Serial.println("Please Wait it takes some time ..."); while(1){ otastatus = HttpsOTA.status(); if(otastatus == HTTPS_OTA_SUCCESS) { client.publish(pubTopic1,("{\"id\":"+ClientId+",\"params\":{\"version\":"+version+",\"module\":\"esp32\"}}").c_str()); Serial.printf("Firmware written successfully. Current version information: %s . To reboot device, call API ESP.restart() or PUSH restart button on device",version0); Serial.println("Auto restart after 3 seconds"); for(uint8_t i=0;i<2;i++){ delay(1000); Serial.print("."); } delay(1000); Serial.println("."); ESP.restart(); break; } else if(otastatus == HTTPS_OTA_FAIL) { Serial.println("Firmware Upgrade Fail"); break; } } } } } void ConnectAliyun(){ while (!client.connected()){ Serial.print("Attempting MQTT connection..."); /*A device connected to the cloud platform based on an automatically calculated username and password*/ if (client.connect(myIot._clientId, myIot._username, myIot._password)){ Serial.println("connected"); client.subscribe(subTopic); client.subscribe(subTopic1); } else{ Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void setup() { Serial.begin(115200); while(!Serial); while(IOExpension.begin()!=0){ delay(1000); } /*Wait for the chip to be initialized completely, and then exit*/ while(LED.begin8() != 0) { Serial.println(""); delay(1000); } LED.setDisplayArea8(2,3,4,5,6,7); LED.print8("H","E","L","L","O","!"); delay(2000); Serial.println("Please select count mode:"); Serial.println(" Mode A: one number at a time;"); Serial.println(" Mode B: multiple numbers at a time;"); Serial.println(" Mode C: multiple induction meter a number;"); Serial.println("Enter 'A' for mode A; Enter 'B' for mode B; Enter 'C' for mode C."); while(1){ if (Serial.available()){ counterValue = 0; int inputchar = Serial.read(); if (char(inputchar) == 'A'){ Serial.read(); Serial.println("The system will operate in A mode"); mode = MODE_A; break; } else if (char(inputchar) == 'B'){ bool flag = true; Serial.read(); Serial.read(); Serial.println("The system will operate in B mode"); Serial.println("Please input the corresponding count value of an induction"); while (1){ uint8_t a=Serial.available(); if(a>0){ flag = true; for(uint8_t i=0;i=48 && value<=57){ counterValue = counterValue * 10; counterValue = counterValue + value - '0'; }else if (char(value) == '\r'|| char(value) == '\n'|| char(value) == '\0'){ }else{ Serial.println("Invalid value, please reselect"); flag = false; for(;i0){ flag = true; for(uint8_t i=0;i=48 && value<=57){ counterValue = counterValue * 10; counterValue = counterValue + value - '0'; }else if (char(value) == '\r'|| char(value) == '\n'|| char(value) == '\0'){ }else{ Serial.println("Invalid value, please reselect"); flag = false; for(;i99999999 ){ LED.setDisplayArea8(1,2,3,4,5,6,7,8); uint32_t err = 88888888; LED.print8(err); Serial.println(val,HEX); errnum++; if(errnum>10){ IOExpension.setCountnerValue(/*counter=*/SWITCH_COUNTER_8,/*value=*/0); Serial.println("Number of times out of range :10. The counter has automatically reset to zero!"); LED.setDisplayArea8(1,2,3,4,5,6,7,8); LED.print8(0.0); errnum = 0; } } else{ if(mode == MODE_A){ } else if(mode == MODE_B){ val = val * counterValue; } else if(mode == MODE_C){ val = val / counterValue; } //Serial.println(val); LED.setDisplayArea8(1,2,3,4,5,6,7,8); LED.print8(val); #if defined(CONNECT_ALIYUN) if(valLast!=val){ unsigned long nowTime = millis(); double pubTime = nowTime/1000/3600.0; client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"countValue\":"+val+",\"StartingTimeLength\":"+pubTime+"},\"method\":\"thing.event.property.post\"}").c_str()); } valLast=val; #endif } delay(500); } ``` #### 1、填写代码中的设备证书 ![](./pictures/image15_2_16.png) #### 2、添加WiFi信息 ![image-20210707184342573](./pictures/image15_2_40.png) #### 3、编译运行 #### 4、按照串口信息,配置工作模式 ![image-20210707184715539](./pictures/image15_2_41.png) 配置成功后成功运行,此时观察数码管计数,或者上到云端观察数据即可。 ![image-20210707184933737](./pictures/image15_2_42.png)