#申请原创#
这次要做的项目就是要通过CH32V103驱动ESP8266芯片,通过MQTT协议连接阿里云的物联网平台,并把温湿度数据和火警信息传递到阿里云的物联网平台。
此次用到的硬件CH32V103 ESP8266模块 DHT11芯片 火焰传感器。
怎么读取ESP8266和火焰传感器就见上一个贴子https://bbs.21ic.com/icview-3156850-1-1.html。
购买一个esp8266模块首先是需要对ESP8266的AT固件进行升级,使用的工具为flash_download_tool_v3.8.5
这个文件太大了,不能上传过来,给一个链接把。https://www.espressif.com/zh-han ... d_type_tid%5B%5D=14
使用的固件版本是Ai-Thinker_ESP8266_DOUT_8Mbit_v1.5.4.1-a_20171130。这个在官网也有下载的。
这个可以放在这里
Ai-Thinker_ESP8266_DOUT_8Mbit_v1.5.4.1-a_20171130.rar
(291.3 KB)
程序下载的配置方式为
硬件第一步的问题解决了。下载开始在阿里云物联网平台搭建一个设备平台。
1 搭建阿里云物联网平台
注册好了阿里云以后,就是怎么搭建环境了。
进入物联网平台以后,首先需要创建产品。如上图所示
输入产品名称以后,选择自定义类型,这个不是必须的,点击确认。
点击查看设备,需要对设备的功能自定义进行配置。
找到功能自定义一栏,编辑草稿。需要添加自己定义的功能。
点击自定义功能,弹出下面的菜单。
对照下图添加功能名称和标识符,这个标识符是唯一的,不能重复。
然后发布就可以了,这个就完成了功能设计的最要的一些步骤了。
点击添加设备,弹出如下的菜单。需要选择产品,并输入设备名称,这个只能为英文。
添加设备成功以后,点击查看设备,进入需要用的三元素
这个就是连接阿里云物联网平台的三元素。后面需要用到的。若使用一机一密认证方式,设备上需要烧写product_key、device_name和device_secret
当设备平台搭建好以后,需要在iot studio 搭建显示界面。
点击新建web应用,并输入下面的设备名称。如果没有绑定设备,需要在iot studio里面绑定之前建好的产品和设备。
这些内容随便输入了。
点击编辑,进入编辑界面,对相关的界面进行配置。
从右侧控件栏中,添加仪表 和指示灯 曲线图等三个空间。
选中空间,在右侧属性一栏对相关数据进行配置。
这里仅仅展示一个温度显示的控件和数据的绑定过程。
搭建好后,点击预览就可在网页端查看相关的数据了。
2、搭建硬件平台。
外设和硬件对应的IO。
ESP8266:串口2
TX-----------PA3
RX------------PA2
火焰传感器:
IO----------PA1
DHT11:
IO----------PB10
至于MQTT是怎么通信的这里就不再赘述了,还是去百度一下吧。当然了不懂里面的规则也是无所谓的。流程都是一样的。
初始化ESP8266
首先需要配置ESP8266为AP模式,连接上家里的路由器,才能与外部网络进行通信。 ssid, pswd分别为路由器的名称和密码。后面才能开始进行阿里云的连接通信了,使用的TCP的通信模式。
uint8_t ESP8266_ConnectAP(char* ssid,char* pswd)
{
uint8_t cnt=5;
while(cnt--)
{
memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));
ESP8266_ATSendString("AT+CWMODE_CUR=1\r\n"); //设置为STATION模式
if(FindStr((char*)usart2_rxbuf,"OK",200) != 0)
{
break;
}
}
if(cnt == 0)
return 0;
cnt=2;
while(cnt--)
{
memset(usart2_txbuf,0,sizeof(usart2_txbuf));//清空发送缓冲
memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));//清空接收缓冲
sprintf((char*)usart2_txbuf,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid,pswd);//连接目标AP
ESP8266_ATSendString((char*)usart2_txbuf);
if(FindStr((char*)usart2_rxbuf,"OK",8000)!=0) //连接成功且分配到IP
{
return 1;
}
}
return 0;
}
MQTT通信阿里云需要明确是阿里云的三元素,就是加密的部分。
char ClientID[128];
char Username[128];
char Passward[128];
密码就是用户名和产品,加上DeviceSecret的组合。
接入域名为 ${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com,端口固定为1883
ClientId由客户端ID(clientId)、安全模式(securemode)、签名算法类型(signmethod)和时间戳(timestamp)拼接而成。
例如${YourProductKey}|securemode=3,signmethod=hmacmd5|
来看个列表
在这里进行http://encode.chahuo.com/加密的过程。
获得的ID 用户名称和密码都填写到 ClientID Username Passward三个里面
使用的ESP8266的AT进行TCP的连接
ESP8266_ConnectServer("TCP",ServerIP,1883)
具体AT的操作代码如下所示,使用的透传方式,就是需要在发送send指令了。
uint8_t ESP8266_ConnectServer(char* mode,char* ip,uint16_t port)
{
uint8_t cnt;
ESP8266_ExitUnvarnishedTrans(); //多次连接需退出透传
Delay_Ms(500);
//连接服务器
cnt=2;
while(cnt--)
{
memset(usart2_txbuf,0,sizeof(usart2_txbuf));//清空发送缓冲
memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));//清空接收缓冲
sprintf((char*)usart2_txbuf,"AT+CIPSTART=\"%s\",\"%s\",%d\r\n",mode,ip,port);
ESP8266_ATSendString((char*)usart2_txbuf);
if(FindStr((char*)usart2_rxbuf,"CONNECT",8000) !=0 )
{
printf("%s",(char*)usart2_rxbuf);
break;
}
}
if(cnt == 0)
return 0;
//设置透传模式
if(ESP8266_OpenTransmission()==0) return 0;
//开启发送状态
cnt=2;
while(cnt--)
{
memset(usart2_rxbuf,0,sizeof(usart2_rxbuf)); //清空接收缓冲
ESP8266_ATSendString("AT+CIPSEND\r\n");//开始处于透传发送状态
if(FindStr((char*)usart2_rxbuf,">",200)!=0)
{
return 1;
}
}
return 0;
}
TCP通信以后,需要进行MQTT通信录。
MQTT_Connect(ClientID, Username, Passward)
MQTT的连接代码
//MQTT连接服务器的打包函数
uint8_t MQTT_Connect(char *ClientID,char *Username,char *Password)
{
//char temp[200];
int ClientIDLen = strlen(ClientID);
int UsernameLen = strlen(Username);
int PasswordLen = strlen(Password);
int DataLen;
MQTT_TxLen=0;
//可变报头+Payload 每个字段包含两个字节的长度标识
DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
//固定报头
//控制报文类型
usart2_txbuf[MQTT_TxLen++] = 0x10; //MQTT Message Type CONNECT
//剩余长度(不包括固定头部)
do{
uint8_t encodedByte = DataLen % 128;
DataLen = DataLen / 128;
// if there are more data to encode, set the top bit of this byte
if ( DataLen > 0 )
encodedByte = encodedByte | 128;
usart2_txbuf[MQTT_TxLen++] = encodedByte;
}while ( DataLen > 0 );
//可变报头
//协议名
usart2_txbuf[MQTT_TxLen++] = 0; // Protocol Name Length MSB
usart2_txbuf[MQTT_TxLen++] = 4; // Protocol Name Length LSB
usart2_txbuf[MQTT_TxLen++] = 'M'; // ASCII Code for M
usart2_txbuf[MQTT_TxLen++] = 'Q'; // ASCII Code for Q
usart2_txbuf[MQTT_TxLen++] = 'T'; // ASCII Code for T
usart2_txbuf[MQTT_TxLen++] = 'T'; // ASCII Code for T
//协议级别
usart2_txbuf[MQTT_TxLen++] = 4; // MQTT Protocol version = 4
//连接标志
usart2_txbuf[MQTT_TxLen++] = 0xc2; // conn flags
usart2_txbuf[MQTT_TxLen++] = 0; // Keep-alive Time Length MSB
usart2_txbuf[MQTT_TxLen++] = 60; // Keep-alive Time Length LSB 60S心跳包
usart2_txbuf[MQTT_TxLen++] = BYTE1(ClientIDLen);// Client ID length MSB
usart2_txbuf[MQTT_TxLen++] = BYTE0(ClientIDLen);// Client ID length LSB
memcpy(&usart2_txbuf[MQTT_TxLen],ClientID,ClientIDLen);
MQTT_TxLen += ClientIDLen;
if(UsernameLen > 0)
{
usart2_txbuf[MQTT_TxLen++] = BYTE1(UsernameLen); //username length MSB
usart2_txbuf[MQTT_TxLen++] = BYTE0(UsernameLen); //username length LSB
memcpy(&usart2_txbuf[MQTT_TxLen],Username,UsernameLen);
MQTT_TxLen += UsernameLen;
}
if(PasswordLen > 0){
usart2_txbuf[MQTT_TxLen++] = BYTE1(PasswordLen); //password length MSB
usart2_txbuf[MQTT_TxLen++] = BYTE0(PasswordLen); //password length LSB
memcpy(&usart2_txbuf[MQTT_TxLen],Password,PasswordLen);
MQTT_TxLen += PasswordLen;
}
uint8_t cnt=2;
uint8_t wait;
while(cnt--){
memset(usart2_rxbuf,0,sizeof(usart2_rxbuf));
MQTT_SendBuf(usart2_txbuf,MQTT_TxLen);
wait=30;//等待3s时间
while(wait--){
//CONNECT
if(usart2_rxbuf[0]==parket_connetAck[0] && usart2_rxbuf[1]==parket_connetAck[1]) //连接成功
建立连接以后,就是需要发布话题了。发布话题的代码如下所示:
uint8_t MQTT_PublishData(char *topic, char *message, uint8_t qos)
{
int topicLength = strlen(topic);
int messageLength = strlen(message);
static uint16_t id=0;
int DataLen;
MQTT_TxLen=0;
//有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
//QOS为0时没有标识符
//数据长度 主题名 报文标识符 有效载荷
if(qos) DataLen = (2+topicLength) + 2 + messageLength;
else DataLen = (2+topicLength) + messageLength;
//固定报头
//控制报文类型
usart2_txbuf[MQTT_TxLen++] = 0x30; // MQTT Message Type PUBLISH
//剩余长度
do
{
uint8_t encodedByte = DataLen % 128;
DataLen = DataLen / 128;
// if there are more data to encode, set the top bit of this byte
if ( DataLen > 0 )
encodedByte = encodedByte | 128;
usart2_txbuf[MQTT_TxLen++] = encodedByte;
}while ( DataLen > 0 );
usart2_txbuf[MQTT_TxLen++] = BYTE1(topicLength);//主题长度MSB
usart2_txbuf[MQTT_TxLen++] = BYTE0(topicLength);//主题长度LSB
memcpy(&usart2_txbuf[MQTT_TxLen],topic,topicLength);//拷贝主题
MQTT_TxLen += topicLength;
//报文标识符
if(qos)
{
usart2_txbuf[MQTT_TxLen++] = BYTE1(id);
usart2_txbuf[MQTT_TxLen++] = BYTE0(id);
id++;
}
memcpy(&usart2_txbuf[MQTT_TxLen],message,messageLength);
MQTT_TxLen += messageLength;
MQTT_SendBuf(usart2_txbuf,MQTT_TxLen);
return MQTT_TxLen;
}
这个就是整个的操作过程。
最后需要在代码里面进行发布的操作。使用一个sprintf函数,把所有的代码转换到字符串中,然后发送出去。
sprintf(s_temp,"{\"id\":1,\"params\":{\"CurrentTemperature\":%d,\"CurrentHumidity\":%d,\"warning\":%d},\"version\":\"1.0\",\"method\":\"thing.event.property.post\"}",
temperature,humidity,cnt>0?1:0);
MQTT_PublishData(P_TOPIC_NAME, s_temp, 0);// 发送数据到服务器
最终的显示效果如图所示。
最后附上源代码
|