当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]本文基于TOS的AT框架,实现了一个基于MX+开发板的demo,用于控制之前搭的智能小车。

本节基于TOS的AT框架,我实现了一个基于MX+开发板的demo,用于控制之前搭的智能小车,效果如下,详细源码及实验例程请参考文末码云仓库链接:

动手智能小车记(5)-坦克底盘硬件模块大杂烩

1、什么是AT指令?

在嵌入式开发过程中,我们有时候要使用一些通信模组,比如蓝牙、WIFI、4G、NBIOT等等,这些模组内部固件已经将协议栈封装好了,然后模组硬件向外部提供了标准的串口,这样通过与模组的串口相连接,就可以与模组进行通信;一般情况下,厂商都会提供模组的使用手册,只要照着流程去操作模组就可以正常通信了,如下图所示,这是一个MCU、蓝牙模组、手机之间的通信案例:

2、为什么要有AT框架?

一般情况下,在一些物联网产品的项目上可能这样的需求,比如:

常规的一些传感器设备,需要监测环境温度、湿度等等这样的情况:

  • 实现数据上传

共享单车、智能门锁

  • 实现开锁的逻辑

等等。。。

这些需求看起来就非常简单,比如我就用ESP8266+一个后台服务器来实现这样的需求吧,只要后台提供好API接口,那么这类简单的需求分分钟搞定,完全没有任何难度,在应用程序上编写好模组的驱动接口和通信逻辑就可以了。

但是,如果换一个呢??再换一个呢?有可能实现同样的需求,我们还要去实现不一样的驱动流程,这是不是显得很麻烦?基于这样的问题诞生,于是各个厂商分别提出了对应的AT框架思维,那么这种AT框架思维具体是什么样的呢?以驱动ESP8266为例,一般有以下几种模式:

  • AP模式
  • STA模式
  • AP+STA模式

以STA模式为例,最后要和云端服务器进行对接,我们首先要完成初始化流程,一般要发以下几个指令:

  • AT+RESTORE\r\n 模组复位

  • ATE0\r\n 关闭回显

  • AT+CWMODE=1\r\n 设置多连接

  • AT+CIPMODE=0\r\n 关闭透传模式

  • AT+CIPMUX=1\r\n 开始多连接模式

  • AT+CWJAP="TOS","12345678"\r\n 连接热点

这样就基本完成了模组的初始化流程,初始化完毕以后,就可以进入数据传输的了,连接服务器,然后开启透传模式,进入透传模式,然后就可以把数据直接传送到后台了,此时还可以读取后台的消息,当我们不需要需要模组的时候,还可以将模组掉电;所以,我们可以在这个基础上把这个驱动流程框架化,即是拥有初始化、连接服务器、发送、接收、关闭等等这些接口。

3、TencetOS tiny AT框架

在TencentOS tiny中,内部就集成了一套简单易用的AT框架,哪怕是不一样的指令,我们也只需要填充对应的方法,然后注册到框架上,就可以顺利与模组进行通信了,以下是TencentOS tiny AT框架的基本组成图:

上图来源于汪兄讲解的PPT

对于应用开发者来说,我们最关注的是SAL interface、也就是网络适配框架,只要模组注网成功,那么在这一层,我们不需要具体去关注模组到底是怎么用AT指令去通信的,我们只需要调用SAL interface的socket、connect、send、recv、close等等接口完成我们与后台的通信或者与别的通信方式的逻辑即可,但是调用SAL接口口还需要去与各个模组进行适配。

typedef struct sal_module_st {
    int (*init)(void);

    int (*get_local_mac)(char *mac);

    int (*get_local_ip)(char *ip, char *gw, char *mask);

    int (*parse_domain)(const char *host_name, char *host_ip, size_t host_ip_len);

    int (*connect)(const char *ip, const char *port, sal_proto_t proto);

    int (*send)(int sock, const void *buf, size_t len);

    int (*recv_timeout)(int sock, void *buf, size_t len, uint32_t timeout);

    int (*recv)(int sock, void *buf, size_t len);

    int (*sendto)(int sock, char *ip, char *port, const void *buf, size_t len);

    int (*recvfrom)(int sock, void *buf, size_t len);

    int (*recvfrom_timeout)(int sock, void *buf, size_t len, uint32_t timeout);

    int (*close)(int sock);
} sal_module_t;

