qqtfh 发表于 2021-4-21 21:36

请教CH552模拟CH340的参考程序是如何发送和接收的。

#include "./Public/CH554.H"
#include "./Public/Debug.H"
#include <stdio.h>
#include <string.h>

#define THIS_ENDP0_SIZE         DEFAULT_ENDP0_SIZE

UINT8X        Ep0Buffer _at_ 0x0000;                              //端点0 OUT&IN缓冲区,必须是偶地址
UINT8X        Ep2Buffer _at_ 0x0008;                              //端点2 IN&OUT缓冲区,必须是偶地址
UINT8XEp1Buffer _at_ 0x00a0;



UINT8   SetupReq,SetupLen,Ready,Count,FLAG,UsbConfig;
PUINT8pDescr;                                                                  //USB配置标志
USB_SETUP_REQ   SetupReqBuf;                                                       //暂存Setup包
UINT8   num = 0;
#define UsbSetupBuf   ((PUSB_SETUP_REQ)Ep0Buffer)

sbit Ep2InKey = P1^5;                                                            //K1按键
#pragmaNOAREGS
/*设备描述符*/

UINT8C DevDesc={0x12,0x01,0x10,0x01,0xff,0x00,0x02,0x08,                   //设备描述符
                  0x86,0x1a,0x23,0x55,0x04,0x03,0x00,0x00,
                  0x00,0x01};

UINT8C CfgDesc={0x09,0x02,0x27,0x00,0x01,0x01,0x00,0x80,0xf0,            //配置描述符,接口描述符,端点描述符
                          0x09,0x04,0x00,0x00,0x03,0xff,0x01,0x02,0x00,         
                  0x07,0x05,0x82,0x02,0x20,0x00,0x00,                        //批量上传端点
                              0x07,0x05,0x02,0x02,0x20,0x00,0x00,                        //批量下传端点      
                                      0x07,0x05,0x81,0x03,0x08,0x00,0x01};                     //中断上传端点

UINT8C DataBuf={0x30,0x00,0xc3,0x00,0xff,0xec,0x9f,0xec,0xff,0xec,0xdf,0xec,
                  0xdf,0xec,0xdf,0xec,0x9f,0xec,0x9f,0xec,0x9f,0xec,0x9f,0xec,
                  0xff,0xec};

/*字符串描述符 略*/

// unsigned charcode LangDes[]={0x04,0x03,0x09,0x04};         //语言描述符
// unsigned charcode SerDes[]={
//                           0x28,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
//                           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
//                           0x00,0x00,0x00,0x00,0x00,0x49,0x00,0x43,0x00,0x42,
//                           0x00,0x43,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00
//                           };                                 //字符串描述符

UINT8X UserEp2Buf;                                          //用户数据定义


