[APM32E1]基于APM32E103的USB Printer实现

目前官方SDKUSB设备例程“APM32E10x_EVAL_SDK_v1.0”只有这几个,分别是:

CDC 虚拟串口 “USB_CDC_VirtualCOMPort”

HID  鼠标 “USB_HID_Mouse”

MCS 大容量存储 “USB_MSC_Disk”

上面是没有Printer类的,如果需要打印机类,可以在CDC例程的基础上进行修改,只需要几步就可以实现一个USB的打印机设备。

1USB打印机类的基础知识

1.1USB的设备类

常见的USB设备类有以下几种,这里要实现就是07h号打印机类。


1.2、调试USB的工具软件

USB数据抓包软件 “Bus Hound”

枚举信息查看软件 “USBlyzer”

1.3、推荐几个关于USB的基础知识的网站

https://www.usbzh.com/article/detail-344.html

http://usb.baiheee.com/

1.4 USB标准组织官网USB-IF上的资料

关于USB 2.0资料:

https://www.usb.org/document-library/usb-20-specification

关于 Printer Device Class 的文档:

https://www.usb.org/document-library/printer-device-class-document-11

2、修改描述符

首先要通过修改描述符,来枚举出打印支持设备。

在极海官网下载USBSDK

https://www.geehy.com/support/apm32?id=305

APM32E10x_EVAL_SDK_v1.0.zip

注释掉不用的代码,例如LCDKEYLED,这些跟USB无关。

2.1 描述符的基础知识

描述符分为:

设备描述符 Device Descriptor           (g_usbDeviceDescriptor)

配置描述符 Configuration Descriptor (g_usbConfigDescriptor)

端点描述符 Endpoint Descriptor       (g_usbConfigDescriptor)

详细信息可以看这里:

http://usb.baiheee.com/usb_article/usb_spec/usb_cmd_desc.html

2.2 修改设备描述符

打开源文件 ..\..\Source\usbd_descriptor.c ,修改数组 g_usbDeviceDescriptor[]

这里只要把设备类从CDC 0x02 改为Printer 0x07

复制

/** bDeviceClass */
 

    0x07, //0x02,

2.3 修改配置描述符和端点描述符

配置描述符和端点描述符都在数组 g_usbConfigDescriptor[] 中,我们只需要1个配置,该配置下有2个端点,删除多余的端点,修改成下面这样。

复制

const uint8_t g_usbConfigDescriptor[USB_CONFIG_DESCRIPTOR_SIZE] =
 

{
 

    /** bLength */
 

    0x09,
 

    /** bDescriptorType */
 

    USBD_DESC_CONFIGURATION,
 

    /** wTotalLength */
 

    USB_CONFIG_DESCRIPTOR_SIZE & 0xFF, USB_CONFIG_DESCRIPTOR_SIZE >> 8,
 


 

    /** bNumInterfaces */
 

    0x01,//0x02,
 

    /** bConfigurationValue */
 

    0x01,
 

    /** iConfiguration */
 

    0x00,
 

    /** bmAttributes */
 

    0xC0,
 

    /** MaxPower */
 

    0x32,
 


 

    /** bLength */
 

    0x09,
 

    /** bDescriptorType */
 

    USBD_DESC_INTERFACE,
 

    /** bInterfaceNumber */
 

    0x00, //0x01,
 

    /** bAlternateSetting */
 

    0x00,
 

    /** bNumEndpoints */
 

    0x02, //0x01,
 

    /** bInterfaceClass */
 

    0x07,//0x02,
 

    /** bInterfaceSubClass */
 

    0x01, //0x02,
 

    /** bInterfaceProtocol */
 

    0x01, //0x01,
 

    /** iInterface */
 

    0x00,
 


 

    0x07,     /** bLength: Endpoint Descriptor size */
 

    USBD_DESC_ENDPOINT,  /** bDescriptorType: Endpoint */
 

    0x01, /** bEndpointAddress */
 

    0x02, /** bmAttributes: Bulk */   
 

    0x40,0x00, /** wMaxPacketSize: */
 

    0x00, /** bInterval: */
 

               
 

    0x07,     /** bLength: Endpoint Descriptor size */
 

    USBD_DESC_ENDPOINT,  /** bDescriptorType: Endpoint */
 

    0x81, /** bEndpointAddress */
 

    0x02, /** bmAttributes: Bulk */   
 

    0x40,0x00, /** wMaxPacketSize: */
 

    0x00 /** bInterval: */
 

};

