网站建设flash,抖音代运营推广,wordpress游戏支付宝,将电脑做的网站放到外网系列文章目录
rt-thread 之 fal移植 rt-thread 之 生成工程模板 文章目录系列文章目录前言一、串口的配置step1#xff1a;通过串口名字找到串口句柄step2#xff1a;配置串口参数step3#xff1a;设置串口接收回调函数step4#xff1a;打开串口设备前言
UART#xff08…系列文章目录
rt-thread 之 fal移植 rt-thread 之 生成工程模板 文章目录系列文章目录前言一、串口的配置step1通过串口名字找到串口句柄step2配置串口参数step3设置串口接收回调函数step4打开串口设备前言
UARTUniversal Asynchronous Receiver/Transmitter通用异步收发传输器UART 作为异步串口通信协议的一种工作原理是将传输数据的每个字符一位接一位地传输是在应用程序开发过程中使用频率最高的数据总线。我们经常在串口上接WIFI、4G模块也可以增加电平转换芯片变成RS232和RS485通信接口。rt-thread官网对串口做了详细的说明。这篇文章的目的是讲一下我对串口发送接收模式的理解和使用过程中遇到的问题。
一、串口的配置
#mermaid-svg-XK2gas1LVEr85HMt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-XK2gas1LVEr85HMt .error-icon{fill:#552222;}#mermaid-svg-XK2gas1LVEr85HMt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XK2gas1LVEr85HMt .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-XK2gas1LVEr85HMt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XK2gas1LVEr85HMt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XK2gas1LVEr85HMt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XK2gas1LVEr85HMt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XK2gas1LVEr85HMt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XK2gas1LVEr85HMt .marker.cross{stroke:#333333;}#mermaid-svg-XK2gas1LVEr85HMt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XK2gas1LVEr85HMt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XK2gas1LVEr85HMt .cluster-label text{fill:#333;}#mermaid-svg-XK2gas1LVEr85HMt .cluster-label span{color:#333;}#mermaid-svg-XK2gas1LVEr85HMt .label text,#mermaid-svg-XK2gas1LVEr85HMt span{fill:#333;color:#333;}#mermaid-svg-XK2gas1LVEr85HMt .node rect,#mermaid-svg-XK2gas1LVEr85HMt .node circle,#mermaid-svg-XK2gas1LVEr85HMt .node ellipse,#mermaid-svg-XK2gas1LVEr85HMt .node polygon,#mermaid-svg-XK2gas1LVEr85HMt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XK2gas1LVEr85HMt .node .label{text-align:center;}#mermaid-svg-XK2gas1LVEr85HMt .node.clickable{cursor:pointer;}#mermaid-svg-XK2gas1LVEr85HMt .arrowheadPath{fill:#333333;}#mermaid-svg-XK2gas1LVEr85HMt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XK2gas1LVEr85HMt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XK2gas1LVEr85HMt .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-XK2gas1LVEr85HMt .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-XK2gas1LVEr85HMt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XK2gas1LVEr85HMt .cluster text{fill:#333;}#mermaid-svg-XK2gas1LVEr85HMt .cluster span{color:#333;}#mermaid-svg-XK2gas1LVEr85HMt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XK2gas1LVEr85HMt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}找到串口设备配置串口参数设置接收回调函数打开设备rt-thread串口配置步骤
step1通过串口名字找到串口句柄
rt_device_find()
例
static rt_device_t serial;
#define SAMPLE_UART_NAME uart2
serial rt_device_find(SAMPLE_UART_NAME);step2配置串口参数
串口配置就是我们常见的串口参数配置 uart2_config.baud_rate BAUD_RATE_115200; //修改波特率为 9600uart2_config.data_bits DATA_BITS_8; //数据位 8uart2_config.stop_bits STOP_BITS_1; //停止位 1uart2_config.bufsz 128; //修改缓冲区 buff size 为 128uart2_config.parity PARITY_NONE; //无奇偶校验位这里有个接收缓存区的概念其实就是一个环形队列可以缓存串口接收的数据。当接收数据大于缓存区会日志输出告警信息。所以接收到的消息需要及时处理。 LOG_W(Warning: There is no enough buffer for saving data, please increase the RT_SERIAL_RB_BUFSZ option.);使用rt_device_control()函数修改串口配置参数
struct serial_configure uart2_config RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置参数 *//* step2修改串口配置参数 */uart2_config.baud_rate BAUD_RATE_115200; //修改波特率为 9600uart2_config.data_bits DATA_BITS_8; //数据位 8uart2_config.stop_bits STOP_BITS_1; //停止位 1uart2_config.bufsz 128; //修改缓冲区 buff size 为 128uart2_config.parity PARITY_NONE; //无奇偶校验位rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, uart2_config);step3设置串口接收回调函数
当发生中断接收中断或者空闲中断时会调用注册的回调函数。用户可以在回调函数中写一些无阻塞的功能。虽然回调函数但是在中断中执行所以不能有阻塞和延时。此回调函数在中断接收和DMA接收时实现的功能不一致。以下代码是中断接收时的参考。
/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{/* 串口接收到数据后产生中断调用此回调函数然后发送接收信号量 */rt_sem_release(rx_sem);cnt;return RT_EOK;
}/* 设置接收回调函数 */rt_device_set_rx_indicate(serial, uart_input);step4打开串口设备
打开设备时可以对串口的模式进行配置rt-thread提供三种模式中断模式、轮询模式、DMA 模式。发送和接收只能从中选一个发送和接收可以配置的不一致。默认使用中断接收和轮训发送。 注其中UART版本1中STM32中断发送模式有问题推荐使用V2版本。
/* 以中断接收及轮询发送模式打开串口设备 */
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)oflag支持模式参数为下列几个
#define RT_DEVICE_FLAG_INT_RX 0x100 /** INT mode on Rx 中断接收 */
#define RT_DEVICE_FLAG_DMA_RX 0x200 /** DMA mode on Rx DMA接收 */
#define RT_DEVICE_FLAG_INT_TX 0x400 /** INT mode on Tx 中断发送 */
#define RT_DEVICE_FLAG_DMA_TX 0x800 /** DMA mode on Tx DMA接收 */rt_device_open函数中初始化DMA模式会进行参数检查需要确认使用串口DMA宏被定义。如BSP_UART2_RX_USING_DMA否则会rt_serial_open()返回错误
/* check device flag with the open flag */
if ((oflag RT_DEVICE_FLAG_DMA_RX) !(dev-flag RT_DEVICE_FLAG_DMA_RX))return -RT_EIO;
if ((oflag RT_DEVICE_FLAG_DMA_TX) !(dev-flag RT_DEVICE_FLAG_DMA_TX))return -RT_EIO;
if ((oflag RT_DEVICE_FLAG_INT_RX) !(dev-flag RT_DEVICE_FLAG_INT_RX))return -RT_EIO;
if ((oflag RT_DEVICE_FLAG_INT_TX) !(dev-flag RT_DEVICE_FLAG_INT_TX))return -RT_EIO;当对应串口DMA宏在rtconfig.h中被定义后通过宏定义设置到对应串口对象的uart_dma_flag参数中在串口初始化阶段通过rt_hw_usart_init()中的rt_hw_serial_register()函数会把对应uart_dma_flag设置到串口dev-flag中后续串口open时只是检查一下参数。
/* register UART device */
result rt_hw_serial_register(uart_obj[i].serial, uart_obj[i].config-name,RT_DEVICE_FLAG_RDWR| RT_DEVICE_FLAG_INT_RX| RT_DEVICE_FLAG_INT_TX| uart_obj[i].uart_dma_flag, NULL);完整的串口配置例程代码如下所示其实现的功能是串口收到数据后回传。 /** 程序清单这是一个 串口 设备使用例程* 例程导出了 uart_sample 命令到控制终端* 命令调用格式uart_sample uart2* 命令解释命令第二个参数是要使用的串口设备名称为空则使用默认的串口设备* 程序功能通过串口输出字符串hello RT-Thread!然后错位输出输入的字符
*/#include rtthread.h
#include module_uart.h
#include drv_usart.h
#define SAMPLE_UART_NAME uart2
struct serial_configure uart2_config RT_SERIAL_CONFIG_DEFAULT; /* 初始化配置参数 */
/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;
uint16_t cnt 0;
/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{/* 串口接收到数据后产生中断调用此回调函数然后发送接收信号量 */rt_sem_release(rx_sem);cnt;return RT_EOK;
}static void serial_thread_entry(void *parameter)
{char ch;while (1){/* 从串口读取一个字节的数据没有读取到则等待接收信号量 */while (rt_device_read(serial, -1, ch, 1) ! 1){/* 阻塞等待接收信号量等到信号量后再次读取数据 */rt_sem_take(rx_sem, RT_WAITING_FOREVER);}/* 读取到的数据通过串口错位输出 */
// ch ch 1;rt_device_write(serial, 0, ch, 1);}
}int uart2_init(void)
{rt_err_t ret;/* 查找系统中的串口设备 */serial rt_device_find(SAMPLE_UART_NAME);if (!serial){rt_kprintf(find %s failed!\n, SAMPLE_UART_NAME);return RT_ERROR;}/* step2修改串口配置参数 */uart2_config.baud_rate BAUD_RATE_115200; //修改波特率为 9600uart2_config.data_bits DATA_BITS_8; //数据位 8uart2_config.stop_bits STOP_BITS_1; //停止位 1uart2_config.bufsz 128; //修改缓冲区 buff size 为 128uart2_config.parity PARITY_NONE; //无奇偶校验位rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, uart2_config);/* 初始化信号量 */rt_sem_init(rx_sem, rx_sem, 0, RT_IPC_FLAG_FIFO);/* 以中断接收及轮询发送模式打开串口设备 */rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);/* 设置接收回调函数 */rt_device_set_rx_indicate(serial, uart_input);/* 创建 serial 线程 */rt_thread_t thread rt_thread_create(serial, serial_thread_entry, RT_NULL, 1024, 25, 10);/* 创建成功则启动线程 */if (thread ! RT_NULL){rt_thread_startup(thread);}else{ret RT_ERROR;}return ret;
}
///* 导出到 msh 命令列表中 */
//MSH_CMD_EXPORT(uart_sample, uart device sample);