对于怎么去绑定(适配)模组和SAL interface,在此之前那我们还需要完成AT framework与HAL(uart)的适配,然后提供SAL interface需要的接口,注册上去,这样我们就可以在SAL上愉快的进行操作了,接下来AT框架具体是怎么解析每个AT指令我们就不需要特别去关心了,感兴趣的可以去研究一下tos_at.c、tos_at.h这两个文件。

在TencentOS tiny SDK中,腾讯官方已经提供了一些热门模组的操作例程,比如esp8266,它是怎么与SAL interface完成适配的呢?如下:

上图来源于戴兄讲解的PPT


这样的话,我们就可以调用TOS提供的SAL接口进行通信了,如下,在sal_module_wrapper.h中查看,详细实现在sal_module_wrapper.c:

/**
 * @brief Convert domain to ip address.
 *
 * @attention None
 *
 * @param[in]   host_name   domain name of the host
 * @param[out]  host_ip     ip address of the host
 * @param[out]  host_ip_len ip address buffer length
 *
 * @return  errcode
 */
int tos_sal_module_parse_domain(const char *host_name, char *host_ip, size_t host_ip_len);

/**
 * @brief Connect to remote host.
 *
 * @attention None
 *
 * @param[in]   ip      ip address of the remote host
 * @param[in]   port    port number of the remote host
 * @param[in]   proto   protocol of the connection(TCP/UDP)
 *
 * @return  socket id if succuss, -1 if failed.
 */
int tos_sal_module_connect(const char *ip, const char *port, sal_proto_t proto);

/**
 * @brief Send data to the remote host(TCP).
 *
 * @attention None
 *
 * @param[in]   sock    socket id
 * @param[in]   buf     data to send
 * @param[in]   len     data length
 *
 * @return  data length sent
 */
int tos_sal_module_send(int sock, const void *buf, size_t len);

/**
 * @brief Receive data from the remote host(TCP).
 *
 * @attention None
 *
 * @param[in]   sock    socket id
 * @param[in]   buf     data buffer to hold the data received
 * @param[in]   len     data buffer length
 *
 * @return  data length received
 */
int tos_sal_module_recv(int sock, void *buf, size_t len);

/**
 * @brief Receive data from the remote host(TCP).
 *
 * @attention None
 *
 * @param[in]   sock    socket id
 * @param[in]   buf     data buffer to hold the data received
 * @param[in]   len     data buffer length
 * @param[in]   timeout timeout
 *
 * @return  data length received
 */
int tos_sal_module_recv_timeout(int sock, void *buf, size_t len, uint32_t timeout);

/**
 * @brief Send data to the remote host(UDP).
 *
 * @attention None
 *
 * @param[in]   sock    socket id
 * @param[in]   ip      ip address of the remote host
 * @param[in]   port    port number of the remote host
 * @param[in]   buf     data to send
 * @param[in]   len     data length
 *
 * @return  data length sent
 */
int tos_sal_module_sendto(int sock, char *ip, char *port, const void *buf, size_t len);

/**
 * @brief Receive data from the remote host(UDP).
 *
 * @attention None
 *
 * @param[in]   sock    socket id
 * @param[in]   buf     data buffer to hold the data received
 * @param[in]   len     data buffer length
 *
 * @return  data length received
 */
int tos_sal_module_recvfrom(int sock, void *buf, size_t len);

/**
 * @brief Receive data from the remote host(UDP).
 *
 * @attention None
 *
 * @param[in]   sock    socket id
 * @param[in]   buf     data buffer to hold the data received
 * @param[in]   len     data buffer length
 * @param[in]   timeout timeout
 *
 * @return  data length received
 */
