Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
原创征文
RPC远程调用
rt-thread 移植 eRPC 之 Transport (serial)
发布于 2022-09-05 13:43:51 浏览:1080
订阅该版
[tocm] ## 前言 前边调试通了 tcp Transport,但是有很多不带网卡的场合,串口设备却很容易配备。添加 rt-thread 串口设备框架的 Transport 会带来更广的应用场合。 ### 串口 Transport 接口 首先,我们浏览一下 "erpc_serial.h" 头文件,这里声明了 6 个函数: ``` int serial_setup(int fd, speed_t speed); int serial_set_read_timeout(int fd, uint8_t vtime, uint8_t vmin); int serial_write(int fd, char *buf, int size); int serial_read(int fd, char *buf, int size); int serial_open(const char *port); int serial_close(int fd); ``` 不同于 tcp transport 修改的 `TCPTransport` 类,串口不修改 `SerialTransport` ,而是上面这几个函数,到时候再细说每一个函数的作用以及注意点儿。 #### `SerialTransport` 虽说不修改吧,其实需要做点儿改动,添加 rt-thread 平台预编译兼容代码,把非 rt-thread 支持操作屏蔽掉,例如 ``` #ifdef _WIN32 #include
#include
#include
#elif defined(__RTTHREAD__) #else #include
#endif ``` 头文件未增加新头文件包含,还有两个地方原本是在 WIN32 平台下啥也没干,这里比猫画虎,也让 rt-thread 环境下啥也不干(共两处) ``` #ifdef _WIN32 // TODO #elif defined(__RTTHREAD__) // TODO ``` #### 修改 "serial.h" 添加 `speed_t` 类型定义: ``` #elif defined(__RTTHREAD__) typedef unsigned int speed_t; ``` #### "serial.cpp" 添加 rt-thread 设备框架头文件: ``` #elif defined(__RTTHREAD__) #include "rtdevice.h" struct rt_completion rx_ind; ``` #### `serial_setup` 串口配置,主要是配置修改波特率值。rt-thread 里配置串口设备波特率只需要调用一个函数 `rt_device_control`。 我们注意到 `serial_setup` 函数的第一个参数是 `int` 类型的(文件描述符概念),但是 rt-thread 里 `rt_deivce_xxx` 簇函数第一个参数是 `rt_device_t` 设备类对象指针类型的。这是我们需要解决的第一个问题。 其实很简单,强制转换一下,闭着眼就认为它是就好了:`rt_device_t dev = (rt_device_t)((unsigned int)fd);` 完整代码如下: ``` #elif defined(__RTTHREAD__) rt_device_t dev; struct serial_configure uart_conf = { \ BAUD_RATE_115200, /* 115200 bits/s */ \ DATA_BITS_8, /* 8 databits */ \ STOP_BITS_1, /* 1 stopbit */ \ PARITY_NONE, /* No parity */ \ BIT_ORDER_LSB, /* LSB first sent */ \ NRZ_NORMAL, /* Normal mode */ \ RT_SERIAL_RB_BUFSZ, /* Buffer size */\ 0 \ }; uart_conf.baud_rate = speed; dev = (rt_device_t)((unsigned int)fd); rt_device_control(dev, RT_DEVICE_CTRL_CONFIG, &uart_conf); ``` #### `serial_set_read_timeout` 这个也是设置串口设备的,用来改变串口读超时时间。rt-thread 里没有这个概念,可以置空。 ``` #ifdef _WIN32 // TODO #elif defined(__RTTHREAD__) // TODO #else ... ``` #### `serial_write` 写串口,第二个参数是预发送数据首字节地址,第三个参数是预发送数据字节数。 为了把所有数据全写出去,这里用了 do while 循环结构。 ``` rt_device_t dev; rt_size_t len = 0, ret = 0; dev = (rt_device_t)((unsigned int)fd); do { ret = rt_device_write(dev, 0, buf, size); if (ret == 0) { break; } len += ret; } while(len < size); return ret; ``` #### `serial_read` 读串口,第二个参数是接收数据缓存首地址,第三个参数是预读取数据字节数。笔者提醒:当且仅当读取到 `size` 个字节数据后才算成功,其它情况都应该算是错误。出错返回 -1。 ``` rt_device_t dev; rt_err_t err = 0; rt_size_t len = 0, ret = 0; rt_tick_t timeout = 0; dev = (rt_device_t)((unsigned int)fd); timeout = rt_tick_get() + 10000; do { err = rt_completion_wait(&rx_ind, 10); if (err == RT_ETIMEOUT) { if ((rt_tick_get() - timeout) < RT_TICK_MAX / 2) { return -1; } continue; } ret = rt_device_read(dev, 0, buf + len, size - len); if (ret == 0) { return -1; } else { len += ret; } } while (len < size); return len; ``` 这里有两点需要注意: 1. 也是一个 do while 循环结构,未得到想要的数据量前不能退出函数。 2. 做了个超时处理,超时 10s 后错误返回。 #### `serial_open` 目前笔者使用串口 v1 ,所以只开了中断接收,轮询发送模式。 ``` rt_device_t dev = RT_NULL; dev = rt_device_find(port); if (dev == RT_NULL) { rt_kprintf("Can not find device: %s\n", port); return -1; } rt_completion_init(&rx_ind); if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | \ RT_DEVICE_FLAG_INT_RX ) == RT_EOK) { rt_device_set_rx_indicate(dev, serial_rx_ind); } return (int)dev; ``` 中断接收添加了中断回调函数 `serial_rx_ind` ``` static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) { rt_completion_done(&rx_ind); } ``` 这里没有使用消息队列,也没有使用信号量,用的是完成量,通知 `serial_read` 有数据来。 如果换成 serialX 怎么样用方便呢? 1. 首先,打开串口设备用阻塞模式最好,收发都可以使用中断或者 DMA 。 2. 服务端阻塞读写都没特别影响,但是客户端的读过程有些特别,如果阻塞读,可能出现服务端掉线导致客户端线程被阻塞到 `serial_read` ,因为 `rt_device_read` 本身没有超时概念。用上中断回调函数可能是目前最优解。 总之,使用 serialX 或者 v1 上述代码差异不大。 #### `serial_close` 关闭串口设备就简单了 ``` #elif defined(__RTTHREAD__) rt_device_t dev; dev = (rt_device_t)((unsigned int)fd); rt_device_close(dev); ``` ### 验证 跑一下之前咱们做的两个小 demo。 和 tcp 不同的是初始化 transport 不一样了。 ``` erpc_transport_t transport = erpc_transport_serial_init("uart2", 115200); ``` 只支持两个参数,一个是串口设备名,一个是串口波特率。其它串口配置都固化到 `serial_setup` 函数里了。 串口 transport 没有 close ,因此没有 `erpc_transport_serial_close` 函数。 ## 结束语 > 友情提醒,使用 serialX 的非阻塞读实现 `serial_read` 效果更佳。 ***相关文章*** [rt-thread 移植 eRPC 系列(一) 之 简介](https://club.rt-thread.org/ask/article/3acf471c19f2595f.html) [rt-thread 移植 eRPC 系列(二) 之 演示](https://club.rt-thread.org/ask/article/7b9ed79f35c8e568.html) [rt-thread 移植 eRPC 系列(三) 之 Porting](https://club.rt-thread.org/ask/article/1713a66f5576e9ae.html) [rt-thread 移植 eRPC 之 Transport (winsock2)](https://club.rt-thread.org/ask/article/150d53743636c899.html) [rt-thread 移植 eRPC 之 Transport (lwip)](https://club.rt-thread.org/ask/article/ac4f22c4655f5581.html)
4
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
出出啊
恃人不如自恃,人之为己者不如己之自为也
文章
43
回答
1517
被采纳
342
关注TA
发私信
相关文章
1
请问RT-Thread有RPC方案吗?
2
rt-thread 支持eRPC吗
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
线程
RT-Thread Nano
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
807
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部