外观
USB ACM 虚拟串口设备
2025-10-29
本文将详细介绍如何通过 RT-Thread 操作系统使用 USB ACM 虚拟串口设备,实现开发板与主机之间的串口通信功能。该示例以 RK3506 平台为基础,帮助用户掌握 ACM 虚拟串口的基本使用流程。
ACM
ACM(Abstract Control Model)是 USB CDC(Communications Device Class)的一个子类,常用于虚拟串口设备。它通常被应用于调试接口或 AT 命令交互 等场景。 在本示例中:
- 开发板 作为 USB 设备(Device)
- PC 主机 作为 USB 主机(Host)
ACM 虚拟串口实验
本实验演示如何通过 USB ACM 虚拟串口在开发板和主机之间建立串口通信。 用户可以在主机上通过虚拟串口与开发板进行数据收发,从而实现与传统串口相同的调试和通信功能。
硬件连接
开发板的 USB0 接口连接电脑

创建工程点击展开
依次点击 “文件” -> “新建” -> "RT-Thread RuiChing App 项目"。

在弹出新建向导中选择 开发版 、BSP: 、示例 、 调试器/下载器。选择好之后点击 “完成”。

点击 “完成” 后,等待工程创建完成。

创建完成。

构建工程点击展开
单击工程使工程进入 Active-Debug 模式。

点击工具栏上的构建按钮进行工程编译。

构建成功后,会显示构建成功的信息。

固件下载点击展开
固化设备树

固化 APP

核心示例代码
- 虚拟串口配置,接收缓冲区要设置大于 2048,其它配置不影响 usb 虚拟串口通信。
usb_device_acm.c
#define ACM_NAME "uart6"
#define RB_SIZE 2048 // buffer 设置要大于等于 2048
...
static struct serial_configure config_uart =
{
BAUD_RATE_115200,
DATA_BITS_8,
STOP_BITS_1,
PARITY_NONE,
BIT_ORDER_LSB,
NRZ_NORMAL,
4096, // buffer 设置要大于等于 2048
0
};- 注册中断回调,在回调函数里接收数据,通知线程打印接收的数据。
usb_device_acm.c
rt_err_t cdc_acm_rx_callback(rt_device_t dev, rt_size_t size)
{
rx_len = rt_device_read(dev, 0, read_buf, RB_SIZE); // 读取数据
if (rx_len > 0)
{
rt_sem_release(acm_sem); // 通知线程
}
return RT_EOK;
}
void cdc_acm_thread(void *arg)
{
int ret = 0;
acm_sem = rt_sem_create("acm", 0, RT_IPC_FLAG_PRIO);
rt_device_t dev = rt_device_find(ACM_NAME);
rt_device_control(dev, RT_DEVICE_CTRL_CONFIG, &config_uart); // 配置串口参数
rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | \
RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX); // 以 DMA 方式打开串口
rt_device_set_rx_indicate(dev, cdc_acm_rx_callback); // 注册接收回调函数
while(1)
{
rt_device_write(dev, 0, send_buf, sizeof(send_buf)); // 发送数据
ret = rt_sem_take(acm_sem, 500);
if(ret ==RT_EOK)
{
LOG_I("ACM recv %d bytes: %.*s", rx_len, rx_len, read_buf); // 打印接收的数据
}
}
}运行程序
提示
因为是虚拟的串口,所以波特率等设置不会影响功能
开发板运行程序后,通过串口调试工具打开新增的 COM 口,可以看到开发板每隔一段时间就会通过虚拟串口发送一串字符,当 PC 往开发板发送数据时,开发板控制台可以打印接收到的字符。
收 <- hello RTThread!
收 <- hello RTThread!
收 <- hello RTThread!
收 <- hello RTThread!
收 <- hello RTThread!
发 -> hello
收 <- hello RTThread!
收 <- hello RTThread!
收 <- hello RTThread!
发 -> hello
收 <- hello RTThread!
收 <- hello RTThread!
发 -> hello 123
收 <- hello RTThread![I/example.dev.acm]ACM send 7 bytes: hello
[I/example.dev.acm]ACM send 7 bytes: hello
[I/example.dev.acm]ACM send 11 bytes: hello 123