CH375精简程序
ch375中文资料
对USB接口芯片CH375的功能、原理做了较详细的介绍,并给出了在单片机读写U盘中的实例及注意事项。
随着计算机技术的快速发展,USB移动存储设备的使用已经非常普遍,因此在一些需要转存数据的设备、仪器上使用USB移动存储设备接口的芯片便相继产生了,CH375就是其中之一,它是一个USB总线的通用接口芯片,支持HOST主机方式和SLAVE设备方式。
在本地端,CH375具有8位数据总线和读、写、片选控制线以及中断输出,可以方便地挂接到单片机/DS P/MCU等控制器的系统总线上。
在USB主机方式下,CH375还提供了串行通信方式,通过串行输入、串行输出和中断输出与单片机/DSP/MCU等相连接。
CH375的USB主机方式支持各种常用的USB全速设备,外部单片机/DSP/MCU可以通过CH375按照相应的USB协议与USB设备通信。
CH375芯片内部结构1 内部结构CH375芯片内部集成了PLL倍频器、主从USB接口SIE、数据缓冲区、被动并行接口、异步串行接口、命令解释器、控制传输的协议处理器、通用的固件程序等。
CH375芯片引脚排列如图1所示。
2 内部物理端点CH375芯片内部具有7个物理端点。
端点0 是默认端点,支持上传和下传,上传和下传缓冲区各是8B;端点1包括上传端点和下传端点,上传和下传缓冲区各是8B,上传端点的端点号是81H,下传端点的端点号是01H;端点2包括上传端点和下传端点,上传和下传缓冲区各是64B,上传端点的端点号是82H,下传端点的端点号是02H。
主机端点包括输出端点和输入端点,输出和输入缓冲区各是64B,主机端点与端点2合用同一组缓冲区,主机端点的输出缓冲区就是端点2的上传缓冲区,主机端点的输入缓冲区就是端点2的下传缓冲区。
其中,CH375的端点0、端点1、端点2只用于USB设备方式,在USB主机方式下只需要用到主机端点。
软件接口对于USB存储设备的应用,CH375直接提供了数据块的读写接口,以512b的物理扇区为基本读写单位,从而将USB存储设备简化为一种外部数据存储器,单片机可以自由读写USB存储设备中的数据,也可以自由定义其数据结构。
CH375 Code
CH375作为USB主机接口的程序示例****************************************** USB 1.1 Host Examples for CH375 **** KC7.0@MCS-51 *******************************************//* CH375作为USB主机接口的程序示例 *//* MCS-51单片机C语言的示例程序, U盘数据读写 */#include "common.h"unsigned char volatile xdata CH375_CMD_PORT _at_ 0xBDF1; /* CH375命令端口的I/O地址 */ unsigned char volatile xdata CH375_DAT_PORT _at_ 0xBCF0; /* CH375数据端口的I/O地址 */ extern unsigned char xdata DBUF[BUFFER_LENGTH];//sbit LED_OUT = 0x90^4; /* P1.4 低电平驱动LED显示,用于监控演示程序的进度 */sbit CH375_INT_WIRE = 0xB0^2; /* P3.2, INT0, 连接CH375的INT#引脚,用于查询中断状态 */ #define mDelay1uS( ) /* 对于MCS51单片机,通常不需要1uS延时 *//* 延时2微秒,请根据单片机速度 *///void mDelay1uS( )//{// unsigned char i;// for ( i = 1; i != 0; i -- );//}/* 延时2微秒,请根据单片机速度 */void mDelay2uS( ){unsigned char i;for ( i = 2; i != 0; i -- );}/* 向CH375命令端口写命令数据 */void CH375_CMD_PORT_d_out( INT8 d_out ){mDelay1uS( );CH375_CMD_PORT=d_out;mDelay2uS( ); /* 至少延时2uS */}/* 向CH375数据端口写数据 */void CH375_DAT_PORT_d_out( INT8 d_out ){CH375_DAT_PORT=d_out;mDelay1uS( );}/* 从CH375命令端口读数据 */INT8 CH375_DAT_PORT_in( ){mDelay1uS( );return( CH375_DAT_PORT );}/* 延时毫秒,不精确 */void DelayMs(unsigned char nFactor){unsigned char i;unsigned int j;for(i=0; i<nFactor; i++) for(j=0;j<1000;j++) j=j; }/* 等待CH375中断并获取状态 */unsigned char mWaitInterrupt( ){unsigned char c;while ( CH375_INT_WIRE ); /* 如果CH375的中断引脚输出高电平则等待 */CH375_CMD_PORT_d_out( CMD_GET_STATUS); /* 获取当前中断状态 */c = CH375_DAT_PORT_in(); /* 返回中断状态 *//* if ( c == USB_INT_DISCONNECT ) /* 检测到USB设备断开事件 *//* else if ( c == USB_INT_CONNECT ) /* 检测到USB设备连接事件 */return( c );}/* 设置CH375为USB主机方式 */unsigned char mCH375Init( ){unsigned char i;#ifdef TEST_CH375_PORTunsigned char c;CH375_CMD_PORT_d_out(CMD_CHECK_EXIST); /* 测试工作状态 */CH375_DAT_PORT_d_out( 0x55); /* 测试数据 */c = CH375_DAT_PORT_in(); /* 返回数据应该是测试数据取反 */if ( c != 0xaa ) { /* CH375出错 */for ( i = 100; i != 0; i -- ) { /* 强制数据同步 */CH375_CMD_PORT_d_out( CMD_RESET_ALL ); /* CH375执行硬件复位 */c = CH375_DAT_PORT_in(); /* 延时 */}DelayMs( 50 ); /* 延时至少30mS */}#endifCH375_CMD_PORT_d_out( CMD_SET_USB_MODE); /* 设置USB工作模式 */CH375_DAT_PORT_d_out( 6); /* 模式代码,自动检测USB设备连接 */for ( i = 0xff; i != 0; i -- ) { /* 等待操作成功,通常需要等待10uS-20uS */if ( CH375_DAT_PORT_in() == CMD_RET_SUCCESS ) break; /* 操作成功 */}if ( i != 0 ) return( 0 ); /* 操作成功 */else return( 0xff ); /* CH375出错,例如芯片型号错或者处于串口方式或者不支持 */ }/* 初始化磁盘 */unsigned char mInitDisk( ){unsigned char mIntStatus;CH375_CMD_PORT_d_out( CMD_DISK_INIT); /* 初始化USB存储器 */mIntStatus = mWaitInterrupt( ); /* 等待中断并获取状态 *///if ( mIntStatus == USB_INT_SUCCESS ) return( 0 ); /* U盘已经成功初始化 */return mIntStatus ; /* 出现错误 */}unsigned char ReadCapacity(void){unsigned char *mBufferPoint;unsigned char mIntStatus,mLength;CH375_CMD_PORT_d_out( CMD_DISK_SIZE); /* 读取容量 */mBufferPoint=DBUF;mIntStatus = mWaitInterrupt( );if ( mIntStatus == USB_INT_DISK_READ ){ /* USB存储器读数据块,请求数据读出 */CH375_CMD_PORT_d_out( CMD_RD_USB_DATA); /* 从CH375缓冲区读取数据块 */mLength = CH375_DAT_PORT_in(); /* 后续数据的长度 */while ( mLength ) { /* 根据长度读取数据 */*mBufferPoint = CH375_DAT_PORT_in(); /* 读出数据并保存 */mBufferPoint ++;mLength --;}return 1;}}unsigned long SwapINT32(unsigned long dData){dData = (dData&0xff)<<24|(dData&0xff00)<<8|(dData&0xff000000)>>24|(dData&0xff0000)>>8; return dData;}unsigned int SwapINT16(unsigned int dData){dData = (dData&0xff00)>>8|(dData&0x00ff)<<8;return dData;}/* 从U盘中读取多个扇区的数据块到缓冲区中 */unsigned char RBC_Read(unsigned long iLbaStart, unsigned char iSectorCount,unsigned char *mB ufferPoint)/* iLbaStart 是读取的线起始性扇区号, iSectorCount 是读取的扇区数 */{unsigned char mIntStatus;unsigned int mBlockCount;unsigned char mLength;CH375_CMD_PORT_d_out(CMD_DISK_READ); /* 从USB存储器读数据块 */CH375_DAT_PORT_d_out((unsigned char)iLbaStart); /* LBA的最低8位 */CH375_DAT_PORT_d_out ((unsigned char)( iLbaStart >> 8 ));CH375_DAT_PORT_d_out((unsigned char)( iLbaStart >> 16 ));CH375_DAT_PORT_d_out((unsigned char)( iLbaStart >> 24 )); /* LBA的最高8位 */CH375_DAT_PORT_d_out( iSectorCount); /* 扇区数 */// mBufferPoint = &DATA_BUFFER; /* 指向缓冲区起始地址 */for ( mBlockCount = iSectorCount * CH375_BLK_PER_SEC; mBlockCount != 0; mBlockCount -- ) { /* 数据块计数 */mIntStatus = mWaitInterrupt( ); /* 等待中断并获取状态 */if ( mIntStatus == USB_INT_DISK_READ ) { /* USB存储器读数据块,请求数据读出 */CH375_CMD_PORT_d_out(CMD_RD_USB_DATA); /* 从CH375缓冲区读取数据块 */mLength = CH375_DAT_PORT_in(); /* 后续数据的长度 *//* 通常数据长度是64,有些U盘要求单片机必须在2mS之内取走64字节数据,否则U盘可能数据丢失 */ /* 建议优化下面的循环程序,确保单片机在1mS之内完成64字节的数据传输 */if ( mLength ) { /* 根据长度读取数据 */do { // 对于C51,这个DO+WHILE结构效率高,速度快*mBufferPoint = CH375_DAT_PORT_in(); /* 读出数据并保存 */mBufferPoint ++;} while ( -- mLength );}CH375_CMD_PORT_d_out( CMD_DISK_RD_GO); /* 继续执行USB存储器的读操作 */}else break; /* 返回错误状态 */}if ( mBlockCount == 0 ) mIntStatus = mWaitInterrupt( ); /* 等待中断并获取状态 */if ( mIntStatus == USB_INT_SUCCESS ) return 1; /* 操作成功 */else return 0; /* 操作失败 */}TPBLK_STRUC idata TPBulk_Block;#define TPBulk_CBW TPBulk_Block.TPBulk_CommandBlock#define CBW_wXferLen TPBulk_CBW.dCBW_DataXferLen#define RBC_CDB TPBulk_CBW.cdbRBC#define RBC_LUN TPBulk_CBW.bCBW_LUN#define TPBulk_CSW TPBulk_Block.TPBulk_CommandStatus/*unsigned char TPBulk_GetMaxLUN(void){usbstack.setup.bmRequest=0xa1;usbstack.setup.bRequest=0xfe;usbstack.setup.wValue=0;usbstack.setup.wIndex=0;usbstack.setup.wLength=1;usbstack.buffer=DBUF;return ep0Xfer();}*//*unsigned char SPC_READLONG(void){#define cdbReadLong RBC_CDB.SpcCdb_ReadLong//nsigned char retStatus=FALSE;TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;TPBulk_CBW.dCBW_Tag=0x60a624de;TPBulk_CBW.dCBW_DataXferLen=0xfc000000;TPBulk_CBW.bCBW_Flag=0x80;TPBulk_CBW.bCBW_LUN=0;TPBulk_CBW.bCBW_CDBLen=sizeof(READ_LONG_CMD);/////////////////////////////////////cdbReadLong.OperationCode=SPC_CMD_READLONG;cdbReadLong.LogicalUnitNum=0;cdbReadLong.AllocationLen=0xfc;//////////////////////////////////////if(!epBulkSend((unsigned char *)&TPBulk_CBW,sizeof(TPBulk_CBW))) return FALSE;if(!epBulkRcv(DBUF,0xfc))return FALSE;if(!epBulkRcv((unsigned char *)&TPBulk_CSW,13))return FALSE;////////////////////////////return TRUE;#undef cdbReadLong}*//*unsigned char SPC_RequestSense(void){#define cdbRequestSenseSPC RBC_CDB.SpcCdb_RequestSense//unsigned char retStatus=FALSE;TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;TPBulk_CBW.dCBW_Tag=0x60a624de;TPBulk_CBW.dCBW_DataXferLen=0x0e000000;TPBulk_CBW.bCBW_Flag=0x80;TPBulk_CBW.bCBW_LUN=0;TPBulk_CBW.bCBW_CDBLen=sizeof(REQUEST_SENSE_SPC);/////////////////////////////////////cdbRequestSenseSPC.OperationCode=SPC_CMD_REQUESTSENSE; cdbRequestSenseSPC.AllocationLen=0x0e;//////////////////////////////////////if(!epBulkSend((unsigned char *)&TPBulk_CBW,sizeof(TPBulk_CBW))) return FALSE;if(!epBulkRcv(DBUF,18))return FALSE;if(!epBulkRcv((unsigned char *)&TPBulk_CSW,13))return FALSE;/////////////////////////////return TRUE;#undef cdbRequestSenseSPC}*/unsigned char SPC_TestUnit(void){#define cdbTestUnit RBC_CDB.SpcCdb_TestUnit//unsigned char retStatus=FALSE;TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;TPBulk_CBW.dCBW_Tag=0x60a624de;TPBulk_CBW.dCBW_DataXferLen=0x00000000;TPBulk_CBW.bCBW_Flag=0x00;TPBulk_CBW.bCBW_LUN=0;TPBulk_CBW.bCBW_CDBLen=sizeof(TEST_UNIT_SPC);/////////////////////////////////////cdbTestUnit.OperationCode=SPC_CMD_TESTUNITREADY;//////////////////////////////////////if(!epBulkSend((unsigned char *)&TPBulk_CBW,sizeof(TPBulk_CBW))) return FALSE;if(!epBulkRcv((unsigned char *)&TPBulk_CSW,13))return FALSE;#undef cdbTestUnit////////////////////////////return TRUE;}unsigned char SPC_LockMedia(void){#define cdbLockSPC RBC_CDB.SpcCdb_Remove//unsigned char retStatus=FALSE;TPBulk_CBW.dCBW_Signature=CBW_SIGNATURE;TPBulk_CBW.dCBW_Tag=0x60a624de;TPBulk_CBW.dCBW_DataXferLen=0x00000000;TPBulk_CBW.bCBW_Flag=0x00;TPBulk_CBW.bCBW_LUN=0;TPBulk_CBW.bCBW_CDBLen=sizeof(MEDIA_REMOVAL_SPC);///////////////////////////////////////////cdbLockSPC.OperationCode=SPC_CMD_PRVENTALLOWMEDIUMREMOVAL; cdbLockSPC.Prevent=1;///////////////////////////////////////////if(!epBulkSend((unsigned char *)&TPBulk_CBW,sizeof(TPBulk_CBW))) return FALSE;if(!epBulkRcv((unsigned char *)&TPBulk_CSW,13))return FALSE;#undef cdbLockSPC/////////////////////////////return TRUE;}。
USB接口芯片CH375的原理及应用
USB接口芯片CH375的原理及应用CH375是一款USB接口芯片,由深圳迅瞳科技有限公司开发。
它的主要功能是实现USB主机设备与外部设备的通信,并提供了一系列的接口和功能,使得用户可以方便地进行USB相关的开发工作。
本文将详细介绍CH375芯片的工作原理和应用。
一、CH375芯片的工作原理CH375芯片是一款集成了USB控制器和数据存储器的单芯片解决方案,它可以通过片内的USB控制器与外部USB设备进行数据传输。
CH375芯片的工作流程如下:1.初始化:通过片内的控制寄存器进行初始化设置,包括设置USB速度、端点地址、传输模式等。
2.数据传输:CH375芯片通过USB总线与外部USB设备进行通信,可以实现数据的读写操作。
在读取数据时,CH375芯片从外部设备的缓冲区读取数据并存储到片内的数据存储器中,用户可以通过读取存储器中的数据来获取外部设备传输的数据。
在写入数据时,用户将数据写入到片内的数据存储器中,CH375芯片将数据传输到外部设备的缓冲区。
3.中断处理:CH375芯片支持中断,当数据传输完成时,芯片会触发中断信号,通知主控器处理数据。
用户可以通过中断处理程序来处理中断,并进行相应的操作。
4.错误处理:CH375芯片还提供了错误处理机制,可以监测和处理传输过程中的错误,如数据包出错、超时等。
二、CH375芯片的应用CH375芯片广泛应用于USB接口模块、USB通信模块、USB存储器接口、USB打印模块等领域。
下面将详细介绍CH375芯片的应用案例:B接口模块:CH375芯片可以实现将串口等其他接口转换为USB 接口,方便用户将不同接口的设备接入到计算机中。
例如,通过将CH375芯片和串口芯片相连,可以将串口设备转换为USB设备,实现串口设备的USB连接。
B通信模块:CH375芯片还可以实现USB主机设备与外部USB设备之间的通信。
例如,用户可以将CH375芯片与单片机相连,通过编写相应的程序实现单片机与计算机之间的数据传输。
USB协议以及CH375简介
• USB数据传输方式 • USB 采用轮询的广播机制传输数据,所有 的传输都由主机发起,任何时刻整个 USB 体系内仅允许一个数据包的传输,即不同 物理传输线上看到的数据包都是同一被广 播的数据包。 • USB 采用“令牌包”-“数据包”-“握手包” 的传输机制,在令牌包中指定数据包去向 或者来源的设备地址和端点(Endpoint), 从而保证了只有一个设备对被广播的数据 包/令牌包作出响应,“握手包”表示了传 输的成功与否。
OTG全称是一键拷贝(USB On-The-Go)
LOOK的商标,它采用USB2.O的传输接口,OTG(USB On-The-Go)是2001年公布传输协议,让两个USB设备 可以不需要用电脑作为HOST,也可以点对点的进行数据 的传输。 USB OTG:USB 的 OTG 规格 (USB On-The-Go)是指: USB 的 OTG 规格是 USB2.0 规格的补充。USB 使用客 服结构。USB OTG 产品能够相互进行通讯,而无需连接 到 PC 机上。因此可把一个 USB 设备可作为一个主机, 而其他的则可作为终端。只有 USB 主机可以包含设备驱 动器和数据传输的一些必要的操控。例如,一个数码摄像 机可以连接一个 PDA,或是手机可以连接到打印机或扫 描仪中,其只要这些所有的设备可与 USB OTG 兼容。当 作为家庭网路中的 PC 为中心的时代已远离,通过使用便 携式设备进行相互交流的需求日益增加,USB OTG 产品 便应运而生。
• 管道(Pipe)是主机和设备端点之间数据传输的 模型,共有两种类型的管道:无格式的流管道 (Stream Pipe)和有格式的信息管道(Message Pipe)。任何 USB 设备一旦上电就存在一个信息 管道,即默认的控制管道,USB 主机通过该管道 来获取设备的描述、配置、状态,并对设备进行 配置。 • USB 设备连接到HOST 时,HOST 必须通过默认 的控制管道对其进行枚举,完成获得其设备描述、 进行地址分配、获得其配置描述、进行配置等操 作方可正常使用。USB 设备的即插即用特性即依 赖于此。
基于CH375的USB数据采集应用程序
基于CH375的USB数据采集应用程序摘要利用USB接口技术,采用USB模块CH375与AT89C81结合,实现与计算机通信。
给出了CH375与单片机接口电路的原理简图,并详细介绍了实现USB数据传输的上位机的程序设计。
关键词:USB,CH375,AT89C51,上位机一、CH375模块简介USB模块CH375是一个USB总线的通用设备接口芯片,用户无需编写驱动程序,内置有USB通讯中的底层协议,完全满足USB1.1标准。
具有8位数据总线(D0~D7)、地址输入(A0)、读(RD#)、写(WR#)、片选控制线(CS#)以及中断输出(INT#),可以方便地挂接到单片机的数据总线上。
当A0为低电平时选择数据端口,单片机通过8位并口对CH375进行读写数据;为高电平时选择命令端口,可以向其写入命令。
在本地端,单片机对CH375的操作是采用命令加数据的I/O操作方式,任何操作都是先发命令给CH375,然后执行数据输入输出。
CH375接收到上位机发送的数据或者发送完给上位机的数据后,以中断方式通知单片机,并进行相应处理。
将CH375芯片的驱动程序、动态链接库拷贝到上位机中,利用CH375动态链接库DLL 提供的API函数对其进行操作,对USB设备的通信就几乎和访问本地硬盘中的文件差不多了。
二、系统原理图CH375的数据总线直接与AT89C51的数据总路线P0口相连,中断输出INT#与AT89C51的外部中断INT1相连,RD#、WR#与A T89C51的RD、WR对应,片选A0及CS#分别接P2.0和P2.1。
接接线电路图如下:三、设计通信方案USB模块CH375在计算机应用层与其本地端单片机AT89C51之间提供了端对端的连接。
统一采用数据加应答方式进行通信,所有的通信都由计算机应用层发起,然后以接收到单片机的应答结束。
单一通道完整的通信过程包括:①计算机应用层按事先约定的格式将数据请求发送给CH375;②CH375以中断方式通知单片机。
CH375HF
USB-HOST芯片CH375的U盘文件级子程序库说明版本:2C1、概述很多数码产品以及单片机系统都需要存储器,当前,U盘(含闪盘、USB闪存盘、USB移动硬盘等,下同)已经成为很常用的移动存储设备,其价格仅比相同容量的闪存略高,而远比闪存易于采购和易于携带,并且U盘的规格通用,具有多种容量可供选用。
所以,数码产品以及单片机系统可以直接采用U盘作为大容量的移动存储器。
CH375是USB总线的HOST主机及DEVICE设备双用接口芯片,单片机可以通过CH375读写U盘中的数据,由于很多产品最终会与使用WINDOWS操作系统的个人计算机交换数据,所以为了方便数据交换,U盘中的数据应该符合WINDOWS的文件系统格式。
CH375提供了U盘文件级子程序库,单片机可以直接调用子程序读写U盘中的文件数据,硬件上只需要在原单片机系统中增加一个CH375芯片,综合成本较低。
CH375的U盘文件级子程序库支持常用的FAT12、FAT16和FAT32文件系统,支持U盘最大容量100GB。
单片机不需要考虑文件系统,只需要了解文件名、文件长度等基础知识。
一个U盘中可以有多个文件,每个文件都是一组数据的集合,以文件名区分和识别。
文件长度是指文件中有效数据的长度,而实际占用的磁盘空间通常大于或者等于文件长度,实际文件数据的存放可能不是连续的,而是通过一组“指针”链接的多个块(也就是分配单元或簇),从而能够根据需要随时增大文件长度以容纳更多数据。
目录是为了便于分类管理,管理者可以人为指定将多个文件归档在一起,例如2004年的文件归到一个目录中。
2、子程序库分类子程序库有两种文件路径表示方式,一种是完整全路径,另一种是逐级路径。
目前子程序库主要使用“完整全路径”方式,而普及版源程序的方式是“逐级路径”。
子程序库按功能分为三个版本:简易版,支持FAT12和FAT16文件系统,只支持读文件,不支持新建和写文件。
标准版,支持FAT12和FAT16文件系统,支持文件读写、删除和新建等。
CH375做HOST的程序
CH375做HOST的程序(C51)CH375做HOST的程序(C51)作者:佚名文章来源:佚名点击数:更新时间:2006-5-9共享某网友CH375做HOST的程序,暂时可以和slaver通讯/***************************************** USB 1.1 Host for CH375 **** 单片机用89C51 ******************************************//* 如果设备端不是CH37X,那么分析描述符 *//* CH375中断为查询方式 */#include <string.h>#include <stdio.h>#include <intrins.h>#include <reg51.h>#include "CH375INC.H"#define DELAY_START_value 1 /* 根据单片机的时钟选择延时初值 */#define UNKNOWN_USB_DEVICE 0xF1#define USB_INT_RET_NAK 0x2A /* 00101010B,返回NAK */typedef struct _USB_DEVICE_DESCRIPTOR {unsigned char bLength;unsigned char bDescriptorType;unsigned short bcdUSB;unsigned char bDeviceClass;unsigned char bDeviceSubClass;unsigned char bDeviceProtocol;unsigned char bMaxPacketSize0;unsigned short idVendor;unsigned short idProduct;unsigned short bcdDevice;unsigned char iManufacturer;unsigned char iProduct;unsigned char iSerialNumber;unsigned char bNumConfigurations;} USB_DEV_DESCR, *PUSB_DEV_DESCR;typedef struct _USB_CONFIG_DESCRIPTOR {unsigned char bLength;unsigned char bDescriptorType;unsigned short wTotalLength;unsigned char bNumInterfaces;unsigned char bConfigurationvalue;unsigned char iConfiguration;unsigned char bmAttributes;unsigned char MaxPower;} USB_CFG_DESCR, *PUSB_CFG_DESCR;typedef struct _USB_INTERF_DESCRIPTOR {unsigned char bLength;unsigned char bDescriptorType;unsigned char bInterfaceNumber;unsigned char bAlternateSetting;unsigned char bNumEndpoints;unsigned char bInterfaceClass;unsigned char bInterfaceSubClass;unsigned char bInterfaceProtocol;unsigned char iInterface;} USB_ITF_DESCR, *PUSB_ITF_DESCR;typedef struct _USB_ENDPOINT_DESCRIPTOR {unsigned char bLength;unsigned char bDescriptorType;unsigned char bEndpointAddress;unsigned char bmAttributes;unsigned short wMaxPacketSize;unsigned char bInterval;} USB_ENDP_DESCR, *PUSB_ENDP_DESCR;typedef struct _USB_CONFIG_DESCRIPTOR_LONG {USB_CFG_DESCR cfg_descr;USB_ITF_DESCR itf_descr;USB_ENDP_DESCR endp_descr[4];} USB_CFG_DESCR_LONG, *PUSB_CFG_DESCR_LONG;unsigned char RECV_LEN; /* 刚接收到的数据的长度 */unsigned char idata RECV_BUFFER[ CH375_MAX_DATA_LEN ]; /* 数据缓冲区,用于保存接收到的下传数据,长度为0到64字节 */unsigned char idata *cmd_buf;unsigned char idata *ret_buf;#define p_dev_descr ((PUSB_DEV_DESCR)RECV_BUFFER)#define p_cfg_descr ((PUSB_CFG_DESCR_LONG)RECV_BUFFER)unsigned char endp_out_addr; /* USB数据接收端点的端点地址 */ unsigned char endp_out_size; /* USB数据接收端点的端点尺寸 */ unsigned char endp_in_addr; /* USB状态发送端点的端点地址,为0则只支持单向接口 */unsigned char endp6_mode, endp7_mode;/*Ch375与51等的连接CH375 51D0 P1.0. .. .. .D7 P1.7A0 P3.7RD P3.5WR P3.4CS 接地INT P3.2(int0)*/#define CH375_DATA_PORT P1 /* CH375端口的I/O地址 */sbit CH375_CMD_DAT = P3^7; /* CH375地址线输入A0,A0=1时写命令,A0=0时读写数据 */sbit CH375_RD = P3^5; /* CH375读选通输入,低电平有效 */sbit CH375_WR = P3^4; /* CH375写选通输入,低电平有效 */sbit led = P3^3; /* 指示灯 */sbit CH375_INT_WIRE = P3^2; /* CH375中断请求输出,低电平有效 */void delay50ms(void);void delay1s(void);void flash_led(void);void CH375_WR_CMD_PORT( unsigned char cmd );void CH375_WR_DAT_PORT( unsigned char dat );unsigned char CH375_RD_DAT_PORT(void);unsigned char wait_interrupt(void);void set_usb_mode( unsigned char mode );void toggle_recv(void);void toggle_send(void);unsigned char clr_stall6( void);unsigned char clr_stall7( void);unsigned char rd_usb_data( unsigned char *buf );void wr_usb_data( unsigned char len, unsigned char *buf );unsigned char issue_token( unsigned char endp_and_pid );void host_send( unsigned char len, unsigned char *buf );unsigned char host_recv( unsigned char *buf ); unsigned char get_descr( unsigned char type ); unsigned char set_addr( unsigned char addr ); unsigned char set_config( unsigned char cfg ); void CH375_Init( void );unsigned char init_USB_device(void);void ComInit(void);void SendChar(unsigned char buff);//void SendChars( unsigned char *buff );void delay2us(void){unsigned char i;for ( i=DELAY_START_value*2+1; i!=0; i-- );}void delay50ms(void){unsigned char i, j;for( i=100; i!=0; i-- )for( j=250; j!=0; j-- );}void delay1s(void){unsigned char i,j,k;for( i=10; i!=0; i-- )for( j=200; j!=0; j-- )for( k=250; k!=0; k-- );}void flash_led(void){unsigned char i;for( i=10;i>0;i-- ){led=!led;delay1s();}}/* 与CH372/CH375有关的基本I/O操作 *//* 向CH375的命令端口写入命令,周期不小于4uS,如果单片机较快则延时 */ void CH375_WR_CMD_PORT( unsigned char cmd ){_nop_();_nop_();CH375_CMD_DAT = 1; /* 命令 */CH375_DATA_PORT = cmd;CH375_RD = 1;CH375_WR = 0;_nop_();_nop_();CH375_WR = 1;CH375_CMD_DAT = 0;CH375_DATA_PORT = 0xFF;}/* 向CH375的数据端口写入数据,周期不小于1.5uS,如果单片机较快则延时 */ void CH375_WR_DAT_PORT( unsigned char dat ){_nop_();CH375_CMD_DAT = 0; /* 数据 */CH375_DATA_PORT = dat;CH375_RD = 1;CH375_WR = 0;_nop_();CH375_WR = 1;CH375_DATA_PORT = 0xFF;}/* 从CH375的数据端口读出数据,周期不小于1.5uS,如果单片机较快则延时 */ unsigned char CH375_RD_DAT_PORT(void){unsigned char rev_data;CH375_DATA_PORT = 0xFF;CH375_CMD_DAT = 0; /* 数据 */CH375_WR = 1;CH375_RD = 0;_nop_();rev_data = CH375_DATA_PORT;CH375_RD = 1;return( rev_data );}/* 主机端等待操作完成, 返回操作状态 */unsigned char wait_interrupt(void){CH375_INT_WIRE = 1;while( CH375_INT_WIRE ) /* 查询等待CH375操作完成中断(INT#低电平) */ {if( RI==1 ) /* 串口接收到数据 */{CH375_WR_CMD_PORT( CMD_ABORT_NAK ); /* 放弃当前操作 */return( 0xEF );}}CH375_WR_CMD_PORT( CMD_GET_STATUS ); /* 产生操作完成中断, 获取中断状态 */return( CH375_RD_DAT_PORT() );}/* 设置CH37X的工作模式 */void set_usb_mode( unsigned char mode ){unsigned char i;CH375_WR_CMD_PORT( CMD_SET_USB_MODE );CH375_WR_DAT_PORT( mode );endp6_mode=endp7_mode=0x80; /* 主机端复位USB数据同步标志 */for( i=100; i!=0; i-- ) /* 等待设置模式操作完成,不超过30uS */ {if( CH375_RD_DAT_PORT() == CMD_RET_SUCCESS )return; /* 成功 */}while(1){flash_led(); /* CH375出错 */}}/******************************************************************** ****************数据同步USB的数据同步通过切换DATA0和DATA1实现: 在设备端, USB设备可以自动切换;在主机端, 必须由SET_ENDP6和SET_ENDP7命令控制CH375切换DATA0与DA TA1.主机端的程序处理方法是为设备端的各个端点分别提供一个全局变量,初始值均为DATA0, 每执行一次成功事务后取反, 每执行一次失败事务后将其复位为DATA1********************************************************************* ****************/void toggle_recv(void) /* 主机接收成功后,切换DATA0和DATA1实现数据同步 */{CH375_WR_CMD_PORT( CMD_SET_ENDP6 );CH375_WR_DAT_PORT( endp6_mode );endp6_mode^=0x40;delay2us();}void toggle_send(void) /* 主机发送成功后,切换DATA0和DATA1实现数据同步 */{CH375_WR_CMD_PORT( CMD_SET_ENDP7 );CH375_WR_DAT_PORT( endp7_mode );endp7_mode^=0x40;delay2us();}unsigned char clr_stall6(void) /* 主机接收失败后,复位设备端的数据同步到DATA0 */{CH375_WR_CMD_PORT( CMD_CLR_STALL );CH375_WR_DAT_PORT( 2 0x80 ); /* 如果设备端不是CH37X芯片,那么需要修改端点号 */// CH375_WR_DAT_PORT( endp_out_addr 0x80 ); /* 如果设备端不是CH37X芯片,那么需要修改端点号 */endp6_mode=0x80;return( wait_interrupt() );}unsigned char clr_stall7(void) /* 主机发送失败后,复位设备端的数据同步到DATA0 */{CH375_WR_CMD_PORT( CMD_CLR_STALL );// CH375_WR_DAT_PORT( 2 ); /* 如果设备端不是CH37X芯片,那么需要修改端点号 */CH375_WR_DAT_PORT( endp_out_addr ); /* 如果设备端不是CH37X芯片,那么需要修改端点号 */endp7_mode=0x80;return( wait_interrupt() );}/* 数据读写, 单片机读写CH372或者CH375芯片中的数据缓冲区 */ unsigned char rd_usb_data( unsigned char *buf ) /* 从CH37X读出数据块 */{unsigned char len, length;CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从CH375的端点缓冲区读取接收到的数据 */len=CH375_RD_DAT_PORT(); /* 后续数据长度 */length=len;while( len-- ){*buf = CH375_RD_DAT_PORT();buf++;}return( length );}/* 向CH37X写入数据块 */void wr_usb_data( unsigned char len, unsigned char *buf ){CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); /* 向CH375的端点缓冲区写入准备发送的数据 */CH375_WR_DAT_PORT( len ); /* 后续数据长度, len不能大于64 */while( len-- ){CH375_WR_DAT_PORT( *buf );buf++;}}/* 主机操作 */unsigned char issue_token( unsigned char endp_and_pid ) /* 执行US B事务 */{unsigned char status;/* 执行完成后, 将产生中断通知单片机, 如果是USB_INT_SUCCESS就说明操作成功 */CH375_WR_CMD_PORT( CMD_ISSUE_TOKEN );CH375_WR_DAT_PORT( endp_and_pid ); /* 高4位目的端点号, 低4位令牌PID */status = wait_interrupt(); /* 等待CH375操作完成 */return( status );}void host_send( unsigned char len, unsigned char *buf ) /* 主机发送 */{unsigned char status;unsigned char length;led=1;while( len ) /* 连续输出数据块给USB设备 */{// length = len>endp_out_size?endp_out_size:len; /* 单次发送不能超过端点尺寸 */if( len>endp_out_size )length=endp_out_size;elselength=len;wr_usb_data( length, buf ); /* 将数据先复制到CH375芯片中 */ toggle_send(); /* 数据同步 */status = issue_token( ( endp_out_addr << 4 ) DEF_USB_PID_OUT ); /* 请求CH375输出数据 */// status = issue_token( ( 2 << 4 ) DEF_USB_PID_OUT ); /* 请求CH375输出数据 */if( status==USB_INT_SUCCESS ) /* CH375成功发出数据 */{len -= length; /* 计数 */buf += length; /* 操作成功 */}elseif( status==0xEF ){led=0;return;}else /* 操作失败,正常情况下不会失败 */if( status != 0xEF ){clr_stall7(); /* 清除设备的数据接收端点 */}}led=0;}unsigned char host_recv( unsigned char *buf ) /* 主机接收, 返回长度 */{unsigned char status;if( endp_in_addr ) /* 支持双向接口 */{toggle_recv(); /* 设置主机接收的同步标志 */status = issue_token( ( endp_in_addr << 4 ) DEF_USB_PID_IN );// status = issue_token( ( 2 << 4 ) DEF_USB_PID_IN );if( status==USB_INT_SUCCESS ) /* 接收成功 */{status = rd_usb_data( buf );return( status ); /* 读取接收到的数据 */}elseif( status==USB_INT_DISCONNECT ){return( 0xFE ); /* USB设备断开事件 */}elseif( status==0xEF ) /* 串口接收到数据 */{return( status );}else /* 接收失败 */{clr_stall6(); /* 接收设备端的端点错误 */return( 0xFF ); /* 返回操作失败 */}}return( 0xFF ); /* 返回操作失败 */}unsigned char get_descr( unsigned char type ) /* 从设备端获取描述符 */{CH375_WR_CMD_PORT( CMD_GET_DESCR );CH375_WR_DAT_PORT( type ); /* 描述符类型, 只支持1(设备)或者2(配置) * /return( wait_interrupt() ); /* 等待CH375操作完成 */}unsigned char set_addr( unsigned char addr ) /* 设置设备端的USB地址 */{unsigned char status;CH375_WR_CMD_PORT( CMD_SET_ADDRESS ); /* 设置USB设备端的USB地址 */ CH375_WR_DAT_PORT( addr ); /* 地址, 从1到127之间的任意值, 常用2到20 */status=wait_interrupt(); /* 等待CH375操作完成 */if( status==USB_INT_SUCCESS ) /* 操作成功 */{CH375_WR_CMD_PORT( CMD_SET_USB_ADDR ); /* 设置USB主机端的USB地址 */ CH375_WR_DAT_PORT( addr ); /* 当目标USB设备的地址成功修改后,应该同步修改主机端的USB地址 */}return( status );}unsigned char set_config( unsigned char cfg ) /* 设置设备端的USB配置 */{endp6_mode=endp7_mode=0x80; /* 复位USB数据同步标志 */CH375_WR_CMD_PORT( CMD_SET_CONFIG ); /* 设置USB设备端的配置值 */CH375_WR_DAT_PORT( cfg ); /* 此值取自USB设备的配置描述符中 */return( wait_interrupt() ); /* 等待CH375操作完成 */}/* CH375初始化子程序 */void CH375_Init( void ){unsigned char i, k;unsigned char RD_Data;CH375_DATA_PORT = 0xFF;CH375_INT_WIRE = 1;CH375_WR = 1;CH375_RD = 1;CH375_CMD_DAT = 0;/* 测试CH375是否正常工作 */for( k=100; k!=0; k-- ){CH375_WR_CMD_PORT( CMD_CHECK_EXIST ); /* 测试CH375是否正常工作 */i = 0x5A;CH375_WR_DAT_PORT( i ); /* 写入测试数据 */i = ~i; /* 返回数据应该是测试数据取反 */RD_Data = CH375_RD_DAT_PORT();if ( RD_Data != i ) /* CH375不正常 */{for ( i=5; i!=0; i-- ){CH375_WR_CMD_PORT( CMD_RESET_ALL ); /* 多次重复发命令,执行硬件复位 */ }delay50ms(); /* 延时50ms */}elsebreak;}if( k==0 ){while(1){flash_led(); /* CH375出错 */}}/* 设置USB主机模式, 如果设备端是CH37X, 那么5和6均可 */set_usb_mode( 6 );}/* 初始化USB设备,完成设备枚举 */unsigned char init_USB_device(void){unsigned char address;unsigned char status;unsigned char length;status = get_descr(1); /* 获取设备描述符 */if( status == USB_INT_SUCCESS ){length = rd_usb_data( RECV_BUFFER ); /* 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度 */if( length<18 p_dev_descr->bDescriptorType!=1 )return( UNKNOWN_USB_DEVICE ); /* 意外错误:描述符长度错误或者类型错误*/// if( p_dev_descr->bDeviceClass!=0 )// return( UNKNOWN_USB_DEVICE ); /* 连接的USB设备不符合USB规范 */status = set_addr(2); /* 设置USB设备的USB地址 */if( status == USB_INT_SUCCESS ){status = get_descr(2); /* 获取配置描述符 */if( status == USB_INT_SUCCESS ) /* 操作成功则读出描述符并分析 */ {length = rd_usb_data( RECV_BUFFER ); /* 将获取的描述符数据从CH375中读出到单片机的RAM缓冲区中,返回描述符长度 */// if( p_cfg_descr->itf_descr.bInterfaceClass!=7 p_cfg_descr->itf_des cr.bInterfaceSubClass!=1 )// return( UNKNOWN_USB_DEVICE ); /* 不符合USB规范 */endp_out_addr=endp_in_addr=0;address = p_cfg_descr->endp_descr[0].bEndpointAddress; /* 第一个端点的地址 */if( address&0x80 )endp_in_addr = address&0x0f; /* IN端点的地址 */else{ /* OUT端点 */endp_out_addr = address&0x0f;endp_out_size = p_cfg_descr->endp_descr[0].wMaxPacketSize; /* 数据接收端点的最大包长度 */if( endp_out_size == 0 endp_out_size > 64 )endp_out_size = 64;}if( p_cfg_descr->itf_descr.bNumEndpoints>=2 ) /* 接口有两个以上的端点 */{if( p_cfg_descr->endp_descr[1].bDescriptorType==5 ) /* 端点描述符*/{address = p_cfg_descr->endp_descr[1].bEndpointAddress; /* 第二个端点的地址 */if( address&0x80 )endp_in_addr = address&0x0f; /* IN端点 */else{ /* OUT端点 */endp_out_addr = address&0x0f;endp_out_size = p_cfg_descr->endp_descr[1].wMaxPacketSize;if( endp_out_size == 0 endp_out_size > 64 )endp_out_size = 64;}}}if( p_cfg_descr->itf_descr.bInterfaceProtocol==1 )endp_in_addr=0; /* 单向接口不需要IN端点 */if( endp_out_addr==0 )return( UNKNOWN_USB_DEVICE ); /* 不符合USB规范 */status = set_config( p_cfg_descr->cfg_descr.bConfigurationvalue ); /*加载USB配置值 */if( status == USB_INT_SUCCESS ){/* 如果单片机在USB设备忙时并无事可做,建议设置位7为1,使CH375在收到N AK时自动重试直到操作成功或者失败 *//* 如果希望单片机在USB设备忙时能够做其它事,那么应该设置位7为0,使CH 375在收到NAK时不重试,所以在下面的USB通讯过程中,如果USB设备正忙,issue_token等子程序将得到状态码USB_INT_RET_NAK */CH375_WR_CMD_PORT( CMD_SET_RETRY ); // 设置USB事务操作的重试次数CH375_WR_DAT_PORT( 0x25 );CH375_WR_DAT_PORT( 0x85 ); // 位7为1则收到NAK时无限重试, 位3~位0为超时后的重试次数}}}}return(status);}/* 串行口通讯子程序 *//* 串行口初始化 */void ComInit(void){TMOD = 0x20; /*T1为方式2 */TH1 = 0xFE; /*计数常数0xFE,波特率:14400 晶振:11.0592MHz */TL1 = 0xFE;PCON = PCON & 0x7f; /* SMOD=0 */SCON = 0x50; /* 串行口工作在方式3 */TR1 = 1;}/* 发送数据 */void SendChar(unsigned char buff){SBUF = buff;while( !TI );TI=0;}/* 发送数据串void SendChars( unsigned char *buff ){unsigned char buf;while(1){buf = *buff;if( buf == 0x00 )break;SBUF = buf;buff++;while( !TI );TI=0;}}*//*串行数据接收程序*/void receive(void){unsigned int count;unsigned char buf;RECV_LEN=0;cmd_buf = RECV_BUFFER; /* 接收缓冲区 */while( 1 ){RI=0;*cmd_buf = SBUF;cmd_buf++;RECV_LEN++;if( RECV_LEN == 64 ) {while( 1 ){count=10000;while( RI==0 ){count--;if( count==0 ) return;}RI=0;buf=SBUF;}}count=10000;while( RI==0 ){count--;if( count==0 ) return;}}}/* 主机端的主程序 */ void main(void){unsigned char i; unsigned char length;delay1s();CH375_Init();ComInit();led=0;while(1){led=0;while (1){if( wait_interrupt() == USB_INT_CONNECT ) /* 等待设备端连接上来 */ {// SendChars( "USB设备连接\n" );break;}}/* 如果设备端是CH37X,那么以下步骤是可选的,如果是其它USB芯片,那么需要执行以下步骤,并且要分析配置描述符的数据获得配置值以及端点号,并修改本程序中的端点号,USB规范中未要求在USB设备插入后必须复位该设备,但是计算机的WINDOWS总是这样做,所以有些USB设备也要求在插入后必须先复位才能工作 */set_usb_mode( 7 ); /* 复位USB设备,CH375向USB信号线的D+和D-输出低电平 *//* 如果单片机对CH375的INT#引脚采用中断方式而不是查询方式,那么应该在复制USB设备期间禁止CH375中断,在USB设备复位完成后清除CH375中断标志再允许中断 */delay50ms();set_usb_mode( 6 ); /* 结束复位 */while (1){if( wait_interrupt() == USB_INT_CONNECT ) /* 等待复位之后的设备端再次连接上来 */break;}delay1s(); /* 有些USB设备要求延时数百毫秒后才能工作 */for( i=5;i!=0;i-- ){if( init_USB_device() != USB_INT_SUCCESS ) /* 初始化USB设备 */flash_led(); //错误elsebreak;}if( i==0 ){flash_led(); //错误flash_led(); //错误flash_led(); //错误continue;}while(1){ret_buf = RECV_BUFFER; /* 接收缓冲区 */length = host_recv( ret_buf ); /* 从设备端接收数据 */if( length == 0xEF ) /* 串口接收到数据 */{led=1;receive();led=0;ret_buf = RECV_BUFFER; /* 接收缓冲区 */length = RECV_LEN; /* 刚接收到的数据长度 */if( length!=0 )host_send( length, ret_buf ); /* 将从串口接收到的数据发送到USB设备 * /}elseif( length == 0xFE ) /* USB设备断开事件 */{// SendChars( "USB设备断开\n" );break;}elseif( length != 0xFF ){ret_buf = RECV_BUFFER; /* 接收缓冲区 */while( length-- ){SendChar( *ret_buf ); /* 将从USB设备接收到的数据发送到串口 */ret_buf++;}}}}}。
USB接口芯片CH375(二)
PID 字节
名称
说明
0DH
DEF_USB_PID_SETUP
发起控制传输,发送建立数据
01H
DEF_USB_PID_OUT
执行 OUT 事务,发送数据
09H
DEF_USB_PID_IN
执行 IN 事务,接收数据
1.16. 命令 DISK_BOC_CMD
该命令对 USB 存储设备执行 BulkOnly 传输协议的命令。在执行该命令之前,单片机必须先通过 WR_USB_DATA7 命令向 CH375 写入相应的 CBW 包,CH375 在命令执行完成后向单片机请求中断,单片机 可以读取中断状态作为该命令的操作状态。如果操作状态是 USB_INT_SUCCESS 则说明命令执行成功, 对于有返回数据的操作,可以由 RD_USB_DATA 命令获取返回数据。
1.15. 命令 ISSUE_TOKEN
该命令使 CH375 发出令牌,执行事务。该命令需要输入 1 个数据,作为事务属性。事务属性的低 4 位指定事务的令牌 PID,高 4 位指定 USB 设备的目的端点号。CH375 在命令执行完成后向单片机请 求中断,单片机可以读取中断状态作为该命令的操作状态。如果操作状态是 USB_INT_SUCCESS,则说 明命令执行成功,否则说明命令执行失败,单片机可以根据操作状态进一步分析失败原因。
CH375 中文手册(二)
1
USB 总线接口芯片 CH375
1、附加命令
中文手册(二):USB 基本传输命令 版本:3D
代码
命令名称
输入数据
输出数据
命令用途
04H
SET_USB_SPEED
总线速度
设置 USB 总线速度
CH375中文手册(一)
CH375中文手册(一)1、如果是在没有单片机的情况下,进行简单的I/O输入输出,那么可以参考CH341的资料CH341不需要单片机就能独立工作,可以提供串口、并口、兼容IIC或12C的2线接口、兼容SPI及JTAG 的4线接口、5线接口等,可以提供多个GPIO通用O,可以用于控制低速。
模数转换AD、DA、数字WO、IO扩展等。
2、如果是单片机/DSP等与计算机相连接,也就是USB设备方式的应用,那么参考CH372的资料。
可以下载CH372+CH451评估板/演示板的资料CH372EVT.ZIP,有PDF文档和例子程序,例如,评估板说明及USB设备应用参考CH375451,参考电路和PCB,小数据量交互传输/应用层中断演示的例子DEMO,含MCS51单片机C程序和汇编程序,批量数据传输的例子BULK测试速度,USB外置固件的C 和汇编例子XFIRM,VCB/BC/DELPHI的例子等。
另外,可以下载CH37X在计算机WINDOWS下的简单调试工具CH372DBG.ZIP其中有MCS51单片机上位机与下位机的C源程序,PC机程序可以通过USB 对MCS51进行简单仿真和控制,其中的C程序稍作修改就可以用于其它单片机。
调试工具DEBUG372可以用于调试和检查下位机的程序。
3、如果是单片机/DSP等控制其它USB设备,也就是USB主机方式的应用,那么可以参考CH375的资料。
如果是读写U盘并且用量较少或者是系统集成,关心快速入门并且简单易用,那么可以参考半成品U盘文件读写模块的说明CH375HM.ZIP;如果是做原始产品设计,关心成本,那么可以参考CH375评估板资料CH375EVT.ZIP,其中有单片机读写U盘的例子和U盘文件级子程序库的API说明:如果是单片机控制USB打印机等,或者CH375与CH372等其它USB产品通讯,可以参考USB主机方式应用参考CH375HST.ZIP。
在设计USB-HOST电路和PCB之前,强烈建议参考CH375的设计注意事项README.PDF *关于电源优先使用5V电源,CH37X在5V电源时的性能高于3.3V,可以作为工业级使用对于USB-HOST应用,建议参考CH375的设计注意事项README.PDF,要考虑USB带电插拔的实际情况。
51单片机-ch375
51单片机usb(CH375)的设计1.1 系统功能简介本设计主要完成U盘的识别和数据的读取,并将U盘中读取的MP3文件解码播放出流畅的音乐,完成.MP3播放器的存储与解码的分离。
系统功能主要包括读取U盘数据和MP3解码播放2部分。
实现设计功能需要USB接口芯片、MP3解码芯片、主控制器和其他外围电路。
考略难易程度和实际实现程度,这里的MP3只提供从u盘的根目录读取MP3格式的文件(不包括wma,wmv,midi格式),而且u盘的文件格式必须为F AT32。
再者,考略到单片机的运行速度较慢,如果文件的采样频率额过高,可能会造成播放断断续续,因此读取的MP3文件的采样频率事先转化为频率64k ps,这样可以获得较好的音质。
2.主要芯片的选取2.1.单片机的选取由于解码和播放有很高的速度要求,且需要单片机有较大的ROM和RAM,这里我们选取了STC12C5A60S2。
STC12C5A60S2是新一代51单片机,是传统51单片机的升级换代产品,可实现“1个时钟/机器周期”,在同等晶振下运行速度可以达到传统单片机的12倍。
在这里,我们采用22.1184M.2.2.USB总线接口芯片的选取通过比较部分参数,我们选择南京沁恒电子生产的一款USB通用接口芯片CH375。
CH375是一个USB总线的通用接口芯片,CH375芯片支持HOST主机方式和DEV IC E设备方式,在本地端,CH375具有8位数据总线和读、写、片选控制线以及终端输出,可以方便地挂接到单片机等控制器的系统总线上。
最重要的是,该芯片内置固件处理海量存储设备的专用通讯协议,可以使我们的编程难度大大减小。
内部集成了PLL倍频器、主从USB接口、数据缓冲区、被动并行接口、异步串行接口、命令解释器、控制传输的协议处理器、通用的固件程序等。
2.3.音频解码芯片的选取音频解码芯片选择芬兰VLSI公司生产的VSl003。
VSl003具有MP3/wMA /MIDI解码和ADPCM编码功能,他内部包含一个高性能、低功耗的DSP处理核(VSD一SP),为用户应用提供5KB的指令RAM和0.5kb的数据RAM。
CH375HM
2、功能与特点
用于嵌入式系统/单片机读写 U 盘、闪盘、闪存盘、USB 移动硬盘、USB 读卡器等。 支持符合 USB 相关规范基于 Bulk-Only 传输协议的各种 U 盘/闪存盘/外置硬盘。 支持文件系统 FAT12 和 FAT16 及 FAT32,如果需要支持 FAT32 请看本文后面的说明。 提供工具程序,只要连接计算机 USB 端口,就可以随时升级模块,随时设置模块。 支持小端格式和大端格式的数据字节顺序,适用于绝大多数单片机系统。 文件操作功能:搜索、新建、删除、读写数据,查询和修改信息等。 读写模式:高速的扇区模式、方便的字节模式、简化的数据流模式。 提供 3 种硬件以适应不同的 I/O 接口:标准版、串口版、低电压版。 提供多种软件供随时下载到模块硬件中,通过多种软硬件组合支持各种不同的 I/O 接口。 模块具有简单的自动演示功能,提供串口连接方式下的计算机端的演示工具。
3.3 升级和配置模块
在模块上电或者复位时,模 块将检查跳线 J1 的状态。 当跳线 J1 断开时进入正常工作状态, 当 跳线 J1 短路时进入功能配置状 态。当升级模块程序或者配置完 毕后, 必须将跳线 J1 断开, 重新 上电才能进入正常工作状态。 在功能配置状态下,只要用 USB 对连线连接计算机的 USB 端 口和模块的 USB 端口,就可以对 模块进行在线程序升级和功能配 置。 首次连接计算机时, WINDOWS 提示找到 USB 新硬件,所以需要 执行驱 动程序 包 CH372DRV.EXE 安装 U 盘模块的驱动程序(就是 CH372 或 CH375 的 WINDOWS 通用 驱动程序) , 然后运行模块工具程 序 CH37XDL.EXE,选择目标程序 文件进行下载或者重新配置模块 的接口。界面通常如右图。
51+ch375读写U盘超精简原程序
SecPerClus = DISK_BUFFER[0x0D]; /*每簇扇区数*/
RsvdSecCnt = DISK_BUFFER[0x0E]; /*逻辑盘的保留扇区数*/
FATSz16 = mGetPointWord( &DISK_BUFFER[0x16] ); /* FAT表占用扇区数*/
return( 0 ); /*成功*/
| (UINT32)DISK_BUFFER[0x1C8] << 16 | (UINT32)DISK_BUFFER[0x1C9] << 24;
Status = mReadSector( DiskStart, 1, DISK_BUFFER );
if ( Status != 0 ) return( Status );
51+ch375读写U盘超精简原程序(啊雨)
/*这个程序用180行C代码就能够读取FAT16文件系统U盘的根目录,可以看到根目录下的文件
名,并可显示
首文件内容,不过,该程序很不严谨,也没有任何错误处理,对U盘兼容性较差,只是用于简单试
验,作为参考.
这个程序可以支持WINDOWS按FAT16格式化的U盘,因为程序精简,所以只兼容超过50%以上的U
}
UINT8 CH375_RD_DAT_PORT( void ) { /*从CH375的数据端口读出数据*/
return( CH375_DAT_PORT ); /*因为MCS51单片机较慢所以实际上无需延时*/
}
UINT8 mWaitInterrupt( void ) { /*等待CH375中断并获取状态,返回操作状态*/
CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /*从CH375缓冲区读取数据块*/
CH375做HOST的程序
CH375做HOST的程序CH375是一款常用的USB主机控制芯片,它可以实现USB设备的控制和数据传输。
在本文中,我将详细介绍如何使用CH375芯片编写HOST程序。
首先,我们需要了解CH375芯片的基本原理和功能。
CH375芯片是一款集成了USB控制器和存储控制器的单片机芯片,它可以通过SPI接口与主控单片机进行通信。
CH375芯片支持USB1.1标准,可以实现USB设备的控制、数据传输和存储等功能。
接下来,我们需要准备工作。
首先,我们需要一台主控单片机,可以是常见的51单片机、STM32等。
其次,我们需要一块CH375芯片的开发板,可以购买现成的开发板或者自己设计。
最后,我们需要一些外围电路,如USB接口、SPI接口等。
在开始编写HOST程序之前,我们需要了解CH375芯片的通信协议。
CH375芯片通过SPI接口与主控单片机进行通信,主控单片机可以通过向CH375芯片发送命令和数据来控制USB设备。
CH375芯片的通信协议比较简单,可以参考CH375芯片的数据手册进行了解。
接下来,我们可以开始编写HOST程序了。
首先,我们需要初始化CH375芯片,包括设置SPI接口的时钟、模式等参数。
然后,我们可以通过发送命令和数据来控制USB设备。
例如,我们可以发送命令来控制USB设备的复位、枚举和传输数据等操作。
在编写HOST程序的过程中,我们需要注意一些细节。
首先,我们需要根据USB设备的特性来选择合适的命令和数据格式。
例如,如果USB设备是存储设备,我们可以使用CH375芯片的存储控制功能来读写数据。
其次,我们需要处理USB设备的中断和错误情况,以确保程序的稳定性和可靠性。
最后,我们需要进行测试和调试。
在测试过程中,我们可以使用USB设备模拟器或者实际的USB设备来验证程序的功能和性能。
如果发现问题,我们可以通过查看日志和调试信息来定位和修复错误。
综上所述,CH375芯片是一款功能强大的USB主机控制芯片,通过编写HOST程序,我们可以实现对USB设备的控制和数据传输。
ch375读写u盘C51示例源程序
ch375读写u盘C51示例源程序#include "datatype.h"#include "console.h"#include "44b0x.h"#include <string.h>/* 以下定义的详细说明请看CH375HF9.H文件*/#define LIB_CFG_FILE_IO 1 /* 文件读写的数据的复制方式,0为"外部子程序",1为"内部复制" */#define LIB_CFG_INT_EN 1 /* CH375的INT#引脚连接方式,接s3c44b0x外部中断2引脚" *//* 单片机的RAM有限,其中CH375子程序用512字节,剩余RAM部分可以用于文件读写缓冲*/#define FILE_DATA_BUF_LEN 0x2000 /* 外部RAM的文件数据缓冲区,缓冲区长度不小于一次读写的数据长度*/#include "CH375HF9.H"#define CH375Cmd *(volatile U8 *)(0x4000001) /*总线方式*/#define CH375Dat *(volatile U8 *)(0x4000000)extern U32 MCLK;/* CH375 主机文件系统接口*//* 支持: FAT12/FA T16/F AT32 *//* ARM单片机C语言的U盘文件读写示例程序*//* 该程序将U盘中的/C51/CH375HFT.C文件中的小写字母转成大写字母后, 写到新建的文件NEWFILE.TXT中,如果找不到原文件CH375HFT.C, 那么该程序将显示C51子目录下所有以CH375开头的文件名, 并新建NEWFILE.TXT文件并写入提示信息,如果找不到C51子目录, 那么该程序将显示根目录下的所有文件名, 并新建NEWFILE.TXT文件并写入提示信息*//* CH375的INT#引脚采用查询方式处理, 数据复制方式为"内部复制", 本程序适用于s3c44b0x单片机, 串口0输出监控信息,57600bps *//* ENDIAN = "little" */void mDelay1_2uS( ) /* 至少延时1.2uS,根据单片机主频调整*/{UINT32 i;for ( i = 30; i != 0; i -- );}void __irq CH375Interrupt( void ) /* CH375中断服务程序,由CH375的INT#的低电平或者下降沿触发单片机中断*/{rEXTINTPND=0xf; //clear EXTINTPND reg.rI_ISPC=BIT_EINT2; //clear pending_bitxWriteCH375Cmd( CMD_GET_STA TUS ); /* 获取中断状态并取消中断请求*/CH375IntStatus = xReadCH375Data( ); /* 获取中断状态*/if ( CH375IntStatus == USB_INT_DISCONNECT ) CH375DiskS tatus = DISK_DISCONNECT; /* 检测到USB 设备断开事件*/else if ( CH375IntStatus == USB_INT_CONNECT ) CH375DiskS tatus = DISK_CONNECT; /* 检测到USB设备连接事件*/}extern void CH375Interrupt( void );void CH375_PORT_INIT( ) /*初始化*/{rINTCON=0x5;rINTMOD=0x0; //All=IRQ moderPDA TG=0xff;rPCONG=0xffff;rPUPG=0x0; //should be enabledrEXTINT=0x0;pISR_EINT2 = (unsigned)CH375Interrupt;rINTMSK=~(BIT_GLOBAL|BIT_EINT2); //start INT}void xWriteCH375Cmd( UINT8 mCmd ) /* 外部定义的被CH375程序库调用的子程序,向CH375写命令*/ {mDelay1_2uS( ); mDelay1_2uS( ); /* 至少延时1uS */CH375Cmd = mCmd;mDelay1_2uS( ); mDelay1_2uS( ); /* 至少延时2uS */}void xWriteCH375Data( UINT8 mData ) /* 外部定义的被CH375程序库调用的子程序,向CH375写数据*/ {CH375Dat = mDatamDelay1_2uS( ); /* 至少延时1.2uS */}UINT8 xReadCH375Data( void ) /* 外部定义的被CH375程序库调用的子程序,从CH375读数据*/{mDelay1_2uS( ); /* 至少延时1.2uS */mData = (UINT8)CH375Dat;return( mData );}/* 延时指定毫秒时间,根据单片机主频调整,不精确*/void mDelaymS( UINT32 ms ){UINT32 i;while ( ms -- ) for ( i = 25000; i != 0; i -- );}/* 检查操作状态,如果错误则显示错误代码并停机*/void mStopIfError( UINT8 iError ){if ( iError == ERR_SUCCESS ) return; /* 操作成功*/printf( "Error: %02X\n", (UINT16)iError ); /* 显示错误*/while ( 1 ) {mDelaymS( 100 );}}/* 为printf和getkey输入输出初始化串口*/void mInitSTDIO( ){}U16 SERIAL_BAUD = 57600;char table_begin[] = "/***************************************************************/\n";void ShowSysClock(int argc, char *argv[]){printf("S ystem is running @%dHz\n", MCLK);}int Main(void){UINT8 i, c, SecCount;UINT16 NewSize, count; /* 因为RAM容量有限,所以NewSize限制为16位,实际上如果文件较大,应该分几次读写并且将NewSize改为UINT32以便累计*/UINT8 *pCodeStr;ChangePllValue(24, 6, 1);Port_Init();console_init(57600);next_line();puts(table_begin);puts("Usb for S3C44B0x\n");ShowSysClock(0, NULL);printf("Serial Baud rate is %d\n", SERIAL_BAUD);next_line();puts(table_begin);puts("System Initialized.\n");mDelaymS( 50 ); /* 延时100毫秒*/printf( "测试CH375是否正常\n" );mDelaymS(60 ); /* 延时50ms */printf("\nCH375_Init完成!!");i = CH375LibInit( ); /* 初始化CH375程序库和CH375芯片,操作成功返回0 */mStopIfError( i );/* 其它电路初始化*/CH375_PORT_INIT( );while ( 1 ) {printf( "\n请插入U盘!\n" );while ( CH375DiskStatus != DISK_CONNECT ) /* 查询CH375中断并更新中断状态,等待U盘插入*/ mDelaymS( 10 );/* 检查U盘是否准备好,有些U盘不需要这一步,但是某些U盘必须要执行这一步才能工作*/for ( i = 0; i < 10; i ++ ) { /* 有的U盘总是返回未准备好,不过可以被忽略*/printf( "Ready ?\n" );if ( CH375DiskReady( ) == ERR_SUCCESS ) break; /* 查询磁盘是否准备好*/}/* 查询磁盘物理容量*/printf( "DiskSize\n" );i = CH375DiskSize( );printf( "TotalSize = %d MB \n", (unsigned int)( mCmdParam.DiskSize.mDiskSizeSec >> 11 ) );/* 读取原文件*/printf( "Open\n" );strcpy( (char *)mCmdParam.Open.mPathName, "\\C51\\CH375HFT.C" ); /* 文件名,该文件在C51子目录下*/ i = CH375FileOpen( ); /* 打开文件*/if ( i == ERR_MISS_DIR || i == ERR_MISS_FILE ) { /* 没有找到文件*//* 列出文件*/if ( i == ERR_MISS_DIR ) pCodeStr = (UINT8 *)"\\*"; /* C51子目录不存在则列出根目录下的文件*/else pCodeStr = (UINT8 *)"\\C51\\CH375*"; /* CH375HFT.C文件不存在则列出\C51子目录下的以CH375开头的文件*/printf( "List file %s\n", pCodeStr );for ( c = 0; c < 255; c ++ ) { /* 最多搜索前255个文件*/strcpy( (char *)mCmdParam.Open.mPathName, (char *)pCodeStr ); /* 搜索文件名,*为通配符,适用于所有文件或者子目录*/i = strlen( (char const *)mCmdParam.Open.mPathName ); /* 计算文件名长度,以处理文件名结束符*/ mCmdParam.Open.mPathName[ i ] = c; /* 根据字符串长度将结束符替换为搜索的序号,从0到255 */i = CH375FileOpen( ); /* 打开文件,如果文件名中含有通配符*,则为搜索文件而不打开*/if ( i == ERR_MISS_FILE ) break; /* 再也搜索不到匹配的文件,已经没有匹配的文件名*/if ( i == ERR_FOUND_NAME ) { /* 搜索到与通配符相匹配的文件名,文件名及其完整路径在命令缓冲区中*/printf( " match file %03d#: %s\n", (unsigned int)c, mCmdParam.Open.mPathName ); /* 显示序号和搜索到的匹配文件名或者子目录名*/continue; /* 继续搜索下一个匹配的文件名,下次搜索时序号会加1 */}else { /* 出错*/mStopIfError( i );break;}}pCodeStr = (UINT8 *)"找不到/C51/CH375HFT.C文件\xd\n";for ( i = 0; i != 255; i ++ ) {if ( ( FILE_DATA_BUF = *pCodeStr ) == 0 ) break;pCodeStr++;}NewSize = i; /* 新文件的长度*/SecCount = 1; /* (NewSize+511)/512, 计算文件的扇区数,因为读写是以扇区为单位的*/}else { /* 找到文件或者出错*/mStopIfError( i );/* printf( "Query\n" );i = CH375FileQuery( ); 查询当前文件的信息printf( "Read\n" );if ( CH375vFileSize > FILE_DATA_BUF_LEN ) { /* 由于演示板用的62256只有32K字节,其中CH375子程序用512字节,所以只读取不超过63个扇区,也就是不超过32256字节*/SecCount = FILE_DATA_BUF_LEN / 512; /* 由于演示板用的62256只有32K字节,其中CH375子程序用512字节,所以只读取不超过63个扇区,也就是不超过32256字节*/NewSize = FILE_DATA_BUF_LEN; /* 由于RAM有限所以限制长度*/}else { /* 如果原文件较小,那么使用原长度*/SecCount = ( CH375vFileSize + 511 ) >> 9; /* (CH375vFileSize+511)/512, 计算文件的扇区数,因为读写是以扇区为单位的,先加511是为了读出文件尾部不足1个扇区的部分*/NewSize = (UINT16)CH375vFileSize; /* 原文件的长度*/}printf( "Size=%ld, Len=%d, Sec=%d\n", CH375vFileSize, NewSize, (UINT16)SecCount );mCmdParam.Read.mSectorCount = SecCount; /* 读取全部数据,如果超过60个扇区则只读取60个扇区*/ /* current_buffer = & FILE_DATA_BUF[0]; 如果文件读写的数据的复制方式为"外部子程序",那么需要设置存放数据的缓冲区的起始地址*/CH375vFileSize += 511; /* 默认情况下,以扇区方式读取数据时,无法读出文件尾部不足1个扇区的部分,所以必须临时加大文件长度以读取尾部零头*/i = CH375FileRead( ); /* 从文件读取数据*/CH375vFileSize -= 511; /* 恢复原文件长度*/mStopIfError( i );/*如果文件比较大,一次读不完,可以再调用CH375FileRead继续读取,文件指针自动向后移动while ( 1 ) {c = 32; 每次读取32个扇区mCmdParam.Read.mSectorCount = c; 指定读取的扇区数CH375FileRead(); 读完后文件指针自动后移处理数据if ( mCmdParam.Read.mSectorCount < c ) break; 实际读出的扇区数较小则说明文件已经结束}如果希望从指定位置开始读写,可以移动文件指针mCmdParam.Locate.mSectorOffset = 3; 跳过文件的前3个扇区开始读写i = CH375FileLocate( );mCmdParam.Read.mSectorCount = 10;CH375FileRead(); 直接读取从文件的第(512*3)个字节开始的数据,前3个扇区被跳过如果希望将新数据添加到原文件的尾部,可以移动文件指针i = CH375FileOpen( );mCmdParam.Locate.mSectorOffset = 0xffffffff; 移到文件的尾部,以扇区为单位,如果原文件是3字节,则从512字节开始添加i = CH375FileLocate( );mCmdParam.Write.mSectorCount = 10;CH375FileWrite(); 在原文件的后面添加数据*/printf( "Close\n" );i = CH375FileClose( ); /* 关闭文件*/mStopIfError( i );i = FILE_DATA_BUF[100];FILE_DATA_BUF[100] = 0; /* 置字符串结束标志,最多显示500个字符*/printf( "Line 1: %s\n", FILE_DATA_BUF );FILE_DATA_BUF[100] = i; /* 恢复原字符*/for ( count=0; count < NewSize; count ++ ) { /* 将文件中的小写字符转换为大写*/c = FILE_DATA_BUF[ count ];if ( c >= 'a' && c <= 'z' ) FILE_DATA_BUF[ count ] = c - ( 'a' - 'A' );}}#ifdef EN_DISK_WRITE /* 子程序库支持写操作*//* 产生新文件*/printf( "Create\n" );strcpy( (char *)mCmdParam.Create.mPathName, "\\NEWFILE.TXT" ); /* 新文件名,在根目录下*/i = CH375FileCreate( ); /* 新建文件并打开,如果文件已经存在则先删除后再新建*/mStopIfError( i );printf( "Write\n" );mCmdParam.Write.mSectorCount = SecCount; /* 写入所有扇区的数据*//* current_buffer = & FILE_DATA_BUF[0]; 如果文件读写的数据的复制方式为"外部子程序",那么需要设置存放数据的缓冲区的起始地址*/i = CH375FileWrite( ); /* 向文件写入数据*/mStopIfError( i );printf( "Modify\n" );mCmdParam.Modify.mFileAttr = 0xff; /* 输入参数: 新的文件属性,为0FFH则不修改*/mCmdParam.Modify.mFileTime = 0xffff; /* 输入参数: 新的文件时间,为0FFFFH则不修改,使用新建文件产生的默认时间*/mCmdParam.Modify.mFileDate = MAKE_FILE_DA TE( 2004, 5, 18 ); /* 输入参数: 新的文件日期: 2004.05.18 */mCmdParam.Modify.mFileSize = NewSize; /* 输入参数: 如果原文件较小,那么新的文件长度与原文件一样长,否则被RAM所限,如果文件长度大于64KB,那么NewSize必须为UINT32 */i = CH375FileModify( ); /* 修改当前文件的信息,修改日期和长度*/mStopIfError( i );printf( "Close\n" );mCmdParam.Close.mUpdateLen = 0; /* 不要自动计算文件长度,如果自动计算,那么该长度总是512的倍数*/i = CH375FileClose( );mStopIfError( i );/* 删除某文件*//* printf( "Erase\n" );strcpy( (char *)mCmdParam.Create.mPathName, "\\OLD" ); 将被删除的文件名,在根目录下i = CH375FileErase( ); 删除文件并关闭if ( i != ERR_SUCCESS ) printf( "Error: %02X\n", (UINT16)i ); 显示错误*//* 查询磁盘信息*/printf( "Disk\n" );i = CH375DiskQuery( );mStopIfError( i );printf( "Fat=%d, Total=%ld, Free=%ld\n", (UINT16)mCmdParam.Query.mDiskFat, mCmdParam.Query.mTotalSector, mCmdParam.Query.mFreeSector );#endifmDelaymS(200 );printf( "请拔出U盘!\n" );while ( CH375DiskStatus != DISK_DISCONNECT ) xQueryInterrupt( ); /* 查询CH375中断并更新中断状态,等待U盘拔出*/mDelaymS( 200 );}}。
USB接口芯片CH375的原理及应用概况
USB接口芯片CH375的原理及应用对USB接口芯片CH375的功能、原理做了较详细的介绍,并给出了在单片机读写U盘中的实例及注意事项。
随着计算机技术的快速发展,USB移动存储设备的使用已经非常普遍,因此在一些需要转存数据的设备、仪器上使用USB移动存储设备接口的芯片便相继产生了,CH375就是其中之一,它是一个USB总线的通用接口芯片,支持HOST主机方式和SLAVE设备方式。
在本地端,CH375具有8位数据总线和读、写、片选控制线以及中断输出,可以方便地挂接到单片机/DSP/MCU等控制器的系统总线上。
在USB主机方式下,CH375还提供了串行通信方式,通过串行输入、串行输出和中断输出与单片机/DSP/MCU等相连接。
CH375的USB主机方式支持各种常用的USB全速设备,外部单片机/DSP/MCU可以通过CH375按照相应的USB协议与USB设备通信。
CH375芯片内部结构1 内部结构CH375芯片内部集成了PLL倍频器、主从USB接口SIE、数据缓冲区、被动并行接口、异步串行接口、命令解释器、控制传输的协议处理器、通用的固件程序等。
CH375芯片引脚排列如图1所示。
2 内部物理端点CH375芯片内部具有7个物理端点。
端点0是默认端点,支持上传和下传,上传和下传缓冲区各是8B;端点1包括上传端点和下传端点,上传和下传缓冲区各是8B,上传端点的端点号是81H,下传端点的端点号是01H;端点2包括上传端点和下传端点,上传和下传缓冲区各是64B,上传端点的端点号是82H,下传端点的端点号是02H。
主机端点包括输出端点和输入端点,输出和输入缓冲区各是64B,主机端点与端点2合用同一组缓冲区,主机端点的输出缓冲区就是端点2的上传缓冲区,主机端点的输入缓冲区就是端点2的下传缓冲区。
其中,CH375的端点0、端点1、端点2只用于USB设备方式,在USB主机方式下只需要用到主机端点。
软件接口对于USB存储设备的应用,CH375直接提供了数据块的读写接口,以512b 的物理扇区为基本读写单位,从而将USB存储设备简化为一种外部数据存储器,单片机可以自由读写USB存储设备中的数据,也可以自由定义其数据结构。
单片机通过CH375读写U盘文件的问题解答
单片机通过CH375读写U盘文件的问题解答单片机通过CH375读写U盘文件的问题解答(转自官网)(发布:2009-9-17 18:07 | 作者:zxgsdu | 来源:本站| 查看:86次| 字号: 小中大* 需要设计参考资料(光盘资料可以参考FILELIST.TXT文档,网上资料更新)USB主机方式的应用可以参考CH375的资料,与计算机连接的USB设备方式(或自己做U盘)可以参考CH372的资料。
如果是读写U盘并且用量较少或者是系统集成,关心快速入门并且简单易用,那么可以参考半成品U盘文件读写模块的说明CH375HM.ZIP;如果是做原始产品设计,关心成本,那么可以参考CH375评估板资料CH375EVT.ZIP,其中有单片机读写U盘的多个例子源程序和U盘文件级子程序库的API说明。
在设计USB-HOST电路和PCB之前,强烈建议参考CH375的USB电路及PCB设计注意事项README.PDF。
常规问题例如不工作/连接失败可以参考CH372的问题解答,关于USB传输速度可以参考评估板中的说明。
* 有关U盘文件的一些基础知识WINDOWS下U盘的文件系统主要有FAT12/FAT16/FAT32,我们的子程序库都能支持,使用角度感觉无区别。
单片机不需要考虑文件系统,只需要了解文件名、文件长度等基础知识。
一个U盘中可以有多个文件,每个文件都是一组数据的集合,以文件名区分和识别。
文件长度是指文件中有效数据的长度,而实际占用的磁盘空间通常大于或者等于文件长度,实际文件数据的存放可能不是连续的,而是通过一组“指针”链接的多个块(也就是分配单元或簇),从而能够根据需要随时增大文件长度以容纳更多数据。
目录是为了便于分类管理,管理者可以人为指定将多个文件归档在一起,例如2004年的文件归到一个目录中。
* 读写U盘中的文件对单片机有要求吗硬件上,单片机需要提供至少600字节的RAM,RAM多些可以提高速度,软件上可以采用我们的子程序库,但是产生的程序代码可能会有几K字节,也就是说单片机的程序空间必须能够放得在几K到十几K的代码。
ch375的测试程序
SET_USB_MODE 命令之前执行
VID:厂商识别码Vendor-ID
PID:厂商识别码Product-ID
***********************************************************
1:已启用外部固件模式
2:已启用内部固件模式
返回值:启用方式。100:设置失败
**********************************************************/
byte SetUSB_Mod372(byte mod)
向USB断点2的上传缓冲区写入数据块。数据块的有效值是0~64,
如果长度不为0,则单片机必须将后续数据逐个写入ch372
psrc:要写的数据
************************************************************/
void WrPoint2(byte * psrc,byte n_byte)
byte q0;
A0=0;WR1=0;RD1=1;CS=1;
//设置写数据状态
for(q0=0;q0<n_byte;q0++)
{P0=(*psrc);
CS=0;
delay_2us(5);
CS=1;psrc++;}
底层命令
**********************************************************/
/************************************************************
USB 总线接口芯片 CH375 中文手册(一)
USB总线接口芯片CH375中文手册版本:3D1、概述CH375是一个USB总线的通用接口芯片,支持USB-HOST主机方式和USB-DEVICE/SLAVE设备方式。
在本地端,CH375具有8位数据总线和读、写、片选控制线以及中断输出,可以方便地挂接到单片机/DSP/MCU/MPU等控制器的系统总线上。
在USB主机方式下,CH375还提供了串行通讯方式,通过串行输入、串行输出和中断输出与单片机/DSP/MCU/MPU等相连接。
CH375的USB设备方式与CH372芯片完全兼容,CH375包含了CH372的全部功能。
本手册中没有提供CH375在USB设备方式下的说明,相关资料可以参考CH372手册CH372DS1.PDF。
CH375的USB主机方式支持常用的USB全速设备,外部单片机可以通过CH375按照相应的USB协议与USB设备通讯。
CH375还内置了处理Mass-Storage海量存储设备的专用通讯协议的固件,外部单片机可以直接以扇区为基本单位读写常用的USB存储设备(包括USB硬盘/USB闪存盘/U盘)。
2、特点●全速USB-HOST主机接口,兼容USB V2.0,外围元器件只需要晶体和电容。
●全速USB设备接口,完全兼容CH372芯片,支持动态切换主机与设备方式。
●主机端点输入和输出缓冲区各64字节,支持12Mbps全速USB设备和1.5Mbps低速设备。
●支持USB设备的控制传输、批量传输、中断传输。
●自动检测USB设备的连接和断开,提供设备连接和断开的事件通知。
●内置控制传输的协议处理器,简化常用的控制传输。
●内置固件处理海量存储设备的专用通讯协议,支持Bulk-Only传输协议和SCSI、UFI、RBC或等效命令集的USB存储设备(包括USB硬盘/USB闪存盘/U盘/USB读卡器)。
●通过U盘文件级子程序库实现单片机读写USB存储设备中的文件。
●并行接口包含8位数据总线,4线控制:读选通、写选通、片选输入、中断输出。
单片机通过CH375 读写U 盘时的注意事项
单片机通过CH375读写U盘时的注意事项版本:1B1、概述USB总线接口芯片CH375支持USB-HOST和USB-DEVICE,可以用于单片机读写U盘。
本说明中的多数内容为建议性说明,而非强制性说明,建议的目的旨在提高最终产品的稳定性和可靠性,很多内容只是针对一般情况和大多数用户而言,而未考虑个别或者例外。
本说明中列举了一些发生在某些品牌U盘上的怪现象,都是我们实际测试现象的描述,我们并没有以此评价U盘的优劣,因为实际上它们可能已经算是所有U盘中比较优秀的几种,而且,我们也不排除这仅仅是品牌U盘中的个别现象,只是正好被我们碰到而已。
2、硬件2.1. CH375芯片1) CH375内部含有时钟振荡电路,但是驱动能力比普通的单片机要弱一些,振荡波形通常比较接近正弦波(普通单片机的振荡波形接近方波),这种弱振荡的优点是对外产生的电磁干扰较少,缺点是理论上自身比较容易受外来的干扰,当然,如果电路及PCB设计良好则不会产生干扰。
2) CH375的时钟可以使用普通12MHz石英晶体或者普通12MHz有源晶振,但是不宜使用频率误差较大的陶瓷晶体。
对于普通石英晶体,虽然CH375手册中标明振荡电容为15pF,但是原则上应该根据晶体厂家的推荐值选择匹配的振荡电容,例如是18pF、20pF、22pF、24pF、27pF等。
3) 如果电源电压为3.3V,可以将XI引脚的电容C1容量选用小些(例如10pF),或者用有源晶振或者外部振荡电路为CH375的XI引脚提供时钟,以保证时钟稳定性。
有的电路还可以在CH375的XO引脚串接100Ω到300Ω的电阻,改善振荡参数。
对于CH375B芯片,不需要外串电阻。
4) 为了降低电磁辐射,并减少来自外界的干扰,振荡电路的晶体X1的金属外壳应该接地,晶体X1以及电容C1、C2应该尽量靠近CH375,C1和C2的GND端应该尽量接近CH375的GND端,相关的PCB走线应该尽量短,并且可以在周边环绕接地线或敷铜。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
}
UINT8 mWaitInterrupt( void ) { /* 等待CH375中断并获取状态,返回操作状态 */
while( CH375_INT_WIRE ); /* 查询等待CH375操作完成中断(INT#低电平) */
区 */
DiskStart = DISK_BUFFER[0x1C6] | (UINT16)DISK_BUFFER[0x1C7] << 8
| (UINT32)DISK_BUFFER[0x1C8] << 16 | (UINT32)DISK_BUFFER[0x1C9] << 24;
#define UINT32 unsigned long
#define UINT8X unsigned char xdata
#define UINT8VX unsigned char volatile xdata
UINT8VX CH375_CMD_PORT _at_ 0xBDF1; /* CH375命令端口的I/O地址 */
}
void CH375_WR_DAT_PORT( UINT8 dat ) { /* 向CH375的数据端口写入数据 */
CH375_DAT_PORT=dat; /* 因为MCS51单片机较慢所以实际上无需延时 */
}
UINT8 CH375_RD_DAT_PORT( void ) { /* 从CH375的数据端口读出数据 */
Status = mWaitInterrupt( ); /* 等待中断并获取状态 */
if ( Status != USB_INT_SUCCESS ) { /* 出错重试 */
/* 对于CH375A芯片,建议在此执行一次CMD_DISK_R_SENSE命令 */
mDelaymS( 250 );
单 */
Status = mReadSector( 0, 1, DISK_BUFFER ); /* 读取逻辑盘引导信息 */
if ( Status != 0 ) return( Status );
if ( DISK_BUFFER[0] != 0xEB && DISK_BUFFER[0] != 0xE9 ) { /* 不是逻辑引导扇
/* 输入: iCluster 当前簇号, 返回: 原链接簇号, 如果为0则说明错误 */
UINT8 Status;
Status = mReadSector( DiskStart + RsvdSecCnt + iCluster / 256, 1,
DISK_BUFFER );
if ( Status != 0 ) return( 0 ); /* 错误 */
CH375_WR_CMD_PORT( CMD_RD_USB_DATA ); /* 从CH375缓冲区读取数据块 */
c = 据的长度 */
while ( c -- ) *oDataBuffer++ = CH375_RD_DAT_PORT( );
#include <stdio.h>
#include "CH375INC.H"
#include <reg51.h> /* 以下定义适用于MCS-51单片机,其它单片机参照修改 */
#define UINT8 unsigned char
#define UINT16 unsigned short
Status = mWaitInterrupt( ); /* 等待中断并获取状态 */
if ( Status != USB_INT_SUCCESS ) return( Status ); /* 出现错误 */
CH375_WR_CMD_PORT( CMD_DISK_SIZE ); /* 获取USB存储器的容量 */
FATSz16 = mGetPointWord( &DISK_BUFFER[0x16] ); /* FAT表占用扇区数 */
return( 0 ); /* 成功 */
}
UINT16 mLinkCluster( UINT16 iCluster ) { /* 获得指定簇号的链接簇 */
UINT32 DiskStart; /* 逻辑盘的起始绝对扇区号LBA */
UINT8 SecPerClus; /* 逻辑盘的每簇扇区数 */
UINT8 RsvdSecCnt; /* 逻辑盘的保留扇区数 */
UINT16 FATSz16; /* FAT16逻辑盘的FAT表占用的扇区数 */
Status = CH375_RD_DAT_PORT( );
if ( Status == USB_INT_DISCONNECT ) return( Status ); /* USB设备断开 */
CH375_WR_CMD_PORT( CMD_DISK_INIT ); /* 初始化USB存储器 */
CH375_WR_CMD_PORT( CMD_DISK_RD_GO ); /* 继续执行USB存储器的读操作 */
}
else break; /* 返回错误状态 */
}
if ( mBlockCount == 0 ) {
c = mWaitInterrupt( ); /* 等待中断并获取状态 */
UINT8VX CH375_DAT_PORT _at_ 0xBCF0; /* CH375数据端口的I/O地址 */
#define CH375_INT_WIRE INT0 /* P3.2, 连接CH375的INT#引脚,用于查询中
断状态 */
UINT8X DISK_BUFFER[512*32] _at_ 0x0000; /* 外部RAM数据缓冲区的起始地址 */
return( mGetPointWord( &DISK_BUFFER[ ( iCluster + iCluster ) & 0x01FF ] ) );
}
UINT32 mClusterToLba( UINT16 iCluster ) { /* 将簇号转换为绝对LBA扇区地址 */
return( DiskStart + RsvdSecCnt + FATSz16 * 2 + 32 + ( iCluster - 2 ) *
SecPerClus );
}
void mInitSTDIO( void ) { /* 仅用于调试用途及显示内容到PC机,与该程序功能完全无
/* ********** 硬件USB接口层,无论如何这层省不掉,单片机总要与CH375接口吧 */
void mDelaymS( UINT8 delay ) {
UINT8 i, j, c;
for ( i = delay; i != 0; i -- ) {
for ( j = 200; j != 0; j -- ) c += 3;
CH375_WR_CMD_PORT( CMD_DISK_SIZE ); /* 获取USB存储器的容量 */
Status = mWaitInterrupt( ); /* 等待中断并获取状态 */
}
if ( Status != USB_INT_SUCCESS ) return( Status ); /* 出现错误 */
if ( c== USB_INT_SUCCESS ) return( 0 ); /* 操作成功 */
}
return( c ); /* 操作失败 */
}
/* ********** FAT文件系统层,这层程序量实际较大,不过,该程序仅演示极简单的功能,所
以精简 */
UINT16 mGetPointWord( UINT8X *iAddr ) { /* 获取字数据,因为MCS51是大端格式 */
return( 0 ); /* U盘已经成功初始化 */
}
UINT8 mReadSector( UINT32 iLbaStart, UINT8 iSectorCount, UINT8X *oDataBuffer )
{
UINT16 mBlockCount;
UINT8 c;
CH375_WR_DAT_PORT( (UINT8)( iLbaStart >> 16 ) );
CH375_WR_DAT_PORT( (UINT8)( iLbaStart >> 24 ) ); /* LBA的最高8位 */
CH375_WR_DAT_PORT( iSectorCount ); /* 扇区数 */
Status = mReadSector( DiskStart, 1, DISK_BUFFER );
if ( Status != 0 ) return( Status );
}
SecPerClus = DISK_BUFFER[0x0D]; /* 每簇扇区数 */
RsvdSecCnt = DISK_BUFFER[0x0E]; /* 逻辑盘的保留扇区数 */
CH375_WR_CMD_PORT( CMD_DISK_READ ); /* 从USB存储器读数据块 */
CH375_WR_DAT_PORT( (UINT8)iLbaStart ); /* LBA的最低8位 */
CH375_WR_DAT_PORT( (UINT8)( iLbaStart >> 8 ) );
CH375_WR_CMD_PORT( CMD_GET_STATUS ); /* 产生操作完成中断,获取中断状态 */