int tos_sal_module_recvfrom_timeout(int sock, void *buf, size_t len, uint32_t timeout);

/**
 * @brief Close the connection.
 *
 * @attention None
 *
 * @param[in]   sock    socket id
 *
 * @return  errcode
 */
int tos_sal_module_close(int sock);

但是你以为这就完了吗?为了和Posix API无差异化调用,TencentOS tiny官方开发人员开发了一套近似于通用网络操作接口,就类似操作一个文件一样open、read、write、close,这不就更简单了嘛?我们来一睹为快:

tos_at_socket.h

#ifndef  _TOS_AT_SOCKET_H_
#define  _TOS_AT_SOCKET_H_

#include "tos_at_socket_lib.h"
#include "tos_at_socket_types.h"

#define AF_INET             0

#define AF_INET6            1

#define AF_UNIX             2

/* Provides sequenced, reliable, bidirectional, connection-mode byte streams, and may provide a transmission mechanism for out-of-band data. */
#define SOCK_STREAM         0

/* Provides datagrams, which are connectionless-mode, unreliable messages of fixed maximum length. */
#define SOCK_DGRAM          1

/* Peeks at an incoming message. The data is treated as unread and the next recv() or similar function shall still return this data. */
#define MSG_PEEK            0x01

/* Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific. */
#define MSG_OOB             0x02

/* On SOCK_STREAM sockets this requests that the function block until the full amount of data can be returned. The function may return the smaller amount of data if the socket is a message-based socket, if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket. */
#define MSG_WAITALL         0x04

int socket(int domain, int type, int protocol);

int connect(int socket, const struct sockaddr *address, socklen_t address_len);

int recv(int socket, void *buffer, size_t length, int flags);

int recvfrom(int socket, void * buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len);

int send(int socket, const void *buffer, size_t length, int flags);

int sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);

int shutdown(int socket, int how);

int read(int socket, void *buffer, size_t length);

int close(int socket);

int write(int socket, const void *buffer, size_t length);

#endif /* _TOS_AT_SOCKET_H_ */

只要注册框架等流程完成以后,模组注网成功,后面就可以直接这样常规操作了:

void network_demo(void)
{
    int recv_len = -1;
    int fd, rc, cnt = 0;

    struct sockaddr_in addr;

    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    addr.sin_port = htons(SERVER_PORT);

    fd = socket(AF_INET, SOCK_STREAM, 0);

    if (fd < 0)
    {
        printf("socket failed\n");
        return;
    }

    rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));

    if (rc < 0)
    {
        printf("connect failed\n");
        close(fd);
        return;
    }
 
  while(1)
  {
   //调用send发送数据
   //调用recv接收并处理数据
  }
 
  close(fd);
}

基于TencentOS tiny AT框架的基础上,我编写了一个基于MX+开发板的控制小车例程,源码已更新到码云个人仓库。

个人码云仓库地址:

https://gitee.com/morixinguan

我还将之前做的一些项目以及练习例程在近期内全部上传完毕,与大家一起分享交流:

全文参考资料

腾讯物联网终端操作系统SDK文档.pdf

腾讯物联网终端操作系统开发指南.pdf

TencentOS tiny技术讲解与开发实践PPT.pdf

云加社区沙龙(腾讯物联网操作系统TencentOS tiny架构解析与实践).pdf

公众号粉丝福利时刻

这里我给大家申请到了福利,本公众号读者购买小熊派开发板可享受9折优惠,有需要购买小熊派以及腾讯物联网开发板的朋友,淘宝搜索即可,跟客服说你是公众号:嵌入式云IOT技术圈 的粉丝,立享9折优惠!

往期精彩

TencentOS tiny RTOS快速入门

网红腾讯物联网开发板终极开箱评测,让我们一睹为快!

Linux进程间通信(中)之信号、信号量实践

Linux进程间通信(下)之共享内存实践

STM32硬核DIY机械键盘|蓝牙USB双模|灯控

觉得本次分享的文章对您有帮助,随手点[在看]并转发分享,也是对我的支持。

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