基于STM32+ESP8266的物联网环境监测系统设计

                                                          STM32+UCOSII+ESP8266

参考链接:https://blog.csdn.net/qq_38410730/article/details/86538288

参考资料:朱有鹏老师网络编程部分教程、正点原子官方资料、百度查询

        因为很早之前就一直想做一套完整的物联网系统,所以趁着这段时间的一个设计,就一边学一边尝试着做一套。系统数据采集部分采用大众化的STM32作为主控,再加上一些具有代表性的传感器;数据传输部分即联网媒介选择ESP8266串口WIFI模块;数据处理部分采用LAMP环境的云服务器处理,再加上前端网页共同组成一套完整的IOT系统(功能相对简单)。

        数据采集部分。室内环境几个具有代表性的参数,主要是甲醛、可燃性气体、PM颗粒、温湿度等,故本系统分别用到了ZE08-CH2O甲醛模组、MQ2、PM、DHT11几个传感器。主控采用STM32F103C8T6,这一块因为网上资料非常多,全部开源,所以就不不一一讲述了。这部分主要讲一下我在移植UCOSII的时候,遇到的问题。因为系统涉及到很多传感器,需要进行大量任务,如果一条主任务,肯定是满足不了需求的,所以移植了自己相对较熟悉的UCOSII操作系统。参考教程即为正点原子官方提供的UCOSII移植资料,移植完了后,遇到了一些小问题,比如浮点数8字节对齐( __align(8) 和任务栈大小的设置,这些都可能会影响到某个任务出现卡死的现象,因为这些问题以及解决方法移植资料上面都会提及,就不一一赘述,此处说明是希望大家注意细节。

       数据传输部分。数据上传到互联网则需要联网媒介作为中转,联网的方式有很多,无线、有线,无线又分很多种:无线串口、zigbee、WIFI、蓝牙、GPRS等等,基于多方面考虑,本系统采用ESP8266串口WIFI模块作为联网媒介。关于ESP8266的资料也非常多,原理、代码都讲得非常清楚,因为我采用的是正点原子开发板配套的WIFI模块,所以直接移植了自带的例程,采用的是TCP透传模式,采集终端作为客户端,不断向服务器上传数据。因为MiniStm32例程是自带TFTLCD显示屏的例程,加上WIFI模块,配合按键,可以手动输入模式、IP等等信息,当然了例程运行一切正常。但是因为我暂时不需要显示屏,所以就取消显示屏部分,只需要wifi部分,但是这时候出错了,始终连接不了服务器。此处卡死:

开始以为是服务器的问题,结果调试了很久终于发现了问题,因为例程是自带的配置串口2作为WIFI传输部分,我换了一个串口3马上就好了,当然了并不是串口2配置不对,而是因为例程是开启了DMA传输,即串口2采用DMA传输,可能是因为取消掉显示屏的原因,导致DMA配置部分有一些遗漏,所以DMA传输失败从而导致串口2通信失败,取消DMA传输立即OK。希望大家遇到了类似的问题引起注意。后面调试甲醛传感器的时候,因为其支持两种通信协议,分别是串口和ADC,刚开始采用串口3,后面发现一直失败,而且显示屏字体颜色变淡,读不到数据导致系统卡死,后面发现是因为TFTLCD显示屏和串口3的引脚复用了,PB10,PB11都被显示屏数据口占用,此时想到了端口复用功能,随后参考数据手册发现串口3的复用重映射引脚也同样被占用了,马上看了串口4、5都是一样的结果,没办法,只好改成ADC,采集模拟量,最后成功。

       后台处理部分。本系统租用了一台腾讯云服务器,环境为LAMP(Linux+Apache+Mysql+Php)。因为服务器需要不断接收来自采集终端部分的数据,所以接收服务器采用了socket监听端口的方式来监听接收数据。参考:朱有鹏老师网络编程部分教程。代码附在后面。接收到数据后,需要实时存储到数据库,以更新数据,保证数据的实时性。

       前端网页部分。采用CSS+DIV布局,PHP和服务器交互,目前实现了一部分,能够实时显示采集到的数据,但是目前采用的是比较古老的刷新页面的方法来刷新数据,后面将会加上AJAX局部刷新技术来更新动态数据,并且附上数据动态曲线走势图。

当前效果还比较简陋,暂不贴图,后面完善了再附上详细代码和效果图。望各位见谅...

附代码:

数据传输部分(esp8266):

/***********************************************************
** 函 数 名: wifi_sta_trans_config
** 功能描述: ATK-ESP8266模块TCP透传模式配置
** 输     入: 无
** 输     出: 无
** 返 回 值: 无
** 日    期: 2019/4/23
************************************************************/
void wifi_sta_trans_config(void)
{
        //一、设置工作模式(需重启生效) 1:station模式   2:AP模式  3:兼容 AP+station模式
        atk_8266_send_cmd("AT+CWMODE=1","OK",50);
        
        //二、Wifi模块重启生效
        atk_8266_send_cmd("AT+RST","ready",20);
        
        delay_ms(1000);         //延时3S等待重启成功
        delay_ms(1000);
        delay_ms(1000);
        delay_ms(1000);
        
        //三、模块连接上自己的路由
        while(atk_8266_send_cmd("AT+CWJAP=\"MERCURY\",\"12345678\"","WIFI GOT IP",600));
        
        //四、是否启用多路连接  0:单路连接模式 1:多路连接模式
        atk_8266_send_cmd("AT+CIPMUX=0","OK",20);
        
        //五、建立TCP连接  这四项分别代表了:要连接的ID号0~4   连接类型  远程服务器IP地址   远程服务器端口号
        while(atk_8266_send_cmd("AT+CIPSTART=\"TCP\",\"192.168.x.x\",5000","CONNECT",200));
        
        //六、开启透传模式  0:表示关闭 1:表示开启透传
        atk_8266_send_cmd("AT+CIPMODE=1","OK",200);
        
        //七、透传模式下开始发送数据  这个指令之后就可以直接发数据了
        atk_8266_send_cmd("AT+CIPSEND","OK",50);
}
 

/***********************************************************
** 函 数 名: atk_8266_send_cmd
** 功能描述: 向ATK-ESP8266发送命令
** 输    入: cmd:发送的命令字符串  ack:期待的应答结果,如果为空,则表示不需要等待应答 waittime:等待时间(单位:10ms)
** 输    出: 无
** 返 回 值: 0,发送成功(得到了期待的应答结果) 1,发送失败
** 日    期: 2019/3/23
************************************************************/
u8 atk_8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
    u8 res=0; 
    USART2_RX_STA=0;
    u2_printf("%s\r\n",cmd);    //发送命令  (向WiFi模块发送)
    
    if(ack&&waittime)        //需要等待应答
    {
        while(--waittime)    //等待倒计时
        {
            delay_ms(10);
            if(USART2_RX_STA&0X8000)//接收到期待的应答结果
            {
                if(atk_8266_check_cmd(ack))
                {
                    printf("ack:%s\r\n",(u8*)ack);
                    break;//得到有效数据 
                }
                USART2_RX_STA=0;
            } 
        }
        if(waittime==0)res=1; 
    }
    return res;


/***********************************************************
** 函 数 名: atk_8266_send_data
** 功能描述: 向ATK-ESP8266发送指定数据
** 输    入: data:发送的数据(不需要添加回车了) ack:期待的应答结果,如果为空,则表示不需要等待应答 waittime:等待时间(单位:10ms) 
** 输    出: 无
** 返 回 值: 0,发送成功(得到了期待的应答结果)
** 日    期: 2019/3/23
************************************************************/
u8 atk_8266_send_data(u8 *data,u8 *ack,u16 waittime)
{
    u8 res=0; 
    USART2_RX_STA=0;
    u2_printf("%s",data);                     //发送命令
    
    if(ack&&waittime)                           //需要等待应答
    {
        while(--waittime)                       //等待倒计时
        {
            delay_ms(10);
            if(USART2_RX_STA&0X8000)           //接收到期待的应答结果
            {
                if(atk_8266_check_cmd(ack))break;//得到有效数据 
                USART2_RX_STA=0;
            } 
        }
        if(waittime==0)res=1; 
    }
    return res;
}
 

数据接收部分:

    $my_severIP = "x.x.x.x";                      //服务器IP
    $my_serverPORT = 5000;                   //服务器端口号
    $my_databs_server = "localhost";        //数据库服务器
    $my_databs_user = "root";                   //数据库用户名
    $my_databs_passwd = "xxxxxxxxx";    //数据库密码
    $my_databs_name = "xxx";                 //数据库名称
    
    //连接数据库服务器
    $con = mysql_connect($my_databs_server,$my_databs_user,$my_databs_passwd);//连接数据库
    if (!$con)
    {
        die('can`t connect to database $my_databs_user: ' . mysql_error());
    }
    else
    {
        echo "connect success...";
    }
    
    //选择数据库
    mysql_select_db($my_databs_name, $con);

    
    //**********第1步:socket_create 打开一个网络文件描述符****************
    $socket_fd = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);  

    //**********第2步:socket_bind 绑定sokfd、服务端IP和端口号*************
    if(socket_bind($socket_fd,$my_severIP,$my_serverPORT) == false) //
    {
        echo 'server bind fail:'.socket_strerror(socket_last_error());
    }
    
    //**********第3步:socket_listen 监听端口******************************
    if(socket_listen($socket_fd,4)==false)
    {
        echo 'server listen fail:'.socket_strerror(socket_last_error());
    }
    
    //**********第4步:socket_accept 阻塞等待客户端连接服务器**************
    $client_fd = socket_accept($socket_fd);
    //echo 'clieid :'.$client_fd;
    //**********第5步:建立连接之后,进行通信(服务端接收)*******************************
    while(true)
    {
        $string = (int)socket_read($client_fd,1024);//PHP_BINARY_READ
        //echo 'receive_data:'.$string.PHP_EOL; //PHP_EOL为php的换行预定义常量
        //$string = "66";
        //更新数据表信息
        var_dump($string);
            $result = mysql_query("update indoor set value = '{$string}' where paraname = 'temp' ");
        echo "update indoor set value = '{$string}' where paraname = 'temp' ";
        var_dump($result);
        
    }

    //关掉数据库
    mysql_close($con);
    
