对于yeelink服务器的请求的最快的频率是11秒一次,请求时间间隔小于10秒的时候会丢包,不知道机智云的效果怎么样,有尝试过的朋友可以留言。
stm32将18b20的温度信息上传到yeelink服务器。上位机读取yeelink服务器的数据。同时可用stm32串口查看服务器的回传信息(usart1 波特率115200 无校验位 一个停止位)。
上位机显示界面,代码和上一篇的代码基本相同。不同的地方是定时器的时间间隔加长了,因为时间间隔过短会导致丢包。
下位机是stm32zet6+18b20.18b20的DQ引脚接PG11,至于w5500按照用户手册插线即可。用网线将路由器和w5500模块连接(因为路由器可以自动分配ip地址,使用起来很方便)。
下位机的难点是dns解析。
/**
******************************************************************************
* @file main.c
* $Author: 飞鸿踏雪 $
* $Revision: 17 $
* $Date:: 2014-10-25 11:16:48 +0800 #$
* @brief 主函数.
******************************************************************************
* @attention
*
*© Copyright 2009-2012, EmbedNet
*http://www.embed-net.com
*All Rights Reserved
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "delay.h"
#include "spi.h"
#include "socket.h" // Just include one header for WIZCHIP
#include "Internet/DNS/dns.h"
#include "timer.h"
#include
#include
/* Private typedef -----------------------------------------------------------*/
#include "ds18b20.h"
/* Private define ------------------------------------------------------------*/
#define SOCK_TCPS 0
#define SOCK_DNS 1
#define DATA_BUF_SIZE 2048
/* Private macro -------------------------------------------------------------*/
uint8_t gDATABUF[DATA_BUF_SIZE];
uint8_t domain_ip[4]={0};
uint8_t domain_name[]="yeelink.net";
// Default Network Configuration
wiz_NetInfo gWIZNETINFO = { .mac = {0x00, 0x08, 0xdc,0x00, 0xab, 0xcd},
.ip = {192, 168, 0, 123},//貌似瞎写就行
.sn = {255,255,255,0},
.gw = {192, 168, 0, 1},//这个也需要用ipconfig /all查看
.dns = {192, 168, 0, 1},//修改成自己网络的DNS,windows下需要用ipconfig /all查看dns服务器地址
.dhcp = NETINFO_STATIC };
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void platform_init(void); // initialize the dependent host peripheral
void network_init(void); // Initialize Network information and display it
uint8_t yeelink_get(const char *device_id,const char *sensors_id,char *value);
/**
* @brief 串口打印输出
* @param None
* @retval None
*/
int main(void)
{
uint8_t tmp;
int32_t ret = 0,t=0;
uint8_t memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};
char value[16]={0};
delay_init();
// DS18B20_Init();
while(DS18B20_Init()) //DS18B20初始化
{
}
//Host dependent peripheral initialized
platform_init();
// First of all, Should register SPI callback functions implemented by user for accessing WIZCHIP
/* Critical section callback */
reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit); //注册临界区函数
/* Chip selection call back */
#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_
reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);//注册SPI片选信号函数
#elif _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_FDM_
reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect); // CS must be tried with LOW.
#else
#if (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SIP_) != _WIZCHIP_IO_MODE_SIP_
#error "Unknown _WIZCHIP_IO_MODE_"
#else
reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);
#endif
#endif
/* SPI Read & Write callback function */
reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte); //注册读写函数
/* WIZCHIP SOCKET Buffer initialize */
if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1){
printf("WIZCHIP Initialized fail.\r\n");
while(1);
}
/* PHY link status check */
do{
if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1){
printf("Unknown PHY Link stauts.\r\n");
}
}while(tmp == PHY_LINK_OFF);
/* Network initialization */
network_init();
/* DNS client initialization */
DNS_init(SOCK_DNS, gDATABUF);
Timer_Start();
/* DNS procssing */
if ((ret = DNS_run(gWIZNETINFO.dns, domain_name, domain_ip)) > 0){ // try to 1st DNS
printf("> 1st DNS Reponsed\r\n");
}else if(ret == -1){
printf("> MAX_DOMAIN_NAME is too small. Should be redefined it.\r\n");
Timer_Stop();
while(1);
}else{
printf("> DNS Failed\r\n");
Timer_Stop();
while(1);
}
//DNS解析成功
if(ret > 0){
printf("> Translated %s to %d.%d.%d.%d\r\n",domain_name,domain_ip[0],domain_ip[1],domain_ip[2],domain_ip[3]);
}
Timer_Stop();
while(1)
{
yeelink_get("358143","406963",value);//获取开关变量
// printf("%s\n\r",value);
// delay_ms(1000);
for(t=0;t<11;t++){
delay_ms(1000);
}
}
}
/**
* @brief Intialize the network information to be used in WIZCHIP
* @retval None
*/
void network_init(void)
{
uint8_t tmpstr[6];
ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);
ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
// Display Network Information
ctlwizchip(CW_GET_ID,(void*)tmpstr);
printf("\r\n=== %s NET CONF ===\r\n",(char*)tmpstr);
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);
printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
printf("======================\r\n");
}
/**
* @brief Loopback Test Example Code using ioLibrary_BSD
* @retval None
*/
void platform_init(void)
{
SystemInit();//系统时钟初始化
USART_Configuration();//串口1初始化
printf("\x0c");printf("\x0c");//超级终端清屏
printf("\033[1;40;32m");//设置超级终端背景为黑色,字符为绿色
printf("\r\n*******************************************************************************");
printf("\r\n************************ Copyright 2009-2014, EmbedNet ************************");
printf("\r\n*************************** http://www.embed-net.com **************************");
printf("\r\n***************************** All Rights Reserved *****************************");
printf("\r\n*******************************************************************************");
printf("\r\n");
//Config SPI
SPI_Configuration();
//延时初始化
delay_init();
//初始化DNS所需要的定时器
Timer_Config();
}
uint8_t yeelink_get(const char *device_id,const char *sensors_id,char *value)
{
int ret;
int temperature=256;
char* presult;
char remote_server[] = "api.yeelink.net";
char str_tmp[128] = {0};
// 请求缓冲区和响应缓冲区
static char http_request[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
static char http_response[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
static char test_request[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
static char http_content[64] = { 0, };
temperature=DS18B20_Get_Temp();
sprintf(http_content, "{\"value\":%d}", temperature);
sprintf(test_request,"POST /v1.0/device/写自己的/sensor/写自己的/datapoints HTTP/1.1\r\nHost:api.yeelink.net\r\nU-ApiKey:写自己的\r\nContent-Length:%d\r\nContent-Type:application/x-www-form-urlencoded\r\n\r\n{\"value\":%d}",strlen(http_content),temperature);
sprintf(str_tmp,"/v1.0/device/%s/sensor/%s/datapoints",device_id,sensors_id);
// 确定 HTTP请求首部
// 例如POST /v1.0/device/98d19569e0474e9abf6f075b8b5876b9/1/1/datapoints/add HTTP/1.1\r\n
sprintf( http_request , "GET %s HTTP/1.1\r\n",str_tmp);
// 增加属性 例如 Host: api.machtalk.net\r\n
sprintf( str_tmp , "Host:%s\r\n" , remote_server);
strcat( http_request , str_tmp);
// 增加密码 例如 APIKey: d8a605daa5f4c8a3ad086151686dce64
sprintf( str_tmp , "U-ApiKey:%s\r\n" , "写自己的");//需要替换为自己的APIKey
strcat( http_request , str_tmp);
//
strcat( http_request , "Accept: */*\r\n");
// 增加表单编码格式 Content-Type:application/x-www-form-urlencoded\r\n
strcat( http_request , "Content-Type: application/x-www-form-urlencoded\r\n");
strcat( http_request , "Connection: close\r\n");
// HTTP首部和HTTP内容 分隔部分
strcat( http_request , "\r\n");
//将数据通过TCP发送出去
//新建一个Socket并绑定本地端口5000
ret = socket(SOCK_TCPS,Sn_MR_TCP,5000,0x00);
if(ret != SOCK_TCPS){
printf("%d:Socket Error\r\n",SOCK_TCPS);
while(1);
}
//连接TCP服务器
ret = connect(SOCK_TCPS,domain_ip,80);
if(ret != SOCK_OK){
printf("%d:Socket Connect Error\r\n",SOCK_TCPS);
while(1);
}
//发送请求
// ret = send(SOCK_TCPS,(unsigned char *)http_request,strlen(http_request));
ret = send(SOCK_TCPS,(unsigned char *)test_request,strlen(test_request));
if(ret != strlen(test_request)){
printf("%d:Socket Send Error\r\n",SOCK_TCPS);
while(1);
}
// 获得响应
ret = recv(SOCK_TCPS,(unsigned char *)http_response,DATA_BUF_SIZE);
if(ret <= 0){
printf("%d:Socket Get Error\r\n",SOCK_TCPS);
while(1);
}
http_response[ret] = '\0';
//判断是否收到HTTP OK
printf("%s",http_response);
// presult = strstr( (const char *)http_response , (const char *)"200 OK\r\n");
// if( presult != NULL ){
// static char strTmp[DATA_BUF_SIZE]={0};//声明为静态变量,防止堆栈溢出
// sscanf(http_response,"%*[^{]{%[^}]",strTmp);
// //提取返回信息
// char timestamp[64]={0};
// char timestampTmp[64]={0};
// char valueTmp[64]={0};
// sscanf(strTmp,"%[^,],%[^,]",timestampTmp,valueTmp);
// strncpy(timestamp,strstr(timestampTmp,":")+2,strlen(strstr(timestampTmp,":"))-3);
// strncpy(value,strstr(valueTmp,":")+1,strlen(strstr(valueTmp,":"))-1);
// }else{
// printf("Http Response Error\r\n");
// printf("%s",http_response);
// }
close(SOCK_TCPS);
return 0;
}
/*********************************END OF FILE**********************************/
上述代码是网站上的大神编写的。不过已经被我按照自己的需求更改过了。下面的链接是这个大神的博客,里面有他的源码。
http://www.embed-net.com/forum.php?mod=viewthread&tid=69
这是文章链接。他写了很多关于yeelink的博客,都很有用。
http://www.embed-net.com/thread-57-1-1.html
这是用stm32实现域名解析的链接。
上图显示了工程所引用的文件。个人感觉dns.c dhcp.c的文件嘴刁。他们可以将域名解析成ip地址。前提是要在程序里面书写正确的dns服务器地址。
因为我的电脑里面安装了虚拟机,所以可能和大多数人不一样。上面三张命令行的图片中的第一张图片显示了dns服务器的ip地址,网关地址等重要信息。在stm32的程序中把自己的dns服务器的地址写上,网关也写上。就可以解析域名了。
uint8_t yeelink_get(const char *device_id,const char *sensors_id,char *value)
{
int ret;
int temperature=256;
char* presult;
char remote_server[] = "api.yeelink.net";
char str_tmp[128] = {0};
// 请求缓冲区和响应缓冲区
static char http_request[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
static char http_response[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
static char test_request[DATA_BUF_SIZE] = {0}; //声明为静态变量,防止堆栈溢出
static char http_content[64] = { 0, };
temperature=DS18B20_Get_Temp();
sprintf(http_content, "{\"value\":%d}", temperature);
sprintf(test_request,"POST /v1.0/device/写自己的/sensor/写自己的/datapoints HTTP/1.1\r\nHost:api.yeelink.net\r\nU-ApiKey:写自己的\r\nContent-Length:%d\r\nContent-Type:application/x-www-form-urlencoded\r\n\r\n{\"value\":%d}",strlen(http_content),temperature);
sprintf(str_tmp,"/v1.0/device/%s/sensor/%s/datapoints",device_id,sensors_id);
// 确定 HTTP请求首部
// 例如POST /v1.0/device/98d19569e0474e9abf6f075b8b5876b9/1/1/datapoints/add HTTP/1.1\r\n
sprintf( http_request , "GET %s HTTP/1.1\r\n",str_tmp);
// 增加属性 例如 Host: api.machtalk.net\r\n
sprintf( str_tmp , "Host:%s\r\n" , remote_server);
strcat( http_request , str_tmp);
// 增加密码 例如 APIKey: d8a605daa5f4c8a3ad086151686dce64
sprintf( str_tmp , "U-ApiKey:%s\r\n" , "写自己的");//需要替换为自己的APIKey
strcat( http_request , str_tmp);
//
strcat( http_request , "Accept: */*\r\n");
// 增加表单编码格式 Content-Type:application/x-www-form-urlencoded\r\n
strcat( http_request , "Content-Type: application/x-www-form-urlencoded\r\n");
strcat( http_request , "Connection: close\r\n");
// HTTP首部和HTTP内容 分隔部分
strcat( http_request , "\r\n");
//将数据通过TCP发送出去
//新建一个Socket并绑定本地端口5000
ret = socket(SOCK_TCPS,Sn_MR_TCP,5000,0x00);
if(ret != SOCK_TCPS){
printf("%d:Socket Error\r\n",SOCK_TCPS);
while(1);
}
//连接TCP服务器
ret = connect(SOCK_TCPS,domain_ip,80);
if(ret != SOCK_OK){
printf("%d:Socket Connect Error\r\n",SOCK_TCPS);
while(1);
}
//发送请求
// ret = send(SOCK_TCPS,(unsigned char *)http_request,strlen(http_request));
ret = send(SOCK_TCPS,(unsigned char *)test_request,strlen(test_request));
if(ret != strlen(test_request)){
printf("%d:Socket Send Error\r\n",SOCK_TCPS);
while(1);
}
// 获得响应
ret = recv(SOCK_TCPS,(unsigned char *)http_response,DATA_BUF_SIZE);
if(ret <= 0){
printf("%d:Socket Get Error\r\n",SOCK_TCPS);
while(1);
}
http_response[ret] = '\0';
//判断是否收到HTTP OK
printf("%s",http_response);
// presult = strstr( (const char *)http_response , (const char *)"200 OK\r\n");
// if( presult != NULL ){
// static char strTmp[DATA_BUF_SIZE]={0};//声明为静态变量,防止堆栈溢出
// sscanf(http_response,"%*[^{]{%[^}]",strTmp);
// //提取返回信息
// char timestamp[64]={0};
// char timestampTmp[64]={0};
// char valueTmp[64]={0};
// sscanf(strTmp,"%[^,],%[^,]",timestampTmp,valueTmp);
// strncpy(timestamp,strstr(timestampTmp,":")+2,strlen(strstr(timestampTmp,":"))-3);
// strncpy(value,strstr(valueTmp,":")+1,strlen(strstr(valueTmp,":"))-1);
// }else{
// printf("Http Response Error\r\n");
// printf("%s",http_response);
// }
close(SOCK_TCPS);
return 0;
}
用上面这段程序向服务器发送指令。但是一定要记住,不管是上位机发送指令还是下位机发送指令,指令之间的时间间隔必须大于10秒。否则会出错。
if ((ret = DNS_run(gWIZNETINFO.dns, domain_name, domain_ip)) > 0){ // try to 1st DNS
printf("> 1st DNS Reponsed\r\n");
}else if(ret == -1){
printf("> MAX_DOMAIN_NAME is too small. Should be redefined it.\r\n");
Timer_Stop();
while(1);
}else{
printf("> DNS Failed\r\n");
Timer_Stop();
while(1);
}
初始化中(while死循环外部)有域名解析
一下代码是yeelink_get函数里面的
//新建一个Socket并绑定本地端口5000
ret = socket(SOCK_TCPS,Sn_MR_TCP,5000,0x00);
if(ret != SOCK_TCPS){
printf("%d:Socket Error\r\n",SOCK_TCPS);
while(1);
}
创建端口
//连接TCP服务器
ret = connect(SOCK_TCPS,domain_ip,80);
if(ret != SOCK_OK){
printf("%d:Socket Connect Error\r\n",SOCK_TCPS);
while(1);
}
与服务器连接
//发送请求
// ret = send(SOCK_TCPS,(unsigned char *)http_request,strlen(http_request));
ret = send(SOCK_TCPS,(unsigned char *)test_request,strlen(test_request));
if(ret != strlen(test_request)){
printf("%d:Socket Send Error\r\n",SOCK_TCPS);
while(1);
}
向服务器发送请求,再次强调,任何想yeelink服务器发送请求的时间间隔必须大于10秒
// 获得响应
ret = recv(SOCK_TCPS,(unsigned char *)http_response,DATA_BUF_SIZE);
if(ret <= 0){
printf("%d:Socket Get Error\r\n",SOCK_TCPS);
while(1);
}
http_response[ret] = '\0';
//判断是否收到HTTP OK
printf("%s",http_response);
获得服务器的回传数据,并将其数据通过串口打印到串口调试住手。
close(SOCK_TCPS);
关闭套接字
主要步骤为:域名解析 建立套接字 连接服务器 向服务器发送请求 服务器回传信息 关闭套接字(第一次)
建立套接字 连接服务器 向服务器发送请求 服务器回传信息 关闭套接字 (域名解析一次就行了)
http://download.csdn.net/detail/m1f2c3/9849558
YIXIN_W5500模块用户手册
http://download.csdn.net/detail/m1f2c3/9849573
JXW_W5500+模块配套资料
http://download.csdn.net/detail/m1f2c3/9849630
yeelink+stm32+18b20下位机