Kiiato

导航

考研复试项目回顾——智能积木开发(硬件开发方面)

 首先是单片机程序方面,由于使用了淘宝上买的开发板,上面已经集成了一些基础模块,也附赠了它们的驱动程序。因此我的工作主要是:

  1)设计好整个硬件电路的功能,规划好主逻辑(裸机)

  2)根据项目需求,选择外接模块,并为各个模块写驱动程序(蓝牙,ESP8266,自制传感器阵列)

ESP8266+MQTT

  简单来说,在我的项目中,ESP8266可以理解为,为一个mcu设备添加了一个网卡,使用WiFi进行通信,支持完整的tcp/ip协议栈。

       为了能够正常的使用这个模块与阿里云平台使用mqtt协议进行通信,我需要实现两组功能:

    1)实现ESP8266通过串口与mcu通信,实现ESP8266连接到环境内的WiFi上

    2)将mcu中存储的游戏数据封装成mqtt数据报,实现与阿里云平台的通信。

  我用了两个c文件完成上面的功能,为了方便,暂且称为wifi.c和mqtt.c

     WiFi.c

  这其中我设计了以下内容(宏定义很少,已省略)

    1)模块初始化函数:选择了一个空闲IO口,将其设置成匹配的输出模式。

    2)模块复位函数:根据芯片手册的时序图,控制IO口进行模块复位

    3)发送AT指令函数:选择串口2进行通信。计数器清零,缓冲区清空,发送指令,成功或者超时,返回结果。

    4)接入wifi函数:特殊AT指令函数。因为接入无线网需要特定的网络名称和密码,所以这个指令的实现也要单独拿出来。

    5)连接服务器函数:特殊的AT指令函数,由于mqtt是基于tcp的应用层协议,因此该函数试图让mcu访问目的服务器的域名地址,端口以建立tcp连接,各种连接错误对应不同的错误返回值,若连接成功,则发送一般指令,进入透传模式(只发送数据,不会有任何的修改)

    6)封装函数:根据AT指令手册,将mcu连接阿里云物联网平台的过程封装到一个函数内以便减少主函数代码量。

 

  MQTT.c

  mqtt协议的中文官方网址为:http://mqtt.p2hp.com/mqtt311

  先回顾一下我对MQTT的理解,只有理解了MQTT协议,才能写出合格的代码。

    1)什么是MQTT协议? ——MQTT协议是一个轻量级的发布/订阅信息传输协议。用户A发布了一个topic及其Qos,其他用户订阅了这个topic后,只要用户A发布消息,订阅者们就会收到该消息。

    2)为什么要用MQTT协议?要在什么场景下使用它?——这应该是比较难解释的一个点了。

      先说一下成品中数据的流通方向:传感器阵列  -> mcu  -> 阿里云物联网平台  -> 微信小程序  -> 阿里云服务器(模型部署所在)  -> 微信小程序

      在pc端跑模型的时候,我用的是mcu+bluetooth,这是因为我是在一个实验室里做的,距离很近。但成品中,使用硬件的老年人/小孩与使用手机的家长未必在一个很近的距离,因此无论是这个因素,还是数据量的大小而言,mqtt都是一个合适的选择。客户端包括:mcu,微信小程序。它们各自只与平台通信。

    3)怎么使用MQTT协议?——我是mcu端的开发者,因此我所关心的事情包括:连接云平台,订阅目标主题,处理接收报头,心跳请求,如果收到startFlag就发布Qos为0的数据报(压力,时间数据)。这些通过14个基本控制报文中的一些就可以实现。

 

  这其中我设计了以下内容:

    1)首先我要设计合适的数据结构,管理发送/接收缓冲区。缓冲区由[8][512]的二维数组构成,定义三个数组指针用于管理,分别指向数据的存放位置,读取位置和缓冲区的结束位置。每次执行后续操作。存放/读取指针会相应的变化。如果到底了,将buffer入栈,指针回到起点。

    2)初始化函数:初始化缓冲区,初始化产品ID,设备名,密钥,订阅/发布的主题等(密钥用了阿里开源库的哈希加密算法)

    后面的代码都涉及了上述功能的实现,因此要对MQTT3.1.1协议报文有一个基本的了解

    首先,MQTT数据报是基于TCP的应用层数据报,它包括三个部分:固定报头,可变报头和负载。

        固定报头:是所有MQTT报文都必须有的部分,它由2个byte组成。

 

                            byte1的高4bit代表MQTT数据报的报文类型,低4bit根据每个不同类型的报文各有差别,byte2代表报文的剩余长度。

        报文类型如下,这是我们填充byte1高4bit的重要依据。

        

        byte1低4bit为报文标识位,只有符合表中所示,才表示报文可用,否则连接关闭。

    byte2的数据代表接下来的数据还有多长(不带他自己这个字节),他一共可以用4个字节,最高位是标志位(后面一整个字节必都是0,本字节最高位也必是0),用循环取余/取整/位运算就可以实现。

      可变报头:每种报文的可变报头都不太一样,根据手册撸代码就行。

 

            3)connect函数:填充固定报头,计算剩余长度,填充可变报头(参考手册),填充负载(ID,产品号,密钥),加入发送缓冲区

            4)subcribet函数:填充固定报头,计算剩余长度,填充可变报头(参考手册),填充负载(topic,QoS),加入发送缓冲区

            5)ringreq函数:类似

    6)publish函数:只发布QoS0的推送,类似,多一个将数据指针以及数据长度当作参数输入

    7)pubHandle函数:处理收到的推送函数,这个是最麻烦的,与微信小程序开发人员协定好:收到负载为0xFF表示开始游戏。

      逻辑:接收所有推送,依次判断其类型进入相应操作,当收到QoS0的public,进一步判断其负载量,若为0xFF,返回对应值,交给主函数处理。

 

    主函数逻辑就不说了。

 

    

       

posted on 2022-03-22 17:01  Kiiato  阅读(79)  评论(0编辑  收藏  举报