基于单片机的远程控制系统

主要内容

自己设计了一个iPhone手机应用,该应用在联网的情况下实现与单片机的远程通信,控制单片机继电器的开或者关。联网是4G网络也可以的,因为单片机终端使用了NB-Iot窄带物联网模块,通过将设备接入阿里云平台来实现通信,而不是简单的在局域网内进行信息传输。

大致方案

该项目大致分为三个部分:iOS手机应用、STM32单片机终端、阿里云平台和云端监听。
iOS手机应用主要负责接入阿里云平台与单片机通信,然后通过简单易懂的UI控件让用户远程控制单片机端的继电器,并且通过单片机返回的继电器状态信息实时更新UI界面,用Swift实现。
单片机终端运行RT-Thread操作系统,通过NB-Iot窄带物联网模块接入阿里云平台,与手机端口进行通信,用C语言实现。
阿里云平台主要实现两手机应用和单片机之间的远程通信,云端监听主要实现的时监测设备的上线和下线以及继电器状态的变化,若发生变化,推送通给给iOS应用。

iOS应用

本app基于iOS平台,使用swift语言编写。主要功能即推送单片机设备的上下线和继电器开关的通知,以及应用中实现设备状态的显示和手动远程控制单片机继电器的开关。由于单片机端使用NB-Iot技术,不需要依靠Wi-Fi,所以该远程控制系统不需要在局域网内使用,而是任何地方都可以远程控制。同时,本app支持额外增加了NFC功能,通过扫描单片机设备上的NFC贴片可以获取相应的STM32设备的信息,当然,该NFC功能同时支持写入和读取数据,支持iPhone XR及以上的机型。
首先,该应用需要接入阿里云平台,然后进行与单片机的远程通信。所以此处用到了阿里云给出的iOS框架IotLinkKit,目前更新到了1.2.1,该SDK包含初始化、去初始化、数据上下行以及订阅/取消订阅等内容。
其次,iOS端接入阿里云平台之后需要先确认单片机设备端是否上线,如果上线则确立之间的连接,可以发送指令;如果单片机设备端没有上线,那么等待其上线,无法控制。若确立了连接,则app中远程发送指令的控件呈可用状态,用户可以点击相应的的控件来发送相应的远程指令控制继电器的开关。
这些iOS框架均由使用Cocoapods管理。然后,若app在未运行状态时,若单片机设备端上下线或者继电器开关状态发生了变化,需要推送通知到iOS应用,此时需要用到阿里云框架AlicloudPush,目前更新版本为1.9.9,此版本也更新了iOS13新系统无法正确获取DeviceToken的问题,非常及时。注册推送流程如下:app运行后,使用方法来注册iPhone的远程信息推送,当调用该方法成功获取到设备标识之后,使用CloudPushSDK.registerDevice(deviceToken)方法上传到CloudPush服务器,至此推送注册功能完成,推送功能由云端监听并且推送。

STM32单片机

该STM32F407单片机代码总体来说不算复杂,如灯的闪烁速度可以用rt_thread_mdelay时间的多少来控制,继电器开关用电平高低控制,设备继电器属性的上报可以用串口发送特定信息来实现,当然,这些任务都需要多线程来实现,否则需要用状态机思想实现较为复杂。
该代码中较为复杂的是json数据的封装发送、NB-Iot串口收发数据的逻辑处理以及接入阿里云时各种情况以的处理。
首先,单片机C语言处理json即相当于处理字符串,没有封装,这与Java或是swift不同。Json数据与字典类型很相似,而上报的json数据中有很多键值的数据类型会是String类型,而且在C语言中对这些键值很多都需要加上前后两个双引号,所以若是用C语言上报Json数据,多处要用到转义字符。且接收到的json字符串只能当字符串处理,要取出字典中的值需要算出特定的下标数字,再取值。
然后,由于NB-Iot的串口有两种工作模式,一种是未接入和正在接入阿里云时,还有一种是已经接入阿里云平台时。当设备未接入或正在接入阿里云时,需要接收连接指令,以便一步步的接入阿里云,然后在已经接入了阿里云平台时,需要时时监听远程传来的指令来控制继电器状态和传回设备状态。在本代码中,由于连接程序时一个线程,可以通过该线程是否为空值来确定是否已经接入。若为空,则表明已经接入,此时我们再进一步来判断该数据的字符串前缀中包含的内容是否为控制继电器开关的控制指令,若是,则判断value键对应的值是1还是0,来判断是开启设备还是关闭设备;若索引接入平台的线程非空,则表明正在接入物联网,此时需要接收数据,然后把数据传给连接的线程来处理。另外,由于串口是一个字符一个字符的传入的,本程序中每一段数据都以\r\n为分隔,若接收到的不是\r\n,则存入字符数组中继续接收,知道接收到了\r\n后,才开始执行以上的判断操作。
最后,是设备接入阿里云的步骤以及情况分析。由于接入阿里云需要多个AT指令的发送,没发送一个指令都需要等待NB-Iot模块的回应,根据它的回应来作出下一步的操作。首先,用而为数据本地存储每一个步骤的相应的字符串指令,等待发送。本程序串口发送时均由信号量锁住,因为多线程任务串口发送可能会出现打断、串口干扰的情况发生。发送的字符串2~4分别为检查网络、检查信号、配置连接信息,均需要等待回应OK,所以可以写在同一句代码上;随后发送字符串5发送连接的地址以及端口号,等待回应QMTOPEN: 0,0;接下来发送字符串6准备连接,等待回应QMTCONN: 0,0,0,此时表明已经接入了阿里云平台;接下去需要发送字符串7~8,分别订阅设备属性和普通消息,均等待回应QMTSUB: 0,1,0,1表明订阅成功,至此,阿里云平台的连接工作完毕。

云端监听

该软件使用Java编写,代码使用eclipse软件编写以及测试。由于需要实现STM32单片机设备端上下线以及继电器开关状态的推送通知,所以首先使用阿里云提供云端订阅Java SDK框架,用来监听设备上下线以及继电器开关状态,监听到属性变化后,再使用阿里云提供的OpenAPI2.0框架中的advancedPush及pushMessageToIOS方法对iOS终端推送相应的消息通知。
这两个Java框架均可由Apache Maven软件管理添加。当然,使用该平台提供监听和推送通知时需要对应账号的AccessKeyId和accessSecret才能权限监听和推送该账号下开启的设备。
最后,由于该代码的监听以及推送功能需要一直执行,而在自己的计算机做不到常开,所以需要用exlipse导出一个可执行的jar包,然后挂在阿里云的服务器上执行。阿里云服务器需要自己花钱购买,不过对于我们学生来说有学生优惠,所以价格还是很感人的。有了阿里云服务器之后(这一带地区基本为上海阿里云服务器),需要在macOS的terminal终端使用ssh协议登录控制服务器,然后使用nohup java -jar指令执行jar包,输出的内容会重定向到同目录的nohup 文件,一天24小时执行,效率非常高,只是偶尔会有推送延迟。

内容展示

另本人才疏学浅,若有任何不严谨或者错误的地方,欢迎指正:Scotteland@163.com

Author: Jcwang

Permalink: http://example.com/2020/05/07/%E5%9F%BA%E4%BA%8E%E5%8D%95%E7%89%87%E6%9C%BA%E7%9A%84%E8%BF%9C%E7%A8%8B%E6%8E%A7%E5%88%B6%E7%B3%BB%E7%BB%9F/