STM32 S5P6818在智能家居领域的应用与解析
采用 S5P6818作为网关,接收STM32串口发来的协议数据包,再将其转换为mqtt协议数据包。
网关在将数据从传给云平台——这里用阿里飞燕云平台。
为了平衡成本与性能,采用STM32连接温湿度传感器、灯、报警器、电机等,充当终端节点,而为了提高性能采用S5P6818做网关。
一、项目概述
本项目采用STM32搭建终端节点,应用OLED显示屏、电机、灯光、报警器、ds18b20温湿度传感器,通过TCP协议将串口数据传递给S5P6818搭建的服务器端,采用QT进行图形界面的设置,同时连接舵机、报警器等。服务器通过MQTT协议链接阿里云飞燕平台,上传温度、湿度等环境数据。并通过云平台连接手机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——让手机连接热点,依赖于两个库
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 //安装
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 //拷贝默认配置文件
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/
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" #你的密码
}
保存退出
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
127.0.0.1 localhost
保存退出
nameserver 114.114.114.114 //全球公用·DNS
nameserver 8.8.8.8
保存退出
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