rt-thread的at组件在freeRTOS上的移植与应用

2023-05-16

目录

一、AT命令

二、rtthread at组件简介

三、移植到freeRTOS

3.1、数据结构

3.2、API

3.3、at client 流程

3.4、串口数据接收处理

3.5、数据缓存 --- 顺序队列

四、使用示例

4.1、串口配置信息解析

4.2、IP和MAC地址解析

五、最后


一、AT命令

AT 命令集是一种应用于 AT 服务器(AT Server)与 AT 客户端(AT Client)间的设备连接与数据通信的方式。其基本结构如下图所示:

  1. 一般 AT 命令由三个部分组成,分别是:前缀、主体和结束符。其中前缀由字符 AT 构成;主体由命令、参数和可能用到的数据组成;结束符一般为  ("\r\n")
  2. AT Server 向 AT Client 发送的数据分成两种:响应数据和 URC 数据
  • 响应数据: AT Client 发送命令之后收到的 AT Server 响应状态和信息
  • URC 数据: AT Server 主动发送给 AT Client 的数据,一般出现在一些特殊的情况,比如 WIFI 连接断开、TCP 接收数据等,这些情况往往需要用户做出相应操作

    二、rtthread at组件简介

    RT-Thread系统的AT 组件是 AT Server 和 AT Client 的实现,组件完成 AT 命令的发送、命令格式及参数判断、命令的响应、响应数据的接收、响应数据的解析、URC 数据处理等整个 AT 命令数据交互流程。

    通过 AT 组件,设备可以作为 AT Client 使用串口连接其他设备发送并接收解析数据,可以作为 AT Server 让其他设备甚至电脑端连接完成发送数据的响应,也可以在本地 shell 启动 CLI 模式使设备同时支持 AT Server 和 AT Client 功能,该模式多用于设备开发调试。

    AT 组件资源占用

    • AT Client 功能:4.6K ROM 和2.0K RAM;

    • AT Server 功能:4.0K ROM 和2.5K RAM;

    • AT CLI 功能:1.5K ROM ,几乎没有使用RAM

三、移植到freeRTOS

项目中只用到的at client的功能,所以这里也只移植了client部分。移植分为两块,一块是将at client中使用的线程创建、信号量创建收发等rtthread系统API替换成freeRTOS的,这部分比较简单;另一块是串口数据收发部分,rtthread是基于自带的UART设备驱动框架来做的,并带有数据缓存功能,移植过来需要将其剥离,然后实现串口数据的发送、接收及接收数据的缓存功能。移植后

  • 串口数据发送是采用的轮询发送模式
  • 串口数据接收使用的是DMA方式
  • 接收数据缓存使用的是顺序队列

在移植前先来了解下at client的设计思路,有哪些数据结构以及提供了哪些API,注意这些数据结构跟API是移植调整过后的,跟原有的相差不大

3.1、数据结构

at_response 结构体用于响应数据的接收,at_urc_table 结构体是urc数据注册表,at_client 结构体是at client控制句柄

struct at_response
{
    /* response buffer */
    char *buf;
    /* the maximum response buffer size, it set by `at_create_resp()` function */
    uint16_t buf_size;
    /* the length of current response buffer */
    uint16_t buf_len;
    /* the number of setting response lines, it set by `at_create_resp()` function
     * == 0: the response data will auto return when received 'OK' or 'ERROR'
     * != 0: the response data will return when received setting lines number data */
    uint16_t line_num;
    /* the count of received response lines */
    uint16_t line_counts;
    /* the maximum response time */
    uint32_t timeout;
};
typedef struct at_response *at_response_t;

struct at_client;

/* URC(Unsolicited Result Code) object, such as: 'RING', 'READY' request by AT server */
struct at_urc
{
    const char *cmd_prefix;
    const char *cmd_suffix;
    void (*func)(struct at_client *client, const char *data, uint16_t size);
};
typedef struct at_urc *at_urc_t;

struct at_urc_table
{
    size_t urc_size;
    const struct at_urc *urc;
};
typedef struct at_urc *at_urc_table_t;

struct at_client
{    
    at_status_t status;
    char end_sign;

    /* the current received one line data buffer */
    char *recv_line_buf;
    /* The length of the currently received one line data */
    uint16_t recv_line_len;
    /* The maximum supported receive one line data length */
    uint16_t recv_line_size;
    xSemaphoreHandle rx_notice;
    xSemaphoreHandle lock;

