STM32 S5P6818在智能家居领域的应用与解析

采用 S5P6818作为网关,接收STM32串口发来的协议数据包,再将其转换为mqtt协议数据包。

网关在将数据从传给云平台——这里用阿里飞燕云平台。

为了平衡成本与性能,采用STM32连接温湿度传感器、灯、报警器、电机等,充当终端节点,而为了提高性能采用S5P6818做网关。


一、项目概述

本项目采用STM32搭建终端节点,应用OLED显示屏、电机、灯光、报警器、ds18b20温湿度传感器,通过TCP协议将串口数据传递给S5P6818搭建的服务器端,采用QT进行图形界面的设置,同时连接舵机、报警器等。服务器通过MQTT协议链接阿里云飞燕平台,上传温度、湿度等环境数据。并通过云平台连接手机APP,控制电机、舵机等完成相关命令。

  • 电机:控制窗帘,电机正转控制窗帘开,反转控制窗帘关
  • OLED显示屏:显示当前温湿度数据
  • 舵机:连接摄像头,进行实时监控,传输监控画面,舵机可使其自由摆动(按角度),可360度无死角。并识别人脸信息,对非法入侵者进行拍照。
  • 超声波传感器:采用驱动编程,设定相应距离,检测人员靠近时进行警报。超声波测距存在误差,采用相应算法进行计算消除。
  • QT界面:同步手机APP界面,多平台操作
  • 二、搭建服务器。

    使用S5P6818使其能够连接网络,将灯、报警器等传感器获取信息传递至云平台。

    三、搭建云平台准备工作

    X6818利用MQTT协议对接云平台,本项目采用阿里飞燕云平台。

    主要实现对室内灯光的控制,和对灯光状态、温度状态的显示

    将下位机X6818连接到家里路由器(或自己的手机热点)上

    让开发板能够连接网络,主要通过串口WIFI ESP8266上网

    思路:

    1.采用有线连接的方式

    将下位机连接到家里路由器上,很麻烦,且物理限制较多

    2.故实验后采用无线WIFI方式

    需要下位机连接一个USB WIFI模块(TPLINK USB WIFI模块)

    3.添加WIFI模块驱动

    在上位机执行:内核添加:

    cd /opt/kernel
       make menuconfig
        Networking supports-> //网络协议,更改以下配置内核源码让WIFI无线通信协议802.11协议支持
       	    Wireless->
       	      [*]   cfg80211 wireless extensions compatibility
      	      [*]   Wireless extensions sysfs files      
        Device Drivers-> //支持WIFI的AP模式——别人连他,他也可以连别人
       		Network device supports->
       			  [*]   Wireless LAN  --->
       			  		 <*>   IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP) 
       			  		  [*]     Support downloading firmware images with Host AP driver 
       			  		   [*]       Support for non-volatile firmware download 
       make uImage
       

    重新烧写新的uImage

     mkdir /opt/rootfs/home/wifi/
       mkdir /opt/project/wifi/drivers/ -p   //注意:以后项目内容都是放在/opt/project目录中
       cp DPO_MT7601U_LinuxSTA_3.0.0.4_20130913.tar.bz2 /opt/project/wifi/drivers//移植WIFI驱动程序
       cd /opt/project/wifi/drivers/
       tar -xvf DPO_MT7601U_LinuxSTA_3.0.0.4_20130913.tar.bz2
       cd DPO_MT7601U_LinuxSTA_3.0.0.4_20130913
       make
       mkdir /opt/rootfs/etc/Wireless/RT2870STA -p
       cp os/linux/mt7601Usta.ko /opt/rootfs/home/drivers/
       cp RT2870STA.dat /opt/rootfs/etc/Wireless/RT2870STA/
    
    

    插入USB接口的WIFI模块到下位机的USB口上
       开发板加载驱动:
       insmod /home/drivers/mt7601Usta.ko //安装驱动
       ifconfig -a //获取WIFI的设备信息ra0 ,查看WIFI驱动是否成功


    4.移植wiretools——用WIFI连手机热点
     

    上位机执行:
      mkdir /opt/project/wifi/
      cp wireless_tools.29.tar.gz /opt/project/wifi/
      cd /opt/project/wifi/
      tar -xvf wireless_tools.29.tar.gz
      cd wireless_tools.29

      vim Makefile
      将
      CC,AR,RANLIB
      修改为:
      CC = arm-cortex_a9-linux-gnueabi-gcc
      AR = arm-cortex_a9-linux-gnueabi-ar
     RANLIB =arm-cortex_a9-linux-gnueabi-ranlib
     保存退出
     make
     cp libiw.so.29 /opt/rootfs/lib/  //三个工具: //需要一个动态库,给需要上网的软件用
     cp iwconfig /opt/rootfs/bin
     cp iwpriv /opt/rootfs/bin/
     cp iwlist /opt/rootfs/bin/

    5.移植wpa——让手机连接热点,依赖于两个库

  • 移植NL库
  •   cp  libnl-1.1.4.tar.gz /opt/project/wifi
      cd /opt/project/wifi/
      tar -xvf  libnl-1.1.4.tar.gz
      cd  libnl-1.1.4
      ./configure –prefix=/opt/project/wifi/install  //指定安装路径
      rm lib/libnl.a //针对X86的静态库去掉
      make CC=arm-cortex_a9-linux-gnueabi-gcc AR=arm-cortex_a9-linux-gnueabi-ar LD=arm-cortex_a9-linux-gnueabi-ld  //编译,把里面编译路径,按命令行传参改一改
      make install  //安装

  •   移植openssl库
  •   cp  openssl-1.0.0.tar.gz /opt/project/wifi
      cd /opt/project/wifi/
      tar -xvf  openssl-1.0.0.tar.gz
      cd  openssl-1.0.0
      ./config no-asm shared –prefix=/opt/project/wifi/install  //生成makefile文件,shared生成动态库,后面为指定安装路径
     vim Makefile
    修改交叉编译器

  • 将:
  • CC= gcc
    AR= ar $(ARFLAGS) r
    RANLIB= /usr/bin/ranlib
    NM= nm

    修改为:
    CC= arm-cortex_a9-linux-gnueabi-gcc
    AR= arm-cortex_a9-linux-gnueabi-ar $(ARFLAGS) r
    RANLIB= arm-cortex_a9-linux-gnueabi-ranlib
    NM= arm-cortex_a9-linux-gnueabi-nm

    去掉此文件中所有的-m64,这四个字符,不需要支持64位
    保存退出

    make 
    make install //安装完毕,可以去/opt/project/wifi/install目录下查看生成的内容

      cp  wpa_supplicant-2.6.tar.gz /opt/project/wifi
      cd /opt/project/wifi/
      tar -xvf  wpa_supplicant-2.6.tar.gz
      cd  wpa_supplicant-2.6/wpa_supplicant
      cp defconfig .config  //拷贝默认配置文件
      

  • 修改.config
  • vim .config
    开头添加:
    CC= arm-cortex_a9-linux-gnueabi-gcc -L/opt/project/wifi/install/lib  //指定交叉编译器
    CFLAGS += -I/opt/project/wifi/install/include
    LIBS += -L/opt/project/wifi/install/lib
    保存退出

    vim Makefile

  • 将:
  • wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
        $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
        @$(E) "  LD " $@

    修改为 //修改为静态编译,不需要动态库了
    wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
        $(Q)$(LDO) –static $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) -lm -lpthread 
        @$(E) "  LD " $@

  • wpa_cli: $(OBJS_c)
        $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
        @$(E) "  LD " $@

    修改为
    wpa_cli: $(OBJS_c)
        $(Q)$(LDO) –static $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
        @$(E) "  LD " $@
    保存退出
    make

    cp wpa_supplicant /opt/rootfs/bin/
    cp wpa_cli /opt/rootfs/bin/
    cp wpa_passphrase /opt/rootfs/bin/

  • vim /opt/rootfs/etc/wpa_supplicant.conf 添加如下内容:
  • ctrl_interface=/var/run/wpa_supplicant
    network={
    ssid="youcw" #你的热点名称
    scan_ssid=1
    key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
    pairwise=TKIP CCMP
    group=CCMP TKIP WEP104 WEP40
    psk="asd12345" #你的密码
    }
    保存退出

  • DHCP动态分配地址服务
  • mkdir /opt/rootfs/usr/share/udhcpc/ -p 
    cp default.script /opt/rootfs/usr/share/udhcpc/   //统一的动态分配ip地址的脚本文件
    chmod 777 /opt/rootfs/usr/share/udhcpc/default.script //添加可执行权限
    mkdir /opt/rootfs/tmp
    touch /opt/rootfs/etc/resolv.conf

  • vim /opt/rootfs/etc/hosts 添加  ,指定本地回环IP地址和别名
  •  127.0.0.1   localhost
    保存退出

  • vim /opt/rootfs/etc/resolv.conf 添加,域名解析,DNS域名解析
  • nameserver 114.114.114.114 //全球公用·DNS
    nameserver 8.8.8.8  
    保存退出

  • 所需的动态库全部拷贝到 /opt/rootfs/lib目录下
  • cp /opt/toolchains/arm-cortex_a9-linux-gnueabi/sysroot/lib/* /opt/rootfs/lib/ -frd

    6.下位机测试

      提前准备好手机的热点或者家里的路由器
      插入WiFi模块
      注意:驱动安装完毕,驱动程序会疯狂的打印wifi驱动的调试信息,如果看的心烦,只需将默认打印级别调高
      echo 4 > /proc/sys/kernel/printk
      如果安装驱动之后,发现内核崩溃,系统重启,此时需要更换USB口
      
      insmod /home/drivers/mt7601Usta.ko
      mkdir /var/run
      wpa_supplicant -B -d -Dwext -ira0 -c /etc/wpa_supplicant.conf  //WIFI连手机热点
      udhcpc -i ra0 //动态的为WIFI分配地址
      ifconfig  
      ping www.baidu.com  //测试

    四、创建物联网平台

    1.注册阿里云飞燕平台

    创建物联网平台,创建服务器,获取公网IP地址,获取三元组。
    MQTT协议代码编写一遍,务必说出三大经典报文(连接,订阅,发布)的详细信息:固定,可变,有效载荷中每个字节的含义,甚至说出每个BIT位含义

  • 打开阿里云飞燕平台
  • 点击管理控制台
  • 新建项目
  • 2.接下来利用阿里提供的物联网平台的SDK(库函数,能连接、发布、订阅),也就是各种库来实现下位机和阿里云的对接

    下载阿里云IOT–SDK连接:https://github.com/maxlicheng/iotkit-embedded.git
    下载源码包:iotkit-embedded-3.0.1.zip,也是可以使用下载好的源码包!
    移植阿里mqtt的SDK到下位机,所谓的移植就是交叉编译SDK代码!
    mkdir /opt/project/ehome_mqtt
    cp iotkit-embedded-3.0.1.zip /opt/project/ehome_mqtt/ 
    cd /opt/project/ehome_mqtt
    unzip iotkit-embedded-3.0.1.zip
    cd iotkit-embedded-3.0.1
    vim tools/board/config.arm-linux.demo 新建一个arm-linux配置文件,针对开发板,给makefile用决定程序如何编译
    添加以下文本内容,注意:-前面必须要空两格:
    CONFIG_ENV_CFLAGS = \
    -D_PLATFORM_IS_LINUX_ \    //传递条件编译,是linux吗
    -Wall \   //把所有警告弄出来
    -DNO_EXECUTABLES   //传递宏

    CONFIG_ENV_LDFLAGS = \
    -lpthread -lrt    //一个线程库,一个跟时间相关的库

    OVERRIDE_CC = arm-cortex_a9-linux-gnueabi-gcc
    OVERRIDE_AR = arm-cortex_a9-linux-gnueabi-ar
    OVERRIDE_LD = arm-cortex_a9-linux-gnueabi-ld

    CONFIG_wrappers :=     //目录,要编译

    保存退出

    确认配置文件
    make reconfig
    选3: 3) config.arm-linux.demo

    无报错,进行编译
    make

    rm -rf wrappers/os/arm-linux
    cp -r wrappers/os/ubuntu/   wrappers/os/arm-linux
    删除HAL_UART_linux.c文件,不用串口,用WIFI网络
    rm wrappers/os/arm-linux/HAL_UART_linux.c

    屏蔽wrappers 选项
    vim tools/board/config.arm-linux.demo

    第15行前面加#注释掉
    # CONFIG_wrappers :=  

    执行配置
    make reconfig
    3

    编译
    make

    编译正常,删除config.arm-linux.demo 里面的 -DNO_EXECUTABLES语句, 即可编译可运行程序
    vim tools/board/config.arm-linux.demo

    文本内容
    注意:-前面必须要空两格,千万别忘记把-Wall选项后面的\也要去掉呦
    CONFIG_ENV_CFLAGS = \
    -D_PLATFORM_IS_LINUX_ \
    -Wall 

    CONFIG_ENV_LDFLAGS = \
    -lpthread -lrt

    OVERRIDE_CC = arm-cortex_a9-linux-gnueabi-gcc
    OVERRIDE_AR = arm-cortex_a9-linux-gnueabi-ar
    OVERRIDE_LD = arm-cortex_a9-linux-gnueabi-ld

    #CONFIG_wrappers :=

    执行配置
    make reconfig
    3

    编译
    make

    vim wrappers/os/arm-linux/HAL_OS_linux.c
    修改三元组(阿里飞燕平台获取)
    make

    查看输出文件,检查编译的可执行文件是否正常
    ls output/release/bin/
    file output/release/bin/*
    mkdir /opt/rootfs/home/appbin/  //此目录将来存放咱们最终的可执行文件
    cp output/release/bin/mqtt_example  /opt/rootfs/home/appbin/   //阿里提供参考代码

    下位机运行mqtt_example即可
    下位机执行:
    提前准备好手机的热点或者家里的路由器
    插入WiFi模块
      insmod /home/drivers/mt7601Usta.ko
      mkdir /var/run
      wpa_supplicant -B -d -Dwext -ira0 -c /etc/wpa_supplicant.conf
      udhcpc -i ra0
      cd /home/appbin
      ./mqtt_example 
      此时开发板每隔1s向阿里云服务器发送hello,只要串口终端有定期打印信息即可

    3.由于MQTT数据传输采用json格式,键值对方式,所以先掌握CJSON的玩法

    key:value,键值对
    例如:
    char *payload = ”
    {
        "params": {
            "temp":25.5,
            "humi":50,
        "bed_room":1  
        },
        "method":   "thing.event.property.post",
        "id":    "15801588497",
    }

    cJSON,C语言中最常用的JSON库,cJSON是C语言中一个JSON一个编解码器。cJSON的优点是非常轻量级,源码的可读性也十分强,可直接提取温度数值
    GitHub的地址是 https://github.com/DaveGamble/cJSON  

    涉及的相关数据结构:通过链表链接起来
    #define cJSON_Number 3
    #define cJSON_String 4
    #define cJSON_Array 5
    #define cJSON_Object 6
     
    typedef struct cJSON {
        struct cJSON *next,*prev;    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
        struct cJSON *child;        /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
     
        int type;                    /* The type of the item, as above. cjson结构的类型上面宏定义的7中之一*/
     
        char *valuestring;            /* The item's string, if type==cJSON_String */
        int valueint;                /* The item's number, if type==cJSON_Number */
        double valuedouble;            /* The item's number, if type==cJSON_Number */
    } cJSON;

    相关操作函数:
    /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
    extern cJSON *cJSON_Parse(const char *value);//从 给定的json字符串中得到cjson对象

    /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
    extern char  *cJSON_Print(cJSON *item);//从cjson对象中获取有格式的json对象
     
    /* Delete a cJSON entity and all subentities. */
    extern void   cJSON_Delete(cJSON *c);//删除cjson对象,释放链表占用的内存空间

    /* Get item "string" from object. Case insensitive. */
    extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);//根据键获取对应的值(cjson对象)
     
    /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
    extern const char *cJSON_GetErrorPtr(void);//获取错误字符串

    具体参见代码:json目录

    root = cJSON_Parse(playload); //帮你解析字符串,root指针指向根

    params = cJSON_GetObjectItem(root,"params"); // 从跟开始找,传爹的名字

    以此打印出值
     

    作者:Yuanyingbian

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 S5P6818在智能家居领域的应用与解析

    发表回复