物联网实战之基于OneNET的智能农业系统

想玩物联网的时候物色了很多国内的云平台,最后选了中移云去实现。其实阿里云华为云机智云都不错,机智云网页界面不行但是带APP,阿里云也有个贝壳物联APP功能更强大,华为云不太了解不过好像也还行。中移云感觉更加的纯粹,没有那么多花里胡哨的功能(其实是我用不到而已)。这里记录一下基于4个stm32+lora建立组网,上传数据到云平台这个简单的项目。

硬件环境

物联网实战之基于OneNET的智能农业系统

物联网实战之基于OneNET的智能农业系统

硬件环境即一个主控板(照片找不到了)+三个采集板,基于LORA构建组网,采集3个不同地点的环境数据,通过WIFI模块上发数据到云平台。外加一个OpenMV3做人脸识别。采集板挂载了温湿度+光照强度+LORA模块。

软件环境

IDE:Keil 5.15
OS:Ucos-III

ESP8266 WIFI模块基本知识详解

市面上的WIFI模块大多数都是乐鑫的,通过串口+AT指令,即可简单的进行操作。
硬件连接:
物联网实战之基于OneNET的智能农业系统

AT指令基本结构:
物联网实战之基于OneNET的智能农业系统
WIFI模块和服务器建立连接有两种方式:
物联网实战之基于OneNET的智能农业系统
TCP连接通信比较常用,再该模式下,相应的设备必须处于同一网络中,即处于同一个局域网中!!!AP模式下ESP8266做服务端时就是,手机和电脑必须连在ESP8266的WiFi,才能用网络调试助手等软件与ESP8266通信。

WIFI 模块的AT指令配置大家看官方文档即可,整体了来说还是比较简单的。WIFI一般有WIFI-AP模式,WIFI-STA模式,WIFI-AP兼STA模式三种,这里只说常用的前两种:
①、WIFI-AP模式:首先,我们可以把WIFI模块当成一个热点,开启热点以后别的设备可以连接这个热点,从而我们就可以向连接热点的设备
!!发送数据!!
ESP8266建立TCP服务器时,步骤为:
1.AT+CWMODE=2//配置ESP8266为AP模式,(路由器模式,发出WIFI)。
物联网实战之基于OneNET的智能农业系统
2.AT+RST // 重启模块使刚刚配置模式生效
3.AT+CWSAP=“wifi账号”,“WIFI密码”,1,4
物联网实战之基于OneNET的智能农业系统
4.AT+CIPMUX = 1 // 启动多连接
5.AT+CIPSERVER = 1,8080 // 模块开启服务器模式,端口号8080
这一步一定要保证设备连接到了ESP8266的WIFI,不然会连接失败
6.AT+CIPSEND=X,X // 第一个X是对应的ID号,第二个X是对应的字符个数,调用这个AT指令就可以向对应的客户端发送数据,注意对应的字符个数问题,如果个数少了就不发,个数多了就只发前对应的个数。
以上,便是ESP8266做服务器,PC端(移动端)做客户端的情况。

ESP8266做客户端,PC端(移动端)做服务器时(单路连接),具体的步骤简要为:
物联网实战之基于OneNET的智能农业系统完成连接后,调用AT+CIPSEND这个指令即可与服务器收发数据。这里我们只介绍单路连接,这种模式下是可以做到最多5路连接,感兴趣的话可以查一下相关资料。
物联网实战之基于OneNET的智能农业系统
②.WIFI-STA模式:这个模式与AP模式相反,是ESP8266去连接别的路由器(WIFI),只要保证与通信方处于同一局域网下即可,可以理解为一个基站去接收信号。
ESP8266做服务器,PC做客户端,具体步骤为:
物联网实战之基于OneNET的智能农业系统
到这里,我们发送AT+CWLAP指令可以查询周围的WIFI信号(去酒店之类的可以用这招预防那种WIFI摄像头,但是SD卡那种还是防不了的。。)
发送AT+CWJAP?可以查看WIFI是否真的连接成功。
4.AT+CIPMUX=1启动多连接
5.AT+CIPSERVER=1,8080 // 打开服务器端口为8080
6.AT+CIFSR // 看一下你模块现在分配的ip是多少,只要模块联网就会重新分配ip地址,这也是网络调试助手里面远程主机栏要填写的ip地址。
物联网实战之基于OneNET的智能农业系统