    at_response_t resp;
    xSemaphoreHandle resp_notice;
    at_resp_status_t resp_status;

    struct at_urc_table *urc_table;
    uint16_t urc_table_size;

    /* uart receive queue */
    struct array_queue *recv_q;
    /* The maximum supported receive data length */
    uint16_t recv_queue_size;

    /* uart receive uart */
    UART_INDEX_E uart_index;

    /* handle task */
    TaskHandle_t parser;
};
typedef struct at_client *at_client_t;

3.2、API

/* get AT client object */
at_client_t at_client_get_first(void);
/* AT client initialize and start*/
at_client_t at_client_init(UART_INDEX_E uart_index, uint16_t recv_line_size, uint16_t recv_queue_size);


/* AT client send or receive data */
int at_client_obj_send(at_client_t client, char *buf, int size);
int at_client_obj_recv(at_client_t client, char *buf, int size, uint32_t timeout);
/* AT client send commands to AT server and waiter response */
int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr, ...);


/* set AT client a line end sign */
void at_obj_set_end_sign(at_client_t client, char ch);
/* Set URC(Unsolicited Result Code) table */
int at_obj_set_urc_table(at_client_t client, const struct at_urc * table, int size);


/* AT response object create and delete */
at_response_t at_create_resp(uint16_t buf_size, uint16_t line_num, uint32_t timeout);
void at_delete_resp(at_response_t resp);
at_response_t at_resp_set_info(at_response_t resp, int buf_size, int line_num, uint32_t timeout);


/* AT response line buffer get and parse response buffer arguments */
//获取指定行号的响应数据
const char *at_resp_get_line(at_response_t resp, int resp_line);
//根据关键字获取响应数据
const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword);
//根据resp_expr格式使用标准sscanf 解析语法,解析指定行的响应数据

int at_resp_parse_line_args(at_response_t resp, int resp_line, const char *resp_expr, ...);
//根据resp_expr格式使用标准sscanf 解析语法,解析指定关键字的响应数据
int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...);

3.3、at client 流程

用户线程中调用 at_client_init API时会自动创建 parser 线程,parser线程内部实现了 响应数据的接收、响应数据的解析、URC 数据处理等整个AT 命令数据交互流程。

发送数据时的数据流向为:用户线程调用 at_exec_cmd 发送数据 ---> 串口 ---> at server

接收数据时的数据流向为:at server ---> 串口接收,然后发送 rx_notice 信号量 ---> parser线程解析,然后发送 resp_notice 信号量

3.4、串口数据接收处理

 在创建at client处理线程时,需要注册好串口数据接收回调函数,这样当串口接收到数据时,就会调用该回调函数,在该回调函数中,会将接收到的数据存入队列中,然后发送信号量通知at client处理线程进行处理

串口驱动:

typedef enum
{
    UART1_INDEX,
    UART2_INDEX,
    UART3_INDEX,

    UART_INDEX_ALL
    
}UART_INDEX_E;

/* stm32 uart dirver class */
struct stm32_uart
{
    const char *name;
    USART_TypeDef *Instance;
    IRQn_Type irq_type;

    int (*rx_ind)(UART_INDEX_E uart_index, char *recv_data, int recv_len);
};
extern struct stm32_uart stm32_uart_handle[UART_INDEX_ALL];

extern void set_uart_rx_indicate(UART_INDEX_E uart_index, int (*set_rx_ind)(UART_INDEX_E uart_index, char *recv_data, int recv_len));
extern void uart_send_data_by_index(UART_INDEX_E index, unsigned char *data, unsigned short len);

串口接收中断:

void USART3_IRQHandler( void )
{
    uint8_t tmp;
    uint16_t rxLen = 0;
    
    if(LL_USART_IsActiveFlag_IDLE(USART3))
    {
        rxLen = sizeof(uart3_dam_rxbuf) - LL_DMA_GetDataLength(DMA1, LL_DMA_STREAM_1);
        if(stm32_uart_handle[UART3_INDEX].rx_ind)
        {
            //调用了注册的数据接收回调函数
            stm32_uart_handle[UART3_INDEX].rx_ind(UART3_INDEX, uart3_dam_rxbuf, rxLen);
        }
        
	LL_USART_ClearFlag_IDLE(USART3);

        LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_1);
        LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, sizeof(uart3_dam_rxbuf));
        //将 EN 位置“1”以启动新传输之前,DMA_LISR 或 DMA_HISR 寄存器中与数据流相对应的事件标志必须清零。
        LL_DMA_ClearFlag_TE1(DMA1);
        LL_DMA_ClearFlag_FE1(DMA1);
        LL_DMA_ClearFlag_TC1(DMA1);
        LL_DMA_ClearFlag_HT1(DMA1);
        LL_DMA_EnableStream (DMA1, LL_DMA_STREAM_1);
    }

    ...
}

