找回密码
 立即注册
查看: 77|回复: 5

USB-CDC串口接收高速数据时有时会丢失是什么原因

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2026-02-27 11:37:25
已绑定手机

1

主题

2

回帖

11

积分

新手上路

积分
11
发表于 2026-2-26 11:05:13 | 显示全部楼层 |阅读模式
// USB命令定义,VC的stdafx.h中同样定义
#define CMD_Usb_CDC_OK      0xa5
#define CMD_Usb_CDC_NG      0xa6
#define CMD_Usb_CDC_Check   0x1a  //检测USB-CDC串口通信,返回1个字节0x1a给串口
#define CMD_Send_Data                   0x2a  //返回CMD_Usb_CDC_OK或CMD_Usb_CDC_OK一个字节
#define CMD_Send_Strobe                  0x3a  //返回CMD_Usb_CDC_OK或CMD_Usb_CDC_OK一个字节
#define CMD_Pass_Sound                        0x8a  //返回CMD_Usb_CDC_OK或CMD_Usb_CDC_OK一个字节
#define CMD_Fail_Sound                        0x9a  //返回CMD_Usb_CDC_OK或CMD_Usb_CDC_OK一个字节
#define CMD_Alarm_Sound                        0xaa  //返回CMD_Usb_CDC_OK或CMD_Usb_CDC_OK一个字节
#define CMD_Key_Sound                                0xba  //返回CMD_Usb_CDC_OK或CMD_Usb_CDC_OK一个字节
#define CMD_Pin_Sound                                0xca  //返回CMD_Usb_CDC_OK或CMD_Usb_CDC_OK一个字节

#define CMD_QUEUE_SIZE    16         // 队列深度,根据实际需求调整
#define CMD_MAX_LEN       20         // 最大命令长度
typedef struct
{
    u8 len;
    u8 dataBuf[CMD_MAX_LEN];
} CmdItem;

CmdItem cmdQueue[CMD_QUEUE_SIZE];
volatile u8 cmdQueueHead = 0;         // 生产者索引(中断中修改)
volatile u8 cmdQueueTail = 0;         // 消费者索引(主循环中修改)


void usb_callback()
{
        u8 i;
        u8 next = (cmdQueueHead + 1) % CMD_QUEUE_SIZE;
        if (OutNumber == 0 || OutNumber > CMD_MAX_LEN) return;

        // 队列满时覆盖最旧的一条(可根据需求丢弃或等待)
        if (next == cmdQueueTail) {
                        cmdQueueTail = (cmdQueueTail + 1) % CMD_QUEUE_SIZE;  // 丢弃最旧命令
        }

        cmdQueue[cmdQueueHead].len = OutNumber;
        for (i = 0; i < OutNumber; i++)
        {
                        cmdQueue[cmdQueueHead].dataBuf[i] = UsbOutBuffer[i];
        }
        cmdQueueHead = next;
}

