我已经获取到了手册中关于 USB-CDC printf 收发机制的关键信息。现在可以对这个帖子的问题进行深入分析了。
关于"擎天柱 printf_usb 打印接收不到数据"的问题
楼主的问题是:无论是"查询方式"还是"中断方式"的实验,在 CDC-HID 串口助手中发送数据后,始终无法接收到擎天柱(Ai8051U)返回的数据,但"直接打印数据"例程却可以正常工作。
根据 Ai8051U 数据手册《USB库函数使用说明》 章节,我来帮您梳理这个问题的关键点。
核心原因分析
这三个实验("直接打印数据" vs "打印接收到的数据(查询方式/中断方式)")的区别,关键在于数据的方向:
- "直接打印数据"例程:是单片机主动向 PC 发送数据(上行)。它用的是
printf_usb(),这个函数内置了判断 USB 状态和发送忙的逻辑(见下面的手册说明),所以即使 USB 还没完全配置好,也不会堵塞,数据会正常打印出来。
- "打印接收到的数据"(查询/中断方式)例程:是PC 先发数据给单片机(下行),单片机收到后原样返回(上行)。这个流程依赖
bUsbOutReady 标志,而楼主的代码里极有可能是没有正确触发数据接收的条件。
关键点一:bUsbOutReady 是接收成功的标志
根据手册:
"bUsbOutReady":主机发送给HID/CDC设备的数据状态。状态位为1表示,主机发送给HID/CDC设备数据已完成,设备已成功接收一包数据,等待对数据继续处理。
所以,只有当 bUsbOutReady == 1 时,UsbOutBuffer 里的数据才有效。如果楼主的程序从来没有走到 if (bUsbOutReady) 里面,自然就不会有回发了。
关键点二:查询方式必须调用 usb_OUT_done()
手册中强调:
"当使用查询方式调用USB库函数时,数据处理完成后,必须调用一次'usb_OUT_done();',这样才能接收下一包数据。如果是使用中断方式调用USB库函数,用户程序不需要调用'usb_OUT_done();',库函数内部会自动处理。"
如果查询方式下漏掉了 usb_OUT_done();,那么只能接收第一包数据,之后就无法再接收新数据了。
关键点三:中断方式必须正确设置回调函数
手册中说明:
"如果需要使用中断方式调用USB库函数,需要调用此函数来设置回调函数。若不设置,则是使用默认的查询方式调用USB库函数。"
即中断方式必须调用 set_usb_OUT_callback(usb_callback); 来注册回调函数。如果只写了一个中断服务函数但没有调用 set_usb_OUT_callback() 注册,那么中断回调永远不会被触发,数据自然收不到。这是一个非常常见的遗漏点。
同时还要确认 EA = 1; 总中断已经打开(USB 库依赖中断工作)。
给楼主的排查建议
请按以下顺序检查您的"查询方式"和"中断方式"代码:
查询方式检查清单:
- ✅ 主循环是否检测了
if (bUsbOutReady)?
- ✅ 数据处理后是否调用了
usb_OUT_done();?
- ✅
EA = 1; 是否已打开?(查询方式也需要,USB 底层引擎靠中断工作)
中断方式检查清单:
- ✅ 是否调用了
set_usb_OUT_callback(usb_callback); 注册回调?(最容易漏)
- ✅ 回调函数里是否有
USB_SendData(UsbOutBuffer, OutNumber);?
- ✅
EA = 1; 是否已打开?
正确的查询方式核心代码(参考手册范例)
while (1)
{
if (bUsbOutReady) // 检测到主机发来一包数据
{
USB_SendData(UsbOutBuffer, OutNumber); // 数据原样返回
usb_OUT_done(); // ★ 必须调用,才能接收下一包
}
}
正确的中断方式核心代码(参考手册范例)
void usb_callback() // 自定义 USB OUT 中断回调
{
USB_SendData(UsbOutBuffer, OutNumber); // 数据原样返回
}
void main()
{
// ... 端口配置 ...
usb_init();
set_usb_OUT_callback(usb_callback); // ★ 必须注册回调函数
EA = 1;
while (1);
}
小结
| 检查项 |
查询方式 |
中断方式 |
检测 bUsbOutReady / 回调触发 |
主循环 if(bUsbOutReady) |
注册 set_usb_OUT_callback() |
是否调用 usb_OUT_done() |
必须调用 |
不需要(库自动处理) |
EA = 1 总中断 |
需要 |
需要 |
信息来源:Ai8051U 数据手册《USB库函数使用说明》章节——"USB库函数的详细说明"及"USB范例程序,查询方式和中断方式各举一例"部分。
建议您对照手册里的范例程序1(查询方式)和范例程序2(中断方式)逐一核对您的代码。如果确认以上清单都正确但仍收不到数据,欢迎把您的完整代码贴出来,我帮您具体排查。另外请确认使用的实验箱/擎天柱的 USB 口与 PC 连接正常,且串口助手选择的是对应 CDC 的 COM 口。
🔍 搜索 "STC 单片机 AI MCU 论坛"
⏱️ 查找用时 7.1s | 总回答用时 18.6s