at client处理线程注册的接收回调函数

static int at_client_rx_indicate(UART_INDEX_E uart_index, char *recv_data, int recv_len)
{
    int idx = 0, i = 0, res;
    BaseType_t xHigherPriorityTaskWoken;
    
    for (idx = 0; idx < AT_CLIENT_NUM_MAX; idx++)
    {
        if (at_client_table[idx].uart_index == uart_index && at_client_table[idx].status == AT_STATUS_INITIALIZED)
        {
            for(i=0; i<recv_len; i++)
            {
                if((res = array_queue_enqueue(at_client_table[idx].recv_q, &recv_data[i])) != 0)
                    break;
            }
            xSemaphoreGiveFromISR(at_client_table[idx].rx_notice, &xHigherPriorityTaskWoken);
        }
    }

    return recv_len;
}

3.5、数据缓存 --- 顺序队列

队列跟栈类似都是“操作受限”的线性表,只不过队列是先进先出结构,队列也有两个基本的操作:入队 enqueue(),放一个数据到队列尾部;出队 dequeue(),从队列头部取一个元素。根据实现方式不同,也可以分为两种:使用数组来实现的顺序队列,和使用链表来实现的链式队列。

队列需要两个指针:一个是 head 指针,指向队头;一个是 tail 指针,指向队尾;

用size来表示队列的总大小,num来记录队列的当前元素个数,则可以这样判断:队列满时:num = size,队列空时:num = 0

#define ARRAY_QUEUE_MALLOC(size)   pvPortMalloc(size)
#define ARRAY_QUEUE_CALLOC(n,size) pvPortMalloc(n*size)
#define ARRAY_QUEUE_FREE(p)        vPortFree(p)

#define ARRAY_QUEUE_SIZE(pqueue)     (pqueue->size)
#define ARRAY_QUEUE_NUM(pqueue)      (pqueue->num)
#define ARRAY_QUEUE_IS_EMPTY(pqueue) (pqueue->num == 0)
#define ARRAY_QUEUE_IS_FULL(pqueue)  (pqueue->num == pqueue->size)

struct array_queue
{
    int size; /* queue total size */
    int num;  /* queue used size rang:1-(size-1) */
    int head; /* points to the the next dequeue data  */
    int tail; /* points to the the next enqueue data  */
    int tpsz; /* data type size */
    void *p;  /* queue space */
};

extern struct array_queue* array_queue_creat(int size, int tpsz);
extern int array_queue_init   (struct array_queue *queue, int size, int tpsz);
extern int array_queue_empty  (struct array_queue *queue);
extern int array_queue_clear  (struct array_queue *queue);
extern int array_queue_destory(struct array_queue *queue);
extern int array_queue_enqueue(struct array_queue *queue, void *in_data);
extern int array_queue_dequeue(struct array_queue *queue, void *out_data);

四、使用示例

4.1、串口配置信息解析

客户端发生的数据:

AT+UART?

客户端获取的响应数据:

UART=115200,8,1,0,0\r\n
OK\r\n

解析伪代码如下:

/* 创建服务器响应结构体,64 为用户自定义接收数据最大长度 */
resp = at_create_resp(64, 0, rt_tick_from_millisecond(5000));

/* 发送数据到服务器,并接收响应数据存放在 resp 结构体中 */
at_exec_cmd(resp, "AT+UART?");

/* 解析获取串口配置信息,1 表示解析响应数据第一行,'%*[^=]'表示忽略等号之前的数据 */
at_resp_parse_line_args(resp, 1,"%*[^=]=%d,%d,%d,%d,%d", &baudrate, &databits, &stopbits, &parity, &control);
printf("baudrate=%d, databits=%d, stopbits=%d, parity=%d, control=%d\n",
        baudrate, databits, stopbits, parity, control);