void ProcessUsbCommand(u8* dataBuf, u8 len)
{//UsbOutBuffer为接收到数据缓冲区,OutNumber为接收到的数据字节数
        u8 return_buf[8];
        if (len == 0) return;
       
        if(OutNumber == 0) return;

        switch(dataBuf[0])
        {
                case CMD_Usb_CDC_Check: //0x1a:检测USB-CDC串口通信,返回0x1a给串口
                        return_buf[0]=CMD_Usb_CDC_Check;
                        USB_SendData(return_buf, 1); //发送数据缓冲区,字节长度
                        break;
               
                case CMD_Send_Data:
                        Send_Data(dataBuf, len);
                        break;
               
                case CMD_Send_Strobe:
                        Send_Strobe(dataBuf, len);
                        break;
               
                case CMD_Pass_Sound:
                        Song(3,2);        //0,1 is Key_Sound; 1,1 is Pin_Sound; 2,1 is Fail_Sound; 3,2 is Pass_Sound
                        //Pass_Sound();
                        return_buf[0] = CMD_Usb_CDC_OK;
                        USB_SendData(return_buf, 1);
                        break;
               
                case CMD_Fail_Sound:
                        Song(2,1);        //0,1 is Key_Sound; 1,1 is Pin_Sound; 2,1 is Fail_Sound; 3,2 is Pass_Sound
                        //Fail_Sound();
                        return_buf[0] = CMD_Usb_CDC_OK;
                        USB_SendData(return_buf, 1);
                        break;
               
                case CMD_Alarm_Sound:
                        Song(2,1);        //0,1 is Key_Sound; 1,1 is Pin_Sound; 2,1 is Fail_Sound; 3,2 is Pass_Sound
                        //Fail_Sound();
                        return_buf[0] = CMD_Usb_CDC_OK;
                        USB_SendData(return_buf, 1);
                        break;
               
                case CMD_Key_Sound:
                        Song(0,1);        //0,1 is Key_Sound; 1,1 is Pin_Sound; 2,1 is Fail_Sound; 3,2 is Pass_Sound
                        //Key_Sound();
                        return_buf[0] = CMD_Usb_CDC_OK;
                        USB_SendData(return_buf, 1);
                        break;
               
                case CMD_Pin_Sound:
                        Song(1,1);        //0,1 is Key_Sound; 1,1 is Pin_Sound; 2,1 is Fail_Sound; 3,2 is Pass_Sound
                        //Pin_Sound();
                        return_buf[0] = CMD_Usb_CDC_OK;
                        USB_SendData(return_buf, 1);
                        break;

                case CMD_Write_Fixture:
                        Write_Fixture(dataBuf, len);
                        break;
               
                case CMD_Write_Mark:
                        Write_Mark(dataBuf, len);
                        break;
               
                case CMD_Rel_Fixture:
                        DOWN=1;//DOWN OFF
                        _nop_();
                        UP=0;//UP ON
                        _nop_();
                        break;

                case CMD_Read_Fixture:
                        Read_Fixture(len);
                        break;
                               
                case CMD_Read_Adc:
                        Read_Adc(dataBuf, len);
                        break;

                case CMD_Read_Comp:
                        Read_Comp(dataBuf, len);
                        break;
               
                default:
                         break;
        }
}

void main()
{
        EAXFR = 1; //允许访问扩展的特殊寄存器,XFR
        WTST = 0;  //设置取程序代码等待时间,
                                                 //赋值为 0 表示不等待,程序以最快速度运行
        CKCON = 0; //设置访问片内的 xdata 速度,
                                                 //赋值为 0 表示用最快速度访问,
                                                 //不增加额外的等待时

        P0M0 = 0x00; P0M1 = 0x00;  //设置 P0 口为准双向口模式
        P1M0 = 0x00; P1M1 = 0x00;  //设置 P1 口为准双向口模式
        P2M0 = 0x00; P2M1 = 0x00;  //设置 P2 口为准双向口模式
        P3M0 = 0x80; P3M1 = 0x00;  //设置 P3 口为准双向口模式,P3.7强上拉,P3M1:P3M0=0:0为准双向口/弱上拉, P3M1:P3M0=0:1为强推挽/强上拉
        P4M0 = 0x00; P4M1 = 0x00;  //设置 P4 口为准双向口模式
        P5M0 = 0x01; P5M1 = 0x00;  //设置 P5 口为准双向口模式
        P6M0 = 0x00; P6M1 = 0x00;  //设置 P6 口为准双向口模式
        P7M0 = 0x00; P7M1 = 0x00;  //设置 P7 口为准双向口模式
       

        usb_init(); //调用 USB 初始化函数,不需要立即判断电脑已正确识别到 USB 从设备
                                                        /* USB 型单片机从设备,如需要主动向电脑发送数据,
                                                        在执行 USB_SendData( )函数和 printf_usb( )函数时,
                                                        这两个函数已增加了判断电脑是否已正确识别到 USB 从设备的程序。
                                                        如果电脑要主动发送数据给 USB 从设备,电脑自己会主动判断与 USB 从设备是否已正确连接。
                                                        */
               
        set_usb_OUT_callback(usb_callback); //设置USB-CDC接收中断回调函数

        EA = 1;       //打开全局中断,一定要放在usb_init()的后面

        DelayMsT(10); //延时10MS
       

        while(1)
        {
                // 处理USB命令队列
                if (cmdQueueHead != cmdQueueTail)
                {
                                u8 idx = cmdQueueTail;
                                ProcessUsbCommand(cmdQueue[idx].dataBuf, cmdQueue[idx].len);
                                cmdQueueTail = (cmdQueueTail + 1) % CMD_QUEUE_SIZE;
                }
               
                Delay100us(1);
        }
}


