【Arduino】、Arduino+ESP8266上传至oneNet云
一、硬件简介
1. Arudino 是一种开源的电子平台,该平台最初主要基于AVR单片机的微控制器和相应的开发软件,包含硬件(各种型号的Arduino板)和软件(Arduino IDE)。
2. ESP8266 是深圳安信可科技有限公司开发的基于乐鑫ESP8266的超低功耗的UART-WIFI模块的模组,可以方便进行二次元开发,接入云端服务,实现手机3/4G全球随时随地的控制,加速产品原型设计。
二、硬件接线
1. 所用到的硬件有:Arudino Mega 2560, ESP8266-12F.
2. 接线如下表所示
Arduino | ESP8266 |
3.3V | VCC |
GND | GND |
RXD | TXD |
TXD | RXD |
三、硬件编程
1. ESP8266 芯片接收的AT指令顺序
- AT: 发送 AT 指令判断供电,TTL和WIFI模块是否正常 返回OK表示正常
- AT+ CWMODE=? : 发送 AT+CWMODE=? 指令 选择模式 1.Station模式,2. AP 模式, 返回字节中有OK表示连接成功
- AT+CWJAP="ssid","password" : 发送 AT+CWJAP="ssid","password" 来连接AP 返回字节中有CONNECT表示连接成功
- AT+CIPSTART="TCP","hostServer",hostPort : 链接服务器, 返回OK表示连接成功
- AT+CIPSEND=dataLen :向服务器发送数据,dataLen表示HTTP的请求的长度,返回> 表示发送成功,继续发送数据
- data : 向服务器发送数据
- AT+CIPCLOSE: 关闭请求链接,返回CLOSED表示断开连接
2. 程序代码
1 /** 2 * 3 */ 4 #include <TimerOne.h> 5 #include <HttpPacket.h> 6 #include <ArduinoJson.h> 7 /**' 8 * ESP8266 采用串口3通讯 9 */ 10 #define ESP8266Serial Serial3 11 #define mySerial Serial 12 13 #define RES_MAX_LENGTH 500 14 15 #define SEND_SUCCESS 1 16 #define SEND_FAIL 0 17 18 /** 19 * 链接的AP的账户密码 20 */ 21 char ssid[] = "zlei"; 22 char pass[] = "18829237005"; 23 24 /** 25 * Onenet 互联网信息 26 */ 27 char oneNetServer[] = "api.heclouds.com"; //不需要修改 28 char deviceId[] = "10005241"; 29 char API_KEY[] = "qB40IZOP6Rx58EZ7ow16mA=VkRQ="; 30 char sensorID1[] = "waterLevel"; 31 32 33 // ESP8266于Arduino交互的数据缓存 34 char ESP8266Response[RES_MAX_LENGTH]; 35 36 // 交互数据缓存的世纪存储长度 37 int resLength = 0; 38 39 // 请求时间计算的最小分度值 40 const unsigned long interval = 1000; 41 42 // 计时器,以毫秒为最小计数单位 43 unsigned long curTime = 0; 44 45 HttpPacketHead packet; 46 void setup() { 47 ESP8266Serial.begin(115200); 48 mySerial.begin(9600); 49 50 Timer1.initialize(interval); 51 Timer1.attachInterrupt(timeClock); 52 intiESP8266(); 53 54 } 55 56 void loop() { 57 postDataToServer(API_KEY,deviceId,sensorID1,1.00); // 发送数据(数据为模拟数据) 58 delay(10000); 59 } 60 61 /** 62 * 制造重启命令 63 */ 64 void(* resetFunc) (void) = 0; 65 66 /** 67 * ESP8266 板子进行初始化 68 * 1. 发送 AT 指令判断供电,TTL和WIFI模块是否正常 返回OK表示正常 69 * 2. 发送 AT+CWMODE=? 指令 选择模式 1.Station模式,2. AP 模式 70 * 3. 发送 AT+CWJAP="ssid","password" 来连接AP 71 */ 72 void intiESP8266(){ 73 74 // AT 指令, 返回OK表明供电,TTL和WIFI模块通讯正常 75 if(sendATCommead("AT\r\n","OK", 1000, 2) == SEND_SUCCESS ); 76 else ESP8266_Error(1); 77 delay(100); 78 // AT+CWMODE=? 选择模式 1.Station模式,2. AP 模式 79 if(sendATCommead("AT+CWMODE=1\r\n","OK",1000,3) == SEND_SUCCESS ); 80 else ESP8266_Error(2); 81 82 // AT+CWJAP="sid","pass" 加入AP 83 char cwjap[50]; 84 strcat(cwjap,"AT+CWJAP=\""); 85 strcat(cwjap,ssid); 86 strcat(cwjap,"\",\""); 87 strcat(cwjap,pass); 88 strcat(cwjap,"\"\r\n"); 89 if(sendATCommead(cwjap,"OK",2000,4) == SEND_SUCCESS ); 90 else ESP8266_Error(3); 91 } 92 93 /** 94 * ESP8266 错误信息处理 95 * @param type 错误信息类型 96 */ 97 void ESP8266_Error(int type){ 98 mySerial.println("ERROR"); 99 mySerial.println(type); 100 while(1){ 101 if(sendATCommead("AT\r\n","OK", 1000, 2) == SEND_SUCCESS){ 102 mySerial.print("\r\nRESET!!!!!!\r\n"); 103 resetFunc(); 104 } 105 } 106 } 107 108 /** 109 * Arduino 向ESP8266中发送AT指令 110 * @param commoned 需要发送的指令 111 * @param response 发送之后接收到response之后表示成功 112 * @param timeout 在发送命令之后 timeout 毫秒之后重新发送消息 113 * @param reTry 重新发送的次数 114 */ 115 unsigned int sendATCommead(char *commoned, char *response, int timeout, unsigned char reTry){ 116 117 // 多次重复发送消息,直到接收到消息。 118 for(unsigned char tryTime = 0; tryTime < reTry; tryTime++){ 119 clearResponse(); // 清理接收缓存 120 mySerial.print("send commoned "); 121 mySerial.print(commoned); 122 mySerial.print(" to ESP8266.\n"); 123 ESP8266Serial.write(commoned); // 通过串口发送命令 124 curTime = 0; 125 126 // 在延时范围内查看回复消息,如果回复消息成功,返回成功 127 while(curTime < timeout){ 128 readResponse(); 129 if(strstr(ESP8266Response, response) != NULL){ 130 mySerial.println("Response is "); 131 mySerial.println("-------------- Response Start ----------------"); 132 mySerial.println(ESP8266Response); 133 mySerial.println("-------------- Response end ------------------"); 134 return SEND_SUCCESS; 135 } 136 } 137 } 138 // 发送失败 139 mySerial.print("response received, content is \n >>>> "); 140 mySerial.println(ESP8266Response); 141 return SEND_FAIL; 142 } 143 144 /** 145 * 向服务器发送数据请求 146 * @param apiKey 访问网站的apiKey 147 * @param deviceID 设备ID 148 * @param sensorID 传感器ID 149 * @param data 发送的数据 150 */ 151 void postDataToServer(char *apiKey, char *deviceID, char *sensorID, double data){ 152 StaticJsonBuffer<400> jsonBuffer; 153 154 JsonObject &value = jsonBuffer.createObject(); 155 value["value"] = data; 156 157 JsonObject &idDataPoints = jsonBuffer.createObject(); 158 idDataPoints["id"] = sensorID; 159 JsonArray &dataPoints = idDataPoints.createNestedArray("dataPoints"); 160 dataPoints.add(value); 161 162 JsonObject &myJson = jsonBuffer.createObject(); 163 JsonArray &dataStreams = myJson.createNestedArray("dataStreams"); 164 dataStreams.add(idDataPoints); 165 166 // 设置POST的请求表头 167 char postData[400]; 168 int postLength = myJson.printTo(postData, sizeof(postData)); 169 170 packet.setHostAddress(oneNetServer); 171 packet.setDevId(deviceId); 172 packet.setAccessKey(API_KEY); 173 174 packet.createCmdPacket(POST, TYPE_DATAPOINT, postData); 175 176 int httpLength = strlen(packet.content) + postLength; 177 178 char cmd[500]; 179 // 链接服务器 180 memset(cmd, 0, 500); 181 sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",80\r\n",oneNetServer); 182 if(sendATCommead(cmd,"CONNECT", 3000, 5) == SEND_SUCCESS); 183 else ESP8266_Error(4); 184 185 // 发送数据 186 memset(cmd,0,500); 187 sprintf(cmd, "AT+CIPSEND=%d\r\n",httpLength); 188 if(sendATCommead(cmd,">",3000,3) == SEND_SUCCESS); 189 else ESP8266_Error(5); 190 191 memset(cmd,0,500); 192 strcpy(cmd,packet.content); 193 strcat(cmd,postData); 194 if(sendATCommead(cmd,"succ\"}",5000,5) == SEND_SUCCESS); 195 else ESP8266_Error(6); 196 197 if(sendATCommead("AT+CIPCLOSE\r\n","CLOSED",3000,3) == SEND_SUCCESS); 198 else ESP8266_Error(7); 199 } 200 201 /** 202 * @TODO 将ESP8266返回的数据返回到缓存数组中 203 * 1. 清理缓存数据 204 * 2. 将读取的数据存入全局数组中 205 * 3. 超出数组长度之后 206 */ 207 void readResponse(){ 208 clearResponse(); 209 while(ESP8266Serial.available()){ 210 ESP8266Response[resLength++] = ESP8266Serial.read(); 211 if(resLength == RES_MAX_LENGTH) clearResponse(); 212 } 213 } 214 215 /** 216 * @todo 清理数据交互缓存区 217 */ 218 void clearResponse(){ 219 memset(ESP8266Response,0,RES_MAX_LENGTH); 220 resLength = 0; 221 } 222 223 /** 224 * 计时器函数,单位为毫秒 225 */ 226 void timeClock(){ 227 curTime++; 228 }