/* 删除服务器响应结构体 */
at_delete_resp(resp);

4.2、IP和MAC地址解析

客户端发送的数据:

AT+IPMAC?

服务器获取的响应数据:

IP=192.168.1.10\r\n
MAC=12:34:56:78:9a:bc\r\n
OK\r\n

解析伪代码如下:

/* 创建服务器响应结构体,128 为用户自定义接收数据最大长度 */
resp = at_create_resp(128, 0, rt_tick_from_millisecond(5000));

at_exec_cmd(resp, "AT+IPMAC?");

/* 自定义解析表达式,解析当前行号数据中的信息 */
at_resp_parse_line_args(resp, 1,"IP=%s", ip);
at_resp_parse_line_args(resp, 2,"MAC=%s", mac);
printf("IP=%s, MAC=%s\n", ip, mac);

at_delete_resp(resp);

解析数据的关键在于解析表达式的正确定义,因为对于 AT 设备的响应数据,不同设备厂家不同命令的响应数据格式不唯一,所以只能提供自定义解析表达式的形式获取需要信息,at_resp_parse_line_args 解析参数函数的设计基于 sscanf 数据解析方式,使用之前需要先了解基本的解析语法,再结合响应数据设计合适的解析语法。如果不需要解析具体参数,可以直接使用 at_resp_get_line 函数获取一行的具体数据。

五、最后

相关源码修改可从这里下载

rtthread的at组件在freeRTOS上的移植修改代码

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