?>
 

前端网页部分代码:




室内环境监测系统




室内环境在线监测系统






    $my_databs_server = "localhost";        //数据库服务器
    $my_databs_user = "root";               //数据库用户名
    $my_databs_passwd = "xxxxxx";    //数据库密码
    $my_databs_name = "xxx";                //数据库名称
    
    //连接数据库服务器
    $con = mysql_connect($my_databs_server,$my_databs_user,$my_databs_passwd);//连接数据库
    if (!$con)
    {
        die('can`t connect to database $my_databs_user: ' . mysql_error());
    }
    
    //选择数据库
    mysql_select_db($my_databs_name, $con);

    //选择数据表查看
    $result = mysql_query("SELECT * FROM indoor");

    //以表格形式输出
    echo "


    
    
    
    
    
    ";

    //从数据表中读取数据
    while($row = mysql_fetch_array($result))
    {
        //echo "
";
        //echo $row['paraname'] . "      " . $row['value']. "      " . $row['unit'];
        //echo "
";
        
        echo "

";
        echo "";
        echo "";
        echo "";
        echo "";
        echo "";
    }
    echo "
参数走势曲线单位
  ".$row['paraname']."     ".$row['value']. "                            ".$row['unit']."      
";
    
    //关闭数据库
    mysql_close($con);
?>





返回首页


持续更新中。。。

 

 

 

 

 

 

你可能感兴趣的:(一些感悟,技术分享)