ESP8266做客户端,PC端(移动端)做服务器,具体步骤如下:
1.AT+CWMODE=1,设置为STA模式
2.AT+RST , 重启生效
3.AT+CWJAP=“WIFI账号”,“WIFI密码”
4.AT+CIPMUX=0 ,单连接
5.AT+CIPSTART=“TCP”,“192.168.1.101”,8080
下面用AT+CIPSEND发送数据即可

这次工程是把WIFI模块配成STA模式下的客户端,网站就当成服务器,方便操作。

OneNET建立自己的物联网应用

首先来个官网网址中移云网址,进去以后注册一个自己的账号
物联网实战之基于OneNET的智能农业系统
点击开发者中心,然后创建自己的产品。这里跟着官方文档走就好了,不多赘述创建产品
接入协议这里选择http协议,因为我们只需要POST上报数据,GET获得数据即可。有能力的话建议搞一下MQTT协议,近两年最火的物联网协议。然后建一个设备,这里跟着官方文档走就可以了。最后我们会得到这些必要信息:
物联网实战之基于OneNET的智能农业系统
这四个ID/key是上报数据必须的东西,要做好记录。至此平台端我们已经解决了大半。

收发协议

因为涉及了不同设备多个数据的采集,这里制定了一个简单的协议,只有一个帧头采集板发过来的帧头到主控板会被识别为ASCII码,所以主控接收从机帧头时一定要以ASCII码形式判断。其实出来实习以后,发现这些协议走16进制的话会更方便,便于不同平台之间交互。下面上代码:

u8 a = 0;
u8 b = 0;
u8 c = 0;
u8 RX1_Buff[3];
u8 RX2_Buff[3];
u8 RX3_Buff[3];
int i = 1;
int j = 1;
int k = 1;
char one = '1';
char two = '2';
char three = '3';

void USART2_IRQHandler(void)
{
 u8 res;
 {
  res=USART_ReceiveData(USART2);
  //printf("%c",res);
  if(res == one)
  {
   a = 1;
   two = '7';
   three = '8';
  }
  if(a == 1)
  {
   switch(i)
   {
    case 1:i++;break;
    case 2:i++;RX1_Buff[0] = res;break;
    case 3:i++;RX1_Buff[1] = res;break;
    case 4:i++;RX1_Buff[2] = res;i=1;a=0;two = '2';three = '3';break;
    default:break;
   }
  }
  if(res == two)
  {
   b=1;
   one = '6';
   three = '8';
  }
  if(b == 1)
  {
   switch(j)
   {
    case 1:j++;break;
    case 2:j++;RX2_Buff[0]=res;;break;
    case 3:j++;RX2_Buff[1]=res;;break;
    case 4:j++;RX2_Buff[2]=res;j=1;b=0;one = '1';three = '3';break;
    default:break;
   }
  }
  if(res == three)
  {
   c = 1;
   one = '6';
   two = '7';
  }
  if(c == 1)
  {
   switch(k)
   {
    case 1:k++;break;
    case 2:k++;RX3_Buff[0]=res;break;
    case 3:k++;RX3_Buff[1]=res;break;
    case 4:k++;RX3_Buff[2]=res;k=1;c=0;one = '1';two = '2';break;
    default:break;
   }
  }
  LED0 = ~LED0;
  printf("从机1%d,%d,%drn",RX1_Buff[0],RX1_Buff[1],RX1_Buff[2]);
  printf("从机2%d,%d,%drn",RX2_Buff[0],RX2_Buff[1],RX2_Buff[2]);
  printf("从机3%d,%d,%drn",RX3_Buff[0],RX3_Buff[1],RX3_Buff[2]);
  USART_ClearITPendingBit(USART2,USART_IT_RXNE);
 }
}