rt-thread的at组件在freeRTOS上的移植与应用 的相关文章

  • 写字机器人使用教程

    一次制作写字机器人的过程 xff08 含制作教程 xff09 arduino 写字机器人制作教程 写字机器人制作教程2 0 购买链接 资料下载地址 xff1a 智宇科技 写字机器人 光盘资料 xff08 A盘资料 xff09 解压密码 xf
  • Inter RealSenseT265测试总结

    1 光线对定位有影响 xff0c 在一定范围内 xff0c 光线越充足 xff0c 定位精度越高 xff0c 但是当光线达到一定条件之后 xff0c 光照强度就不再跟定位精度成正比了 xff1b 2 周围环境对定位有影响 xff0c 周围的
  • 论文小技巧

    文件 选项 LM3405AXMKE NOPB與LM3405AXMK NOPB LM3405AXMKX NOPB對比 激光二极管 期刊查询 在word里面插入图片时怎样才成是100 比例的 文献 封装与功率 高手支招 xff1a 教你利用裸露
  • 激光啄木鸟使用教程

    软件下载地址 1 红色方框内的按钮长按开机 2 红色方框内的按钮轻触自动对焦 3 打开手机APP选择要雕刻的素材 4 设置要雕刻区域的大小 xff0c 开始预览可以查看雕刻的位置 5 打开蓝牙 xff0c 点击连接设备 6 选择被雕刻物件的
  • STM32 HAL库

    STM32 HAL库 第三章 MDK5 软件入门bug解决关键文件介绍程序仿真User Keywords语法提示代码编辑 查看技巧 第四章 STM32F1 基础知识入门MDK 下 C 语言基础复习STM32F103 时钟系统STM32F10
  • LWIP网络-基于STM32平台

    LWIP P1无操作系统移植RAW UDP实验RAW TCP实验Webserver实验 P1无操作系统移植 MAC 43 PHY 通过符合 IEEE802 3的MII和RMII接口与外接快速以太网PHY进行通信 MII和RMII实现数据交换
  • 树莓派学习

    树莓派学习教程 系统安装数据源的更新与配置命令设定固定IP网络地址 xff1a 法一法二 给树莓派安装中文环境和中文输入法远程控制树莓派SSH方式 xff1a 通过putty软件实现 xff08 不需要屏幕 xff09 VNC方式 xff0
  • C++学习教程

    C 43 43 学习教程 C 43 43 内存分区模型数据类型循环语句for循环语句 跳转语句指针指针 数组 函数 结构体指针 内存分区模型 工具vs codeDEV C 43 43 C 43 43 内存分区模型 程序运行前 全局区和代码区
  • core dumped ?完了?

    微信公众号 xff1a linux码头 core dumped xff1a 当程序在运行过程中发生异常 xff0c 这时linux系统可以把程序出错的内存 内容存储在一个core文件中 xff0c 又叫核心转存 应用程序在运行过程汇总经常会
  • Ubuntu18.04安装网络调试助手 NetAssist

    下载地址 链接 xff1a https pan baidu com s 1DUqZBtxFh pGTsRR2kXaPA 提取码 xff1a fp32 安装步骤 1 xff09 建立依赖关系 sudo apt get install f 2
  • C语言中左移(<<)和右移(>>)的理解

    lt lt 左移 xff1a 相当于乘法 a lt lt b 61 a 2 b 举例 xff1a 1 lt lt 5 xff0c 相当于1 2 5 61 32 1 lt lt 0 xff0c 相当于1 2 0 61 1 gt gt 右移 x
  • 《Linux运维总结:firewalld防火墙使用教程》

    文章目录 一 firewalld基础知识1 1 firewalld基本介绍1 2 firewalld与iptables关系与区别1 3 firewalld默认策略1 4 firewalld配置模式1 5 firewalld配置方法1 6 f
  • ROS常用的功能包

    坐标系 坐标变换 xff08 tf xff09 tf功能包提供了一个基于ROS的分布式框架 xff0c 可以随着时间的推移计算多个坐标系的位置 3D可视化工具 xff08 rviz xff09 机器人模型的可视化 图像数据的可视化 地图数据
  • 树莓派4B+Ubuntu 18.04 LTS + 桌面desktop + ros安装@树莓派4B、Ubuntu、desktop、ros

    树莓派4B 43 Ubuntu 18 04 LTS 43 桌面desktop 43 ros安装 64 树莓派4B Ubuntu desktop ros 久违的一篇博客 xff0c 说实话CSDN的编辑器还是用不太习惯 xff0c 记录一下树
  • 云台控制协议总结(VISCA/PELCOD/PELCOP)

  • error: #20: identifier "TIM_TimeBaseInitTypeDef" is undefined

    如果出现多句错误 xff1a identifier 34 34 is undefined 解决问题方法一 xff1a C C 43 43 include paths 把文件路径添加进去 解决问题方法二 xff1a 在stm32f10x co
  • 使用pyqt5实现键盘(含组合键)鼠标事件响应

    使用pyqt5实现键盘 xff08 含组合键 xff09 鼠标事件响应 使用python3 6 xff0c pyqt5 xff0c 在macOS上测试有效 span class hljs keyword import span sys sp
  • 递归思想刷题总结

    核心思想 我们在调用递归函数的时候 xff0c 把递归函数当做普通函数 xff08 黑箱 xff09 来调用 xff0c 即明白该函数的输入输出是什么 xff0c 而不用管此函数内部在做什么 xff08 千万不要跳进去了 xff0c 你脑袋
  • anonymous unions are only supported in --gnu mode, or when enabled with #pragma anon_unions

    在keil工程下移植代码 xff0c 编译出现了这个问题 xff0c 字面上解决办法有 xff1a 1 打开GNU模式 option gt GNU extensions 2 在代码前加上 pragma anon union 就是代表支持匿名
  • 串口的深入理解

    1 串口是如何发送数据的 xff1f 一般说来 xff0c 串口发送数据是往数据寄存器sbuf填写数据 xff0c 一个字节一个字节的写入 xff0c 如果有串口中断 xff0c 那么发送完一个字节的数据 xff0c 就会进入串口中断一次