用这个USB-CDC 串口 中断方式接收上位机发来的命令处理数据有时上会机发送命令后CDC串口没有执行命令返回数据,丢失的命令是随机的,程序中只要接收命令数据就一定会返回数据给上位机, 上面是一部分代码,请帮忙分析原因

回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:467
  • 最近打卡:2026-03-07 15:12:16
已绑定手机

102

主题

4134

回帖

9097

积分

荣誉版主

无情的代码机器

积分
9097
发表于 2026-2-26 11:16:10 | 显示全部楼层

程序中断里和主循环里都操作了cmdQueueTail
而usb_callback返回后表示程序可以接收下一包数据,逻辑上可能存在正在处理上一包而第二包到来的问题
建议:
1.增加发包间隔
2.usb_callback中负责组包产生消息,主循环只检查消息队列和处理
3.USB抓包工具调试
4.增加额外串口调试


三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2026-02-27 11:37:25
已绑定手机

1

主题

2

回帖

11

积分

新手上路

积分
11
发表于 2026-2-26 15:10:24 | 显示全部楼层
PC与USB-CDC通信是应答方式,PC收到USB-CDC的应答字节后再延时100us发送一包数据,PC等待应答字节延时为5ms,这样就避免了有未处理数据又收到下包数据问题,可还是会出现PC发送命令数据后USB-CDC接收不到命令无响应情况。请问还有哪些原因会影响USB-CDC中断接收数据。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:467
  • 最近打卡:2026-03-07 15:12:16
已绑定手机

102

主题

4134

回帖

9097

积分

荣誉版主

无情的代码机器

积分
9097
发表于 2026-2-26 15:55:23 | 显示全部楼层

测试过所有CMD执行时间远低于5ms?
抓包加串口打印调试吧,按上面描述大概率不是丢包,哪里配合有问题吧
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2026-02-27 11:37:25
已绑定手机

1

主题

2

回帖

11

积分

新手上路

积分
11
发表于 2026-2-27 11:37:25 | 显示全部楼层

能不能设置USB-CDC接中断包与包之的时间间隔为0

我仔细调试了,PC即使收到了USB-CDC串口处理完命令回送的应答字符,单片机送回了应该字符早已结束了接收回调函数可以接收一包数据,可是PC下一包数据与不能立即发送, 包与包之间的时间间隔不能低于2ms,设置和1ms都不行,效率太低了。USB-CDC是不是只是单包数据传输特别快,能不能设置包与包之的时间间隔为0。

点评

不能 USB-STC单片机教学视频 国芯人工智能技术交流网站 - AI32位8051交流社区  详情 回复 发表于 2026-2-27 14:12
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:467
  • 最近打卡:2026-03-07 15:12:16
已绑定手机

102

主题

4134

回帖

9097

积分

荣誉版主

无情的代码机器

积分
9097
发表于 2026-2-27 14:12:03 | 显示全部楼层
ljg*** 发表于 2026-2-27 11:37
我仔细调试了,PC即使收到了USB-CDC串口处理完命令回送的应答字符,单片机送回了应该字符早已结束了接收回 ...

不能

USB-STC单片机教学视频 国芯人工智能技术交流网站 - AI32位8051交流社区
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-3-7 15:32 , Processed in 0.111917 second(s), 67 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表