程序讲解
本节将Yeelink上传数据的整个过程分为3个文件,main.c主文件实现W5500EVB上传数据的主流程,DHT11.c文件实现dht11对室内温湿度数据的采集,mcu_init.c文件实现W5500EVB的初始化。
为了使程序能方便地组建Yeelink所要求的JSON数据格式,我们把采集到数据直接替代这个字符串中的xx即可。
char postT[]={//提交温度
"POST /v1.0/device/15738/sensor/27051/datapoints HTTP/1.1\r\n"
"Host:api.yeelink.net\r\n"
"Accept:*/*\r\n"
"U-ApiKey:fea57b9cc1ed5ad34d48430785b44e8f\r\n"
"Content-Length:12\r\n"
"Content-Type:application/x-www-form-urlencoded\r\n"
"Connection:close\r\n"
"\r\n"
"{\"value\":xx}\r\n"
};//xx用来填充数值
这其中,device/ID/sensor/ID 这两处ID 已经在Yeelink网站上注册得到,一个是设备ID,一个是设备上的传感器的ID,同时,一个设备可以有若干个传感器。U-ApiKey则是你的身份识别码,同样是注册后获得,只有正确提交U-ApiKey才可以在Yeelink上面更新数据。Content-Length:后面的12,指的就是 {"value":24} 的长度,更具体的格式可以翻阅Yeelink的API文档。需要注意的是,在C语言中,双引号 “”需要使用转义字符。
在分析细节代码之前,按照惯例我们还是先来看一下主函数。在这里完成了对W5500EVB的初始化,并在主循环里面完成了向Yeelink提交数据。由于这个程序需要访问Yeelink平台,也就要求W5500EVB能访问外网,因此这里我们要确保给W5500配置IP地址能访问外网。
置W5500为客户端模式的调用过程:W5500_Init()-->Socket_Init(s)-->Socket_Connect(s),设置过程即完成,并与远程服务器连接。连接后就可以发送数据,在这里,数据发送完成后,链接会被Yeelink断开,下次发送需要重新进行Socket_Init(s)-->Socket_Connect(s)的过程。
主程序第7行到第19行实现W5500EVB的初始化,初始化工作完成之后,单片机就可以读取数据和向Yeelink发送数据了。W5500EVB作为Yeelink客户端,在向Yeelink上传数据时为TCP连接,所以这里按照TCP的状态机模式写程序。
第25行,socket初始化之后,W5500EVB就向Yeelink发送连接请求,从而完成了每分钟向Yeelink提交一次温湿度数据。第27行,socket连接建立建立完成,首先把Sn_IR的第0位置1来清空中断,然后读取DHT11采集的数据,并保存在数组temp_rh中。第35行把发送的报文格式存在Buffer中;第36、37行是把Request报文中的xx替换成温度值或者湿度值。然后第38行发送请求报文到Yeelink 服务器。第38行切换数据类型,就是进行温度和湿度的切换,断开socket连接。第42行是socket等待关闭状态,这个状态很简单,由于这个状态是一方断开连接,还能够继续向服务器发送数据,所以就和socket建立连接状态基本相同了。第53行,socket关闭状态,打开socket并初始化TCP模式。
1.int main(void)
2.{
3. static uint8 i=0;
4. uint8 ch=SOCK_HUMTEM;
5. uint16 anyport=3000;
6. uint8 server_ip[4]={42,96,164,52};// api.yeelink.net 的ip地址
7. RCC_Configuration(); /* 配置单片机系统时钟*/
8. GPIO_Configuration();/* 配置GPIO*/
9. NVIC_Configuration();/* 配置嵌套中断向量*/
10.// Timer_Configuration();
11. Systick_Init(72);/* 初始化Systick工作时钟*/
12. USART1_Init(); /*初始化串口通信:115200@8-n-1*/
13. at24c16_init();/*初始化eeprom*/
14. printf("W5500 EVB initialization over.\r\n");
15. Reset_W5500();/*硬重启W5500*/
16. WIZ_SPI_Init();/*初始化SPI接口*/
17. printf("W5500 initialized!\r\n");
18. set_default();
19. set_network();
20. while(1)
21. {
22. switch(getSn_SR(ch))
23. {
24. case SOCK_INIT:
25. connect(ch, server_ip ,80);
26. break;
27. case SOCK_ESTABLISHED:
28. //case SOCK_CLOSE_WAIT:
29. if(getSn_IR(ch) & Sn_IR_CON)
30. {
31. setSn_IR(ch, Sn_IR_CON);
32. }
33. if( DHT11_GetValue(temp_rh))
34. {
35. memcpy(Buffer,post,strlen(post));
36. Buffer[231]=temp_rh/10+0x30;
37. Buffer[232]=temp_rh%10+0x30;
38. send(ch,(const uint8 *)Buffer,sizeof(Buffer));
39. i=!i;
40. printf("RH:%d, Temp:%d\r\n", temp_rh[0], temp_rh[1]);
41. }
42.// printf("yeelink:%d\r\n", temp_rh[1]);//用于yeelink串口工具
43.
44. Delay_ms(500);
45. close(ch); //如果读取数据多次后会停止,可一直通过此函数直接断开Socket
46.// disconnect(ch);
47. break;
48. case SOCK_CLOSE_WAIT:
49.// printf("Send to Yeelink:OK\r\n");
50. break;
51. case SOCK_CLOSED:
52. printf("Send to Yeelink:OK\r\n");
53. socket(ch, Sn_MR_TCP,anyport++ , 0x00);
54. break;
55. default:
56. break;
57. }
58. }
59.}
下面的代码完成了单片机读取温湿度传感器DHT11数据。逐行分析一下单片机读取DHT11采集的数据的驱动程序,第4行我们选取单片机的PA2引脚作为传输数据的接口,开始总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低20毫秒,保证DHT11能检测到起始信号,然后把总线的电平拉高,开始信号结束,然后延时等待40us, 读取DHT11的响应信号。第8行,如果总线为低电平,说明DHT11发送响应信号,当响应信号结束,把响应信号拉高,等待温湿度数据的读取,第14行到第18行为读取40bit的传输数据,最后拉高总线电平,结束数据传输。第21行,如果校验正确,返回1,说明单片机正确读取DHT11采集的数据。如果读取数据不成功,返回0。
/*单片机读取DHT11采集的数据*/
1 uint8 DHT11_GetValue(uint8 *p)
2 {
3 uint8 temp,temp1,temp2;
4 GPIO_DHT_Out_Mode();
/*总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号*/
5 GPIO_ResetBits(GPIOA,PA2);
6 Delay_ms(20);/*精确延时20ms*/
7 GPIO_SetBits(GPIOA,PA2);
/*主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号*/
8 Delay_us(40);//精确延时40us
9 GPIO_DHT_Input_Mode();
/*总线为低电平,说明DHT11发送响应信号*/
10 if(!rDHT11)
11 {
/*判断从机发出的低电平响应信号是否结束*/
12 while(!rDHT11);
/*DHT11发送响应信号后,再把总线拉高80us*/
13 while(rDHT11);
14 p[0]=DHT11_ReadData();/*8bit湿度整数数据*/
15 temp1=DHT11_ReadData();/*忽略无效数据*/
16 p[1]=DHT11_ReadData();/*8bit温度整数数据*/
17 temp2=DHT11_ReadData();/*忽略无效数据*/
18 temp=DHT11_ReadData();/*8bit校验和*/
19 GPIO_DHT_Out_Mode();
20 GPIO_SetBits(GPIOA,PA2);
21 if(temp==(p[0]+p[1]+temp1+temp2))
22 {
23 return 1;
24 }
25 }
26 return 0;
27}
三、 测试效果及注意事项
通过上面Yeelink的截图,我们已成功地将温湿度传感器DHT11采集到的数据传到了云平台Yeelink上,这样便可随时随地监控室内的温湿度了。这个平台也提供了一个手机APP,大家可以在官网下载,登陆Yeelink账号后也可以实时监控温湿度的变化情况
1.在申请账号时要注意API KEY,添加设备时会生成一个URL请求,里面提供了设备ID device/15738,传感器ID sensor/27051。
2.把之前得到的API KEY、设备ID、传感器ID添加到程序中的请求报文中
3.在报文中提供了数据传递的位置,"{\"value\":xx}\r\n",在读取数据时要确定要确定数据在Buffer缓存中的具体位置,可以通过串口打印来粗略判断,也可以通过C函数查找。
4.在读取数据的过程中,每读一次数据Socket就要关闭在开一次,但是测试发现在等待关闭的情况读取几次以后就不能正常关闭,如果出现这种问题可以直接关闭Socket后再打开。