其实思想就是每个从机都有自己的一个帧头,后面分别跟着温度湿度光照强度等环境数据。

与OneNET云平台的交互

这里我们把WIFI模块设置为STA工作模式,就是把WIFI模块连接我们手机的热点,然后与OenNET云平台建立TCP连接,开启透传模式。数据通过POST发送,打包成JSON格式。现在知道了官方有个cJSON,经过简单的移植就可以自动打包JSON数据,但是当时年少无知,就直接手打JSON格式就好了。datastreams这个数据后面跟着传感器的名称和数据流的名称即可。api-key从前面我们说的地方获取即可,Host则直接用这个网址就好,Content-Length的值一定要和datastreams后面的大小对应,不然会报格式错误。

#include "common.h"
#include "stdlib.h"
#include "string.h"
#include "dht11.h"
#include "adc.h"
#include "lsens.h"
#include "led.h"   
//ATK-ESP8266 WIFI STA测试
//用于测试TCP/UDP连接
//返回值:0,正常
//    其他,错误代码
extern u8 RX1_Buff[3];
extern u8 RX2_Buff[3];
extern u8 RX3_Buff[3];
u8 atk_8266_wifista_test(void)
{
 u8 key;
 u8 timex=0; 
 u8 b;
 char RX_Buff[200];
 u8 strData[2];
 u8 *p;
 u8 *q;
 u8 *m;
 u16 t=9999;  //加速第一次获取链接状态
 u8 res=0;
 u16 rlen=0;
 u8 constate=0; //连接状态
 HC_Init();//LORA数据收发协议初始化
 atk_8266_send_cmd("AT+CWMODE=1","OK",500);  //设置WIFI STA模式
 atk_8266_send_cmd("AT+RST","OK",200);  //DHCP服务器关闭(仅AP模式有效) 
 delay_ms(1000);         //延时3S等待重启成功
 delay_ms(1000);
 //设置连接到的WIFI网络名称/加密方式/密码,这几个参数需要根据自己的路由器设置进行修改!! 
 //sprintf((char*)p,"AT+CWJAP="%s","%s"",wifista_ssid,wifista_password);//设置无线参数:ssid,密码 
 p = "AT+CWJAP="mayday123","sunshine998"";
 while(atk_8266_send_cmd(p,"WIFI GOT IP",3000));     //连接目标路由器,并且获得IP
 {
 atk_8266_send_cmd("AT+CIPMUX=0","OK",200);   //0:单连接,1:多连接
 q = "AT+CIPSTART="TCP","183.230.40.33",80";
 //sprintf((char*)p,"AT+CIPSTART="TCP","%s",%s",(u8*)ipbuf,(u8*)portnum);    //配置目标TCP服务器
 while(atk_8266_send_cmd(q,"OK",2000));
 atk_8266_send_cmd("AT+CIPMODE=1","OK",2000);      //传输模式为:透传   
 }
 USART3_RX_STA=0;
 atk_8266_quit_trans();
 atk_8266_send_cmd("AT+CIPSEND","OK",200);         //开始透传 
 while(1)
 {
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 
///***********************************发送第一从机温度数据**************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:63rn
rn
{"datastreams":[{"id":"temp_num","datapoints":[{"value":%d}]}]}",RX1_Buff[0]);
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
///******************************************************************************************/
delay_ms(500);
///***********************************发送第一从机湿度数据**************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:63rn
rn
{"datastreams":[{"id":"humi_num","datapoints":[{"value":%d}]}]}",RX1_Buff[1]);
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
///******************************************************************************************/
delay_ms(500);
///***********************************发送第一从机光照强度数据************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:63rn
rn
{"datastreams":[{"id":"illu_num","datapoints":[{"value":%d}]}]}",RX1_Buff[2]);
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
///******************************************************************************************/ 
delay_ms(500);  
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/  
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/   
/***********************************发送第二从机温度数据**************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:64rn
rn
{"datastreams":[{"id":"temp1_num","datapoints":[{"value":%d}]}]}",RX2_Buff[0]); 
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
/*********************************************************************************************/
delay_ms(500);
///***********************************发送第二从机湿度数据**************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:64rn
rn
{"datastreams":[{"id":"humi1_num","datapoints":[{"value":%d}]}]}",RX2_Buff[1]);
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
///******************************************************************************************/
delay_ms(500); 
///***********************************发送第二从机光照强度数据************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:64rn
rn
{"datastreams":[{"id":"illu1_num","datapoints":[{"value":%d}]}]}",RX2_Buff[2]);
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
/******************************************************************************************/     
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/  
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 
/***********************************发送第三从机温度数据**************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:64rn
rn
{"datastreams":[{"id":"temp2_num","datapoints":[{"value":%d}]}]}",RX3_Buff[0]);
    
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
/*********************************************************************************************/
delay_ms(500);
/***********************************发送第三从机湿度数据*************************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:64rn
rn
{"datastreams":[{"id":"humi2_num","datapoints":[{"value":%d}]}]}",RX3_Buff[1]);
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
///******************************************************************************************/
delay_ms(500); 
///***********************************发送第三从机光照强度数据*********************************/
    sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:64rn
rn
{"datastreams":[{"id":"illu2_num","datapoints":[{"value":%d}]}]}",RX3_Buff[2]);
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
/******************************************************************************************/ 
    delay_ms(500);
    if(LED2 == 1)
    {
     sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:63rn
rn
{"datastreams":[{"id":"open_see","datapoints":[{"value":11}]}]}");
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
    }else{
     sprintf(RX_Buff,"POST /devices/526305478/datapoints HTTP/1.1rn
api-key:AXFPHI6MWoj6oTvz6MQVyEGANR0=rn
Host:api.heclouds.comrn
Content-Length:63rn
rn
{"datastreams":[{"id":"open_see","datapoints":[{"value":22}]}]}");
    u3_printf("%s",RX_Buff);
//    delay_ms(500);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }
    }
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/  
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ 
/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/     
    atk_8266_at_response(1);
    for(b = 0;b  sizeof(RX_Buff);b++)
    {
     RX_Buff[b] = 0 ;
    }  
   }
 return res;  
}

AT指令的发送直接用了原子的程序,在串口中断里根据协议接收数据然后上发到云平台即可。简要来说就是:
通过将WIFI连接上网络,解析出OneNET云平台的IP和端口号,在云平台新建设备,每个设备会分配一个独有的序列号(用于WIFI与设备连接),然后通过AT指令,将WIFI模块连接上云平台,此时用WIFI发送在云平台新建好的设备的序列号,即可连接设备,与设备进行通信。然后定时发送从采集板收到的数据,当数据超过云平台的报警值之后,云平台会自动报警,并将报警信息通过用户绑定邮箱发送给用户,实现实时监测的效果。

把每个步骤都打印出来:
物联网实战之基于OneNET的智能农业系统

当执行到指令AT+CIPSEND时,将数据打包成JSON格式发送即可。

反馈的信息为:
物联网实战之基于OneNET的智能农业系统
这个项目比较简单不需要解析反馈的JSON格式的数据,当error后面为0时,则代表数据上传正确。

下面介绍两个比较重要的点。
如何截取整段反馈的JSON报文

//串口接收缓存区  
u8 USART3_RX_BUF[USART3_MAX_RECV_LEN];     //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
u8 USART3_TX_BUF[USART3_MAX_SEND_LEN];    //发送缓冲,最大USART3_MAX_SEND_LEN字节
//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
vu16 USART3_RX_STA=0;   
void USART3_IRQHandler(void)
{
 u8 res;       
 if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
 {  
  res =USART_ReceiveData(USART3);   
  if((USART3_RX_STA&(115))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
  { 
   if(USART3_RX_STAUSART3_MAX_RECV_LEN) //还可以接收数据
   {
    TIM_SetCounter(TIM7,0);//计数器清空              //计数器清空
    if(USART3_RX_STA==0)     //使能定时器7的中断 
    {
     TIM_Cmd(TIM7,ENABLE);//使能定时器7
    }
    USART3_RX_BUF[USART3_RX_STA++]=res; //记录接收到的值  
   }else 
   {
    USART3_RX_STA|=115;    //强制标记接收完成
   } 
  }
 }                   
}   
//初始化IO 串口3
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率   
void usart3_init(u32 bound)
{  
 NVIC_InitTypeDef NVIC_InitStructure;
 GPIO_InitTypeDef GPIO_InitStructure;
 USART_InitTypeDef USART_InitStructure;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // GPIOB时钟
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能
  USART_DeInit(USART3);  //复位串口3
   //USART3_TX   PB10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10               
    //USART3_RX   PB11
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11 
 USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 
 USART_Init(USART3, &USART_InitStructure); //初始化串口 3
 USART_Cmd(USART3, ENABLE);                    //使能串口 
 //使能接收中断
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   
 //设置中断优先级
 NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //子优先级3
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能
 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
 TIM7_Int_Init(10000-1,7200-1);  //100ms中断
 USART3_RX_STA=0;  //清零
 TIM_Cmd(TIM7,DISABLE);   //关闭定时器7
}

这里也是用原子的程序,其实思想很简单,第一次进入串口中断时打开定时器,一定时间(10ms)没有接收到数据就判定为一帧数据接收完毕。其实如果现在做这个的话直接用IDEL更方便,不需要这么麻烦。

串口3的重定向

//va_list 是C语言定义的宏,解决变量参数的一个宏,可以传入一个参数或多个参数,且对类型无要求,用法:
//首先在函数中,定义一个具有va_list类型的参数ap
//然后在va_start宏初始化变量刚定义的va_list类型的变量,执行:ap = (va_list)&fmt + _INTSIZEOF(fmt),此时ap指向第一个可变参数在堆栈的地址。
//函数声明:int vsprintf(char *str, const char *format, va_list arg)
//str -- str指向一个字符数组的指针,该数组存储了C字符串。
//format -- 这是字符串,包含了要被写入到字符串str的文本。它可以包含嵌入的format标签,format标签可被随后的附加参数中指定的值替换
//并按需求进行格式化。format标签属性是%[flags][width][.precision][length]specifier。
//va_end(ap)的作用是清空va_list ap。
//下面是事例,一看就懂。
void u3_printf(char* fmt,...)  
{  
 u16 i,j; 
 va_list ap; 
 va_start(ap,fmt);
 vsprintf((char*)USART3_TX_BUF,fmt,ap);
 va_end(ap);
 i=strlen((const char*)USART3_TX_BUF);  //此次发送数据的长度
 for(j=0;ji;j++)       //循环发送数据
 {
   while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕   
  USART_SendData(USART3,USART3_TX_BUF[j]); 
 } 
}

这个其实没啥讲的,用的东西是非开源的,只要直到怎么用就好了,注释的很清楚。这样做就可以把串口3以printf的形式调用,非常方便。

效果展示

物联网实战之基于OneNET的智能农业系统
物联网实战之基于OneNET的智能农业系统
物联网实战之基于OneNET的智能农业系统
在我们的云平台是可以搭建界面的,这里显示了3地温湿度,光照强度的曲线比较,并且也可以单独显示某一个地点的环境数据,并且还有异常报警机制,就是发邮箱了。。

本文章来源于互联网,如有侵权,请联系删除!原文地址:物联网实战之基于OneNET的智能农业系统

相关推荐: IOT大世界大未来,微构科技物联网产业大数据应用简析

在物联网时代,面对PB级的数据,企业将难以以一己之力完成基础设施的建设。物联网所产生的大量数据不仅会驱动现在的数据中心发生根本性的变化,同时也会驱动相关企业采用新的大数据策略。 物联网的价值在于数据:企业对数据的分析工作启动地越快,挖掘出的业务价值就越多。而大…