2.4 测试是否枚举成功
修改完描述符后,运行程序,拔插USB,设备管理器中会出现打印支持,使用“USBlyzer”可以看到详细的枚举信息。 
3 实现类特殊请求
3.1 添加GET_DEVICE_ID请求
DEVICE ID是打印机类特有的类请求,关系到打印机驱动的安装, 官方文档“usbprint11a021811.pdf”中有对这个的详细描




通过修改“usbd_class_cdc.c” 文件中的 “void USBD_ClassHandler()”函数来实现。

复制

void USBD_ClassHandler(USBD_DevReqData_T* reqData)
 

{
 

    uint16_t length = ((uint16_t)reqData->byte.wLength[1] << 8) | \
 

                     reqData->byte.wLength[0] ;
 

 
 

                 switch (reqData->byte.bRequest)
 

                 {
 

                               case 0x00:  //GET_DEVICE_ID
 

                                USBD_CtrlInData(PRINTER_DEVICE_ID, sizeof(PRINTER_DEVICE_ID));   
 

                                break;
 

                                
 

                                case 0x01:  //GET_PORT_STATUS
 

                                USBD_CtrlOutData(&g_port_status, 1);  
 

                                break;
 

                                
 

                                case 0x02:  //SOFT_RESET
 

                                USBD_CtrlInData(cmdBuf, length);   
 

                                break;
 

                 
 

         }
 

}
 

3.2 抓包观察请求是否成功

拔插USB,通过软件“Bus Hound”可以看到USB主机发送了 GET_DEVICE_ID 请求,然后USB设备也返回了对应的字符串。

4、实现数据的接收
4.1 OUT端点中保存接收到的数据包
USB OUT端点处理函数进行数据的接收操作,在文件 “usbd_class_cdc.c”中的 “void USBD_VCP_OutEpCallback()” 函数中添加代码。

复制

void USBD_VCP_OutEpCallback(uint8_t ep)
 

{
 

    uint32_t dataCnt;
 


 

    if (ep == USBD_EP_1)
 

    {
 

                         dataCnt = g_usbDev.outBuf[USBD_EP_1].xferCnt;
 

 
 

                          PrinterReceiveCount = dataCnt;
 

                          memcpy(PrinterReceiveData,dataBuf,dataCnt);  //保存接收到的这包数据
 

                        
 

                          USBD_RxData(USBD_EP_1, dataBuf, g_usbDev.outBuf[USBD_EP_1].maxPackSize);         //如果想接收下一包,须加这个        
 

                          //USBD_TxData(USBD_EP_1, dataBuf, dataCnt);
 

    }
 

}


4.2 测试数据接收功能
为了方便查看接收到的数据,在while(1)中把接收到的数据通过串口发送出去。

复制

int main(void)
 

{
 

    APM_EVAL_Init();
 

    printf("This is an example of USB Printer \r\n");
 

        
 

    while(1)
 

    {
 

           if(PrinterReceiveCount>0)
 

            {  
 

                for(unsigned char i=0;i<PrinterReceiveCount;i++)
 

               {                                
 

                          USART_TxData(DEBUG_USART,PrinterReceiveData[i]);
 

                          while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);
 

               }
 

               PrinterReceiveCount=0;
 

          }
 

                        
 

    }
 

}

通过USB发送数据需要一个上位机,这里使用条码打印机调试助手,插上USB后,通讯端口选择USB,然后打开端口,
在数据发送框输入想发的数据,然后点右下角发送数据,这时可以在串口调试助手上看到MCU刚接收的数据。
如下图所示,每次USB接收到的数据都通过串口发送出来了。

---------------------
作者:shanyuxiang
链接:https://bbs.21ic.com/icview-3331288-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值