/*******************************************************************************
* Function Name: Enp2BlukIn()
* Description    : USB设备模式端点2的批量上传
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Enp2BlukIn( )
{
    memcpy( Ep2Buffer+MAX_PACKET_SIZE, UserEp2Buf, sizeof(UserEp2Buf));      //加载上传数据
    UEP2_T_LEN = THIS_ENDP0_SIZE;                                              //上传最大包长度
    UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;                  //有数据时上传数据并应答ACK
    while(UEP2_CTRL&UEP_T_RES_ACK);                                          //等待传输完成
}

/*******************************************************************************
* Function Name: DeviceInterrupt()
* Description    : CH559USB中断处理函数
*******************************************************************************/
void    DeviceInterrupt( void ) interrupt INT_NO_USB using 1                  //USB中断服务程序,使用寄存器组1
{
    UINT8 len,i;
    if(UIF_TRANSFER)                                                            //USB传输完成标志
    {
      switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
      {
      case UIS_TOKEN_IN | 2:                                                //endpoint 2# 端点批量上传
             UEP2_T_LEN = 0;                                                    //预使用发送长度一定要清空
//            UEP1_CTRL ^= bUEP_T_TOG;                                          //如果不设置自动翻转则需要手动翻转
            UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;         //默认应答NAK
            break;
      case UIS_TOKEN_OUT | 2:                                                 //endpoint 2# 端点批量下传
            if ( U_TOG_OK )                                                   // 不同步的数据包将丢弃
            {
                len = USB_RX_LEN;                                             //接收数据长度,数据从Ep2Buffer首地址开始存放
                for ( i = 0; i < len; i ++ )
                {
                  Ep2Buffer = Ep2Buffer;         // OUT数据取反到IN由计算机验证
                }
                UEP2_T_LEN = len;
                UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;       // 允许上传
            }
            break;
      case UIS_TOKEN_SETUP | 0:                                             //SETUP事务
            len = USB_RX_LEN;
            if(len == (sizeof(USB_SETUP_REQ)))
            {
                SetupLen = UsbSetupBuf->wLengthL;
                if(UsbSetupBuf->wLengthH || SetupLen > 0x7F )
                {
                  SetupLen = 0x7F;                                             // 限制总长度
                }
                len = 0;                                                         // 默认为成功并且上传0长度
                SetupReq = UsbSetupBuf->bRequest;                                                       
                if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )/*HID类命令*/
                {
                                        switch( SetupReq )                                             
                                        {
                                                case 0xC0:                                                
                                                  pDescr = &DataBuf;
                                                  len = 2;
                                                  if(num<24)
                                                  {       
                                                        num += 2;
                                                        }
                                                        else
                                                        {
                                                                num = 24;
                                                        }                                                                                       
                                                               break;
                                                case 0x40:
                                                        len = 9;   //保证状态阶段,这里只要比8大,且不等于0xff即可
                                                        break;
                                                default:
                                                               len = 0xFF;                                                                   /*命令不支持*/                                       
                                                               break;
                                        }
                                        if ( SetupLen > len )
                                        {
                                                SetupLen = len;    //限制总长度
                                        }
                                        len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;//本次传输长度
                                        memcpy(Ep0Buffer,pDescr,len);                            //加载上传数据
                                        SetupLen -= len;
                                        pDescr += len;
                                               
                }
                else                                                             //标准请求
                {
                  switch(SetupReq)                                             //请求码
                  {
                  case USB_GET_DESCRIPTOR:
                        switch(UsbSetupBuf->wValueH)
                        {
                        case 1:                                                //设备描述符
                            pDescr = DevDesc;                                    //把设备描述符送到要发送的缓冲区
                            len = sizeof(DevDesc);
                            break;
                        case 2:                                                //配置描述符
                            pDescr = CfgDesc;                                    //把设备描述符送到要发送的缓冲区
                            len = sizeof(CfgDesc);
                            break;
                        default:
                            len = 0xff;                                          //不支持的命令或者出错
                            break;
                        }
                        if ( SetupLen > len )
                        {
                            SetupLen = len;    //限制总长度
                        }
                        len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;//本次传输长度
                        memcpy(Ep0Buffer,pDescr,len);                            //加载上传数据
                        SetupLen -= len;
                        pDescr += len;
                        break;
                  case USB_SET_ADDRESS:
                        SetupLen = UsbSetupBuf->wValueL;                         //暂存USB设备地址
                        break;
                  case USB_GET_CONFIGURATION:
                        Ep0Buffer = UsbConfig;
                        if ( SetupLen >= 1 )
                        {
                            len = 1;
                        }
                        break;
                  case USB_SET_CONFIGURATION:
                        UsbConfig = UsbSetupBuf->wValueL;
                        break;
                  case 0x0A:
                        break;
                  case USB_CLEAR_FEATURE:                                    //Clear Feature
                        if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// 端点
                        {
                            switch( UsbSetupBuf->wIndexL )
                            {
                            case 0x82:
                              UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
                              break;
                            case 0x81:
                              UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
                              break;
                            case 0x02:
                              UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
                              break;
                            default:
                              len = 0xFF;                                       // 不支持的端点
                              break;
                            }
                        }
                        else
                        {
                            len = 0xFF;                                           // 不是端点不支持
                        }
                        break;
                  case USB_SET_FEATURE:                                       /* Set Feature */
                        if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x00 )      /* 设置设备 */
                        {
                            if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 )
                            {
                              if( CfgDesc[ 7 ] & 0x20 )
                              {
                                    /* 设置唤醒使能标志 */
                              }
                              else
                              {
                                    len = 0xFF;                                    /* 操作失败 */
                              }
                            }
                            else
                            {
                              len = 0xFF;                                        /* 操作失败 */
                            }
                        }
                        else if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x02 )    /* 设置端点 */
                        {
                            if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 )
                            {
                              switch( ( ( UINT16 )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL )
                              {
                              case 0x82:
                                    UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
                                    break;
                              case 0x02:
                                    UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
                                    break;
                              case 0x81:
                                    UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
                                    break;
                              default:
                                    len = 0xFF;                                     /* 操作失败 */
                                    break;
                              }
                            }
                            else
                            {
                              len = 0xFF;                                       /* 操作失败 */
                            }
                        }
                        else
                        {
                            len = 0xFF;                                             /* 操作失败 */
                        }
                        break;
                  case USB_GET_STATUS:
                        Ep0Buffer = 0x00;
                        Ep0Buffer = 0x00;
                        if ( SetupLen >= 2 )
                        {
                            len = 2;
                        }
                        else
                        {
                            len = SetupLen;
                        }
                        break;
                  default:
                        len = 0xff;                                                //操作失败
                        break;
                  }
                }
            }
            else
            {
                len = 0xff;                                                          //包长度错误
            }
            if(len == 0xff)
            {
                SetupReq = 0xFF;
                UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
            }
            else if(len <= THIS_ENDP0_SIZE)                                       //上传数据或者状态阶段返回0长度包
            {
                UEP0_T_LEN = len;
                UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
            }
            else
            {
                UEP0_T_LEN = 0;//虽然尚未到状态阶段,但是提前预置上传0长度数据包以防主机提前进入状态阶段
                UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
            }
            break;
      case UIS_TOKEN_IN | 0:                                                      //endpoint0 IN
            switch(SetupReq)
            {
            case USB_GET_DESCRIPTOR:
                len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;   //本次传输长度
                memcpy( Ep0Buffer, pDescr, len );                                 //加载上传数据
                SetupLen -= len;
                pDescr += len;
                UEP0_T_LEN = len;
                UEP0_CTRL ^= bUEP_T_TOG;                                          //同步标志位翻转
                break;
            case USB_SET_ADDRESS:
                USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
                UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
                break;
            default:
                UEP0_T_LEN = 0;                                                      //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
                UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
                break;
            }
            break;
      case UIS_TOKEN_OUT | 0:// endpoint0 OUT
            len = USB_RX_LEN;
            if(SetupReq == 0x09)
            {
                if(Ep0Buffer)
                {
                  printf("Light on Num Lock LED!\n");
                }
                else if(Ep0Buffer == 0)
                {
                  printf("Light off Num Lock LED!\n");
                }
            }
            UEP0_T_LEN = 0;//虽然尚未到状态阶段,但是提前预置上传0长度数据包以防主机提前进入状态阶段
            UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA0,返回应答ACK
            break;
      default:
            break;
      }
      UIF_TRANSFER = 0;                                                         //写0清空中断
    }
    if(UIF_BUS_RST)                                                               //设备模式USB总线复位中断
    {
      UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
      UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
      UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
      USB_DEV_AD = 0x00;
      UIF_SUSPEND = 0;
      UIF_TRANSFER = 0;
      UIF_BUS_RST = 0;                                                             //清中断标志
    }
    if (UIF_SUSPEND)                                                               //USB总线挂起/唤醒完成
    {
      UIF_SUSPEND = 0;
      if ( USB_MIS_ST & bUMS_SUSPEND )                                             //挂起
      {
#ifdef DE_PRINTF
            printf( "zz" );                                                          //睡眠状态
#endif
            while ( XBUS_AUX & bUART0_TX )
            {
                ;    //等待发送完成
            }
            SAFE_MOD = 0x55;
            SAFE_MOD = 0xAA;
            WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO;                                 //USB或者RXD0有信号时可被唤醒
            PCON |= PD;                                                               //睡眠
            SAFE_MOD = 0x55;
            SAFE_MOD = 0xAA;
            WAKE_CTRL = 0x00;
      }
    }
    else {                                                                           //意外的中断,不可能发生的情况
      USB_INT_FG = 0xFF;                                                             //清中断标志
//      printf("UnknownIntN");
    }
}
/*******************************************************************************
* Function Name: USBDeviceCfg()
* Description    : USB设备模式配置
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USBDeviceCfg()
{
    USB_CTRL = 0x00;                                                         //清空USB控制寄存器
    USB_CTRL &= ~bUC_HOST_MODE;                                                //该位为选择设备模式
    USB_CTRL |=bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN;                  //USB设备和内部上拉使能,在中断期间中断标志未清除前自动返回NAK
    USB_DEV_AD = 0x00;                                                         //设备地址初始化
//   USB_CTRL |= bUC_LOW_SPEED;
//   UDEV_CTRL |= bUD_LOW_SPEED;                                                //选择低速1.5M模式
    USB_CTRL &= ~bUC_LOW_SPEED;
    UDEV_CTRL &= ~bUD_LOW_SPEED;                                             //选择全速12M模式,默认方式
          UDEV_CTRL = bUD_PD_DIS;// 禁止DP/DM下拉电阻
    UDEV_CTRL |= bUD_PORT_EN;                                                //使能物理端口
}
/*******************************************************************************
* Function Name: USBDeviceEndPointCfg()
* Description    : USB设备模式端点配置,模拟兼容HID设备,除了端点0的控制传输,还包括端点2批量上下传
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USBDeviceEndPointCfg()
{
        UEP1_DMA = Ep1Buffer;                                                      //端点1 发送数据传输地址
    UEP2_DMA = Ep2Buffer;                                                      //端点2 IN数据传输地址       
    UEP2_3_MOD = 0xCC;                                                         //端点2/3 单缓冲收发使能
    UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;               //端点2自动翻转同步标志位,IN事务返回NAK,OUT返回ACK

    UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;                                 //端点1自动翻转同步标志位,IN事务返回NAK       
        UEP0_DMA = Ep0Buffer;                                                      //端点0数据传输地址
    UEP4_1_MOD = 0X40;                                                         //端点1上传缓冲区;端点0单64字节收发缓冲区
    UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;                                 //手动翻转,OUT事务返回ACK,IN事务返回NAK
}
/*******************************************************************************
* Function Name: USBDeviceIntCfg()
* Description    : USB设备模式中断初始化
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USBDeviceIntCfg()
{
    USB_INT_EN |= bUIE_SUSPEND;                                             //使能设备挂起中断
    USB_INT_EN |= bUIE_TRANSFER;                                              //使能USB传输完成中断
    USB_INT_EN |= bUIE_BUS_RST;                                             //使能设备模式USB总线复位中断
    USB_INT_FG |= 0x1F;                                                       //清中断标志
    IE_USB = 1;                                                               //使能USB中断
    EA = 1;                                                                   //允许单片机中断
}

main()
{
    UINT8 i;
    CfgFsys( );                                                         //CH559时钟选择配置
    mDelaymS(5);                                                          //修改主频等待内部晶振稳定,必加       
    mInitSTDIO( );                                                      //串口0初始化
#ifdef DE_PRINTF
    printf("start ...\n");
#endif       
    USBDeviceCfg();                                                   
    USBDeviceEndPointCfg();                                             //端点配置
    USBDeviceIntCfg();                                                    //中断初始化
        UEP0_T_LEN = 0;
    UEP1_T_LEN = 0;                                                       //预使用发送长度一定要清空
    UEP2_T_LEN = 0;                                                       //预使用发送长度一定要清空

    while(1)
    {

    }
}

上面是官网下载的,CH559模拟CH340 USB转串口的参考程序。我改成CH552是可以识别出CH341A,但是没看懂发送和接收应该如何调用。main()中也没有调用发送和接收。另外,如果想要发送64byte以上数据,应该如何操作。求指点。对沁恒的USB了解不够,刚接触。以前有用过STM32F103C8T6的USB,但是是用库实现的,对USB的详细过程理解得不透。


WCHTech2 发表于 2021-4-22 09:33

本帖最后由 WCHTech2 于 2021-4-22 09:37 编辑

您好,发送和接收见中断函数

,一包数据超过32字节的话需要拆包发送

qqtfh 发表于 2021-4-22 15:05

WCHTech2 发表于 2021-4-22 09:33
您好,发送和接收见中断函数

,一包数据超过32字节的话需要拆包发送

谢谢您,每次问问题都能得到准确的回复。感觉真好。

qqtfh 发表于 2021-4-25 23:10

WCHTech2 发表于 2021-4-22 09:33
您好,发送和接收见中断函数

,一包数据超过32字节的话需要拆包发送

可否结合这个例子,写个简单的发送接收的代码吗?

WCHTech2 发表于 2021-4-26 09:37

qqtfh 发表于 2021-4-25 23:10
可否结合这个例子,写个简单的发送接收的代码吗?

这个就是接收和发送的例子,看代码:

例程中就是将接收到的数据取反上传回去。Ep2Buffer前64字节是上传的数据缓存区,后64字节是接收数据缓存区。
上传数据是只需将数据准备好,置ACK即可。

qqtfh 发表于 2021-4-26 11:22

WCHTech2 发表于 2021-4-26 09:37
这个就是接收和发送的例子,看代码:

例程中就是将接收到的数据取反上传回去。Ep2Buffer前64字节是上传 ...

case UIS_TOKEN_OUT | 2:                                                 //endpoint 2# 端点批量下传
            if ( U_TOG_OK )                                                   // 不同步的数据包将丢弃
            {
               /* len = sendLen;                                             //接收数据长度,数据从Ep2Buffer首地址开始存放
                for ( i = 0; i < len; i ++ )
                {
                  Ep2Buffer = Ep2Buffer;         // OUT数据取反到IN由计算机验证
                }*/
                UEP2_T_LEN = sendLen;
                UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;       // 允许上传
            }
改成这样
然后调用是
USB_INT_ST|=2;
memcpy( Ep2Buffer, SendBuf+i*32, sendLen);
while(!U_TOG_OK)_delay_ms(1);
然而没有反应。

慢动作 发表于 2021-4-30 21:51

这算简单的发送接收的代码吗?
页: [1]
查看完整版本: 请教CH552模拟CH340的参考程序是如何发送和接收的。