随机推荐

  • CMakeLists.txt的简单使用

    Makefile和CMakeLists的关系 环境准备 xff1a 需要安装gcc xff0c g 43 43 xff0c make sudo apt get install gcc g 43 43 sudo apt get isntall
  • .so文件的基本理解,使用。

    一 基本概念 Linux下的 so是基于Linux下的动态链接 其功能和作用类似与windows下 dll文件 代码编译 xff0c 链接 xff0c 最后生成可执行文件 xff1b 这个可执行文件就可看作是一个静态链接 xff0c 因为代
  • jz2440:QT控制LED灯点亮熄灭(11)

    1 LED灯的驱动 xff1a 首先要准备好在驱动文件 xff0c 通过insmod led ko来加载模块 xff0c 然后在QT的代码里面配合调用open xff0c write read函数来点亮 xff0c 关闭LED灯 这一步 x
  • win10下安装ubuntu双系统

    本文章记录自己在Win10系统下安装ubuntu双系统的过程 xff0c 以及注意事项 另一个不错的安装教程 1 下载系统镜像 在官网或清华镜像 xff0c 根据需要的ubuntu版本下载需要的ubuntu镜像文件 这里要注意 xff0c
  • C++ shared_ptr的reset 用法

    include lt iostream gt include lt memory gt class Tmp public Tmp int a Tmp void print a std cout lt lt 34 value 61 34 lt
  • C++ 模板类的继承

    模板类 xff1a template lt typename T gt 说白了就是向之后的内容传递参数类型 xff0c 把T当作一个数据类型传递 xff0c 而在声明一个变量的时候 xff0c 通过base lt xxxx gt pp xx
  • linuxptp源码研究

    目录 1 检查网卡是否支持相应的时间戳 2 linuxptp的目录架构 3 ptp4l的大致流程分析 4 gptp协议对应的sync follow up delay request delay response消息在代码的位置 5 slav
  • xv6---Lab3: page tables

    目录 参考资料 RISC V页表的简化图如下所示 编辑 多级页表 xv6内核页表 3 6 Process Address Space 3 7 Code Sbrk 3 8 Code Exec Print a page table A kern
  • 内存管理---分页机制

    目录 物理内存管理带来的问题 直接映射 一级页表 二级页表 参考 xff1a xff08 C语言内存七 xff09 分页机制究竟是如何实现的 xff1f Smah 博客园 物理内存管理带来的问题 比如4GB的flash 如果应用程序可直接访
  • xv6---Lab4 traps

    参考 xff1a Lab Traps 关于寄存器s0和堆栈 https pdos csail mit edu 6 828 2020 lec l riscv slides pdf RISC V assembly Q 哪些寄存器包含函数的参数
  • stm32F4 hal库之CAN通信的实现

    本文的目的是为了能够实现功能 xff0c 故写的时候比较简略 参考资料 xff1a https blog csdn net u012308586 article details 81001102 正点原子开发手册 目标 xff1a 通过ca
  • 调试sim800L模块

  • 51单片机 串口中断

    1 什么是中断 广义上的中断是指一个过程 xff0c 举个简单的例子 xff0c 打开了电脑 xff0c 你正在放音乐 xff0c 点击了暂停按钮 xff0c 于是歌停了 这就是一个很明显的中断的例子 CPU正在做自己的事情 xff08 放
  • STM32CubeMX应用 -- 定时器输入脉冲计数

    目录 参考链接 一 实现过程 二 STM32CubeMX配置示例 三 C语言示例程序 参考链接 https blog csdn net m0 37845735 article details 105395643 一 实现过程 当选择外部的同
  • 机器人导航dwa(局部避障)分析

    前面部分引用http blog csdn net lqygame article details 72861439 xff08 1 xff09 初始化 xff1a 在move base节点中 xff0c 通过类加载模块载入了BaseLoca
  • 2019年最新VSLAM比较汇总

    2019年最新VSLAM比较汇总 闭源SOFTSOFT2ESOsGAN VOLG SLAMRotRocc 43 GDVOElbrusROCCMonoROCCcv4xv1 sc 开源 xff1a VINS FusionORB SLAM2Ste
  • CMSIS到底是个什么东西

    目录 一 前言 二 CMSIS标准 三 CMSIS文件 1 Include文件 2 Source文件 四 总结 一 前言 使用过ARM单片机的朋友肯定听说过CMSIS xff0c 可以说CMSIS是开启ARM单片机的金钥匙 xff0c 是不
  • TouchGFX介绍

    目录 一 关于TouchGFX 1 TouchGFX是一个图形框架 2 TouchGFX可以减轻CPU负载 3 TouchGFX充分利用了STM32的硬件图形外设 4 TouchGFX创建最佳性能的用户界面 5 TouchGFX可工作于ST
  • rt-thread应用篇(03)---基于STM32F429实现web服务器功能

    目录 参考示例 前言 一 需使用的组件与软件包及其ENV配置 1 文件系统相关组件与软件包 1 1 DFS 框架 1 2 fal 软件包 1 3 SFUD 组件 2 网络通信相关组件和软件包 2 1 SAL组件 2 2 netdev组件 2
  • rt-thread的at组件在freeRTOS上的移植与应用

    目录 一 AT命令 二 rtthread at组件简介 三 移植到freeRTOS 3 1 数据结构 3 2 API 3 3 at client 流程 3 4 串口数据接收处理 3 5 数据缓存 顺序队列 四 使用示例 4 1 串口配置信息