u盘读写控制源程序 - ch376芯片 下载本文

主要包含4个C文件和和三个头文件 CH376INC.H 与CH376HFT.C为u盘主文件 SPI_SW.C 为对硬件操作文件 单片机与SPI接口 FILE_SYS.H与FILE_SYS.C 为ch376接口函数 分别列出

CH376INC.H文件:

/* C Define for CH376 */ /* Website: http://wch.cn */ /* Email: tech@wch.cn */ /* Author: W.ch 2008.10 */ /* V1.0 for CH376 */

#ifndef __CH376INC_H__ #define __CH376INC_H__

#ifdef __cplusplus extern \#endif /*

********************************************************************************************************************* */ /* 常用类型和常量定义 */

#ifndef TRUE #define TRUE 1 #define FALSE 0

#endif #ifndef NULL #define NULL 0 #endif

#ifndef UINT8

typedef unsigned char UINT8; #endif

#ifndef UINT16

typedef unsigned short UINT16; #endif

#ifndef UINT32

typedef unsigned long UINT32; #endif

#ifndef PUINT8

typedef unsigned char *PUINT8; #endif

#ifndef PUINT16

typedef unsigned short *PUINT16; #endif

#ifndef PUINT32

typedef unsigned long *PUINT32; #endif

#ifndef UINT8V

typedef unsigned char volatile UINT8V; #endif

#ifndef PUINT8V

typedef unsigned char volatile *PUINT8V; #endif /*

********************************************************************************************************************* */ /* 硬件特性 */

#define CH376_DAT_BLOCK_LEN 0x40 /* USB单个数据包, 数据块的最大长度, 默认缓冲区的长度 */ /*

********************************************************************************************************************* */ /* 命令代码 */

/* 部分命令兼容CH375芯片, 但是输入数据或者输出数据的可能局部不同) */ /* 一个命令操作顺序包含:

一个命令码(对于串口方式,命令码之前还需要两个同步码), 若干个输入数据(可以是0个),

产生中断通知 或者 若干个输出数据(可以是0个), 二选一, 有中断通知则一定没有输出数据, 有输出数据则一定不产生中断

仅CMD01_WR_REQ_DATA命令例外, 顺序包含: 一个命令码, 一个输出数据, 若干个输入数据

命令码起名规则: CMDxy_NAME

其中的x和y都是数字, x说明最少输入数据个数(字节数), y说明最少输出数据个数(字节数), y如果是H则说明产生中断通知,

有些命令能够实现0到多个字节的数据块读写, 数据块本身的字节数未包含在上述x或y之内 */

/* 本文件默认会同时提供与CH375芯片命令码兼容的命令码格式(即去掉x和y之后), 如果不需要, 那么可以定义_NO_CH375_COMPATIBLE_禁止 */ /*

********************************************************************************************************************* */

/* 主要命令(手册一), 常用 */

#define CMD01_GET_IC_VER 0x01 /* 获取芯片及固件版本 */ /* 输出: 版本号( 位7为0, 位6为1, 位5~位0为版本号 ) */ /* CH376返回版本号的值为041H即版本号为01H */

#define CMD21_SET_BAUDRATE 0x02 /* 串口方式: 设置串口通讯波特率(上电或者复位后的默认波特率为9600bps,由D4/D5/D6引脚选择) */ /* 输入: 波特率分频系数, 波特率分频常数 */

/* 输出: 操作状态( CMD_RET_SUCCESS或CMD_RET_ABORT, 其它值说明操作未完成 ) */

#define CMD00_ENTER_SLEEP 0x03 /* 进入睡眠状态 */

#define CMD00_RESET_ALL

0x05

/* 执行硬件复位 */

#define CMD11_CHECK_EXIST 0x06 /* 测试通讯接口和工作状态 */ /* 输入: 任意数据 */

/* 输出: 输入数据的按位取反 */

#define CMD20_CHK_SUSPEND 0x0B /* 设备方式: 设置检查USB总线挂起状态的方式 */

/* 输入: 数据10H, 检查方式 */

/* 00H=不检查USB挂起, 04H=以50mS为间隔检查USB挂起, 05H=以10mS为间隔检查USB挂起 */

#define CMD20_SET_SDO_INT 0x0B /* SPI接口方式: 设置SPI的SDO引脚的中断方式 */

/* 输入: 数据16H, 中断方式 */

/* 10H=禁止SDO引脚用于中断输出,在SCS片选无效时三态输出禁止, 90H=SDO引脚在SCS片选无效时兼做中断请求输出 */

#define CMD14_GET_FILE_SIZE 0x0C /* 主机文件模式: 获取当前文件长度 */ /* 输入: 数据68H */

/* 输出: 当前文件长度(总长度32位,低字节在前) */

#define CMD50_SET_FILE_SIZE 0x0D /* 主机文件模式: 设置当前文件长度 */ /* 输入: 数据68H, 当前文件长度(总长度32位,低字节在前) */

#define CMD11_SET_USB_MODE 0x15 /* 设置USB工作模式 */ /* 输入: 模式代码 */

/* 00H=未启用的设备方式, 01H=已启用的设备方式并且使用外部固件模式(串口不支持), 02H=已启用的设备方式并且使用内置固件模式 */

/* 03H=SD卡主机模式/未启用的主机模式,用于管理和存取SD卡中的文件 */

/* 04H=未启用的主机方式, 05H=已启用的主机方式, 06H=已启用的主机方式并且自动产生SOF包, 07H=已启用的主机方式并且复位USB总线 */

/* 输出: 操作状态( CMD_RET_SUCCESS或CMD_RET_ABORT, 其它值说明操作未完成 ) */

#define CMD01_GET_STATUS 0x22 /* 输出: 中断状态 */

#define CMD00_UNLOCK_USB 0x23

/* 获取中断状态并取消中断请求 */

/* 设备方式: 释放当前USB缓冲区 */

#define CMD01_RD_USB_DATA0 0x27 /* 从当前USB中断的端点缓冲区或者主机端点的接收缓冲区读取数据块 */ /* 输出: 长度, 数据流 */

#define CMD01_RD_USB_DATA 0x28 /* 设备方式: 从当前USB中断的端点缓冲区读取数据块, 并释放缓冲区, 相当于 CMD01_RD_USB_DATA0 + CMD00_UNLOCK_USB */ /* 输出: 长度, 数据流 */

#define CMD10_WR_USB_DATA7 0x2B /* 设备方式: 向USB端点2的发送缓冲区写入数据块 */

/* 输入: 长度, 数据流 */

#define CMD10_WR_HOST_DATA 0x2C /* 向USB主机端点的发送缓冲区写入数据块 */

/* 输入: 长度, 数据流 */

#define CMD01_WR_REQ_DATA 0x2D /* 向内部指定缓冲区写入请求的数据块 */

/* 输出: 长度 */

/* 输入: 数据流 */

#define CMD20_WR_OFS_DATA 0x2E */

/* 向内部缓冲区指定偏移地址写入数据块

/* 输入: 偏移, 长度, 数据流 */

#define CMD10_SET_FILE_NAME 0x2F /* 主机文件模式: 设置将要操作的文件的文件名 */

/* 输入: 以0结束的字符串(含结束符0在内长度不超过14个字符) */ /*

********************************************************************************************************************* */

/* 主要命令(手册一), 常用, 以下命令总是在操作结束时产生中断通知, 并且总是没有输出数据 */

#define CMD0H_DISK_CONNECT 0x30 否连接 */

/* 输出中断 */

#define CMD0H_DISK_MOUNT 0x31 否就绪 */

/* 输出中断 */

/* 主机文件模式/不支持SD卡: 检查磁盘是

/* 主机文件模式: 初始化磁盘并测试磁盘是

#define CMD0H_FILE_OPEN 0x32 件夹),或者枚举文件和目录(文件夹) */ /* 输出中断 */

#define CMD0H_FILE_ENUM_GO 0x33 (文件夹) */

/* 输出中断 */

/* 主机文件模式: 打开文件或者目录(文

/* 主机文件模式: 继续枚举文件和目录

#define CMD0H_FILE_CREATE 0x34 /* 主机文件模式: 新建文件,如果文件已经存在那么先删除 */ /* 输出中断 */

#define CMD0H_FILE_ERASE 0x35 /* 主机文件模式: 删除文件,如果已经打开则直接删除,否则对于文件会先打开再删除,子目录必须先打开 */ /* 输出中断 */

#define CMD1H_FILE_CLOSE 0x36 /* 主机文件模式: 关闭当前已经打开的文件或者目录(文件夹) */

/* 输入: 是否允许更新文件长度 */

/* 00H=禁止更新长度, 01H=允许更新长度 */

/* 输出中断 */

#define CMD1H_DIR_INFO_READ */

0x37 /* 主机文件模式: 读取文件的目录信息

/* 输入: 指定需要读取的目录信息结构在扇区内的索引号 */

/* 索引号范围为00H~0FH, 索引号0FFH则为当前已经打开的文件 */ /* 输出中断 */

#define CMD0H_DIR_INFO_SAVE */

/* 输出中断 */

#define CMD4H_BYTE_LOCATE 0x39 /* 主机文件模式: 以字节为单位移动当前文件指针 */

/* 输入: 偏移字节数(总长度32位,低字节在前) */ /* 输出中断 */

#define CMD2H_BYTE_READ 0x3A /* 主机文件模式: 以字节为单位从当前位置读取数据块 */

/* 输入: 请求读取的字节数(总长度16位,低字节在前) */ /* 输出中断 */

#define CMD0H_BYTE_RD_GO 0x3B /* 输出中断 */

/* 主机文件模式: 继续字节读 */

0x38

/* 主机文件模式: 保存文件的目录信息

#define CMD2H_BYTE_WRITE 0x3C /* 主机文件模式: 以字节为单位向当前位置写入数据块 */

/* 输入: 请求写入的字节数(总长度16位,低字节在前) */ /* 输出中断 */

#define CMD0H_BYTE_WR_GO 0x3D /* 输出中断 */

#define CMD0H_DISK_CAPACITY 0x3E /* 输出中断 */

#define CMD0H_DISK_QUERY 0x3F /* 输出中断 */

#define CMD0H_DIR_CREATE 0x40 如果目录已经存在那么直接打开 */ /* 输出中断 */

#define CMD4H_SEC_LOCATE 0x4A

/* 主机文件模式: 继续字节写 */

/* 主机文件模式: 查询磁盘物理容量 */

/* 主机文件模式: 查询磁盘空间信息 */

/* 主机文件模式: 新建目录(文件夹)并打开,

/* 主机文件模式: 以扇区为单位移动当

前文件指针 */

/* 输入: 偏移扇区数(总长度32位,低字节在前) */ /* 输出中断 */

#define CMD1H_SEC_READ 0x4B 位从当前位置读取数据块 */ /* 输入: 请求读取的扇区数 */ /* 输出中断 */

#define CMD1H_SEC_WRITE 为单位在当前位置写入数据块 */ /* 输入: 请求写入的扇区数 */ /* 输出中断 */

/* 主机文件模式/不支持SD卡: 以扇区为单

0x4C /* 主机文件模式/不支持SD卡: 以扇区

#define CMD0H_DISK_BOC_CMD 0x50 /* 主机方式/不支持SD卡: 对USB存储

器执行BulkOnly传输协议的命令 */ /* 输出中断 */

#define CMD5H_DISK_READ 0x54 /* 主机方式/不支持SD卡: 从USB存储器读物理扇区 */

/* 输入: LBA物理扇区地址(总长度32位, 低字节在前), 扇区数(01H~FFH) */ /* 输出中断 */

#define CMD0H_DISK_RD_GO 0x55 /* 主机方式/不支持SD卡: 继续执行USB存储器的物理扇区读操作 */ /* 输出中断 */

#define CMD5H_DISK_WRITE 0x56 /* 主机方式/不支持SD卡: 向USB存储器写物理扇区 */

/* 输入: LBA物理扇区地址(总长度32位, 低字节在前), 扇区数(01H~FFH) */ /* 输出中断 */

#define CMD0H_DISK_WR_GO 0x57 /* 主机方式/不支持SD卡: 继续执行USB存储器的物理扇区写操作 */ /* 输出中断 */ /*

********************************************************************************************************************* */

/* 辅助命令(手册二), 不太常用或者是为了与CH375和CH372兼容 */

#define CMD10_SET_USB_SPEED 0x04 /* 设置USB总线速度, 在每次CMD11_SET_USB_MODE设置USB工作模式时会自动恢复到12Mbps全速 */ /* 输入: 总线速度代码 */

/* 00H=12Mbps全速FullSpeed(默认值), 01H=1.5Mbps(仅修改频率), 02H=1.5Mbps低速LowSpeed */

#define CMD11_GET_DEV_RATE 0x0A /* 主机方式: 获取当前连接的USB设备的数据速率类型 */ /* 输入: 数据07H */

/* 输出: 数据速率类型 */

/* 位4为1则是1.5Mbps低速USB设备, 否则是12Mbps全速USB设备 */

#define CMD11_GET_TOGGLE 0x0A /* 获取OUT事务的同步状态 */ /* 输入: 数据1AH */ /* 输出: 同步状态 */

/* 位4为1则OUT事务同步, 否则OUT事务不同步 */

#define CMD11_READ_VAR8 0x0A /* 读取指定的8位文件系统变量 */ /* 输入: 变量地址 */ /* 输出: 数据 */

/*#define CMD11_GET_MAX_LUN = CMD11_READ_VAR8( VAR_UDISK_LUN )*/ /* 主机方式: 获取USB存储器最大和当前逻辑单元号 */

#define CMD20_SET_RETRY 0x0B /* 主机方式: 设置USB事务操作的重试次数 */

/* 输入: 数据25H, 重试次数 */

/* 位7为0则收到NAK时不重试, 位7为1位6为0则收到NAK时无限重试, 位7为1位6为1则收到NAK时最多重试3秒, 位5~位0为超时后的重试次数 */

#define CMD20_WRITE_VAR8 0x0B /* 输入: 变量地址, 数据 */

/* 设置指定的8位文件系统变量 */

/*#define CMD20_SET_DISK_LUN = CMD20_WRITE_VAR8( VAR_UDISK_LUN )*/ /* 主机方式: 设置USB存储器的当前逻辑单元号 */

#define CMD14_READ_VAR32 0x0C /* 读取指定的32位文件系统变量 */ /* 输入: 变量地址 */

/* 输出: 数据(总长度32位,低字节在前) */

#define CMD50_WRITE_VAR32 0x0D /* 设置指定的32位文件系统变量 */ /* 输入: 变量地址, 数据(总长度32位,低字节在前) */

#define CMD01_DELAY_100US 0x0F /* 延时100uS(串口不支持) */ /* 输出: 延时期间输出0,延时结束输出非0 */

#define CMD40_SET_USB_ID 0x12 /* 设备方式: 设置USB厂商VID和产品PID */

/* 输入: 厂商ID低字节, 厂商ID高字节, 产品ID低字节, 产品ID高字节 */

#define CMD10_SET_USB_ADDR 0x13 /* 设置USB地址 */ /* 输入: 地址值 */

#define CMD01_TEST_CONNECT 0x16 /* 主机方式/不支持SD卡: 检查USB设备连接状态 */

/* 输出: 状态( USB_INT_CONNECT或USB_INT_DISCONNECT或USB_INT_USB_READY, 其它值说明操作未完成 ) */

#define CMD00_ABORT_NAK

0x17

/* 主机方式: 放弃当前NAK的重试 */

#define CMD10_SET_ENDP2 0x18 /* 设备方式(串口不支持): 设置USB端点0的接收器 */

/* 输入: 工作方式 */

/* 位7为1则位6为同步触发位, 否则同步触发位不变 */

/* 位3~位0为事务响应方式: 0000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */

#define CMD10_SET_ENDP3 0x19 /* 设备方式(串口不支持): 设置USB端点0的发送器 */

/* 输入: 工作方式 */

/* 位7为1则位6为同步触发位, 否则同步触发位不变 */

/* 位3~位0为事务响应方式: 0000~1000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */

#define CMD10_SET_ENDP4 0x1A /* 设备方式(串口不支持): 设置USB端点1的接收器 */ /* 输入: 工作方式 */

/* 位7为1则位6为同步触发位, 否则同步触发位不变 */

/* 位3~位0为事务响应方式: 0000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */

#define CMD10_SET_ENDP5 0x1B /* 设备方式(串口不支持): 设置USB端点1的发送器 */

/* 输入: 工作方式 */

/* 位7为1则位6为同步触发位, 否则同步触发位不变 */

/* 位3~位0为事务响应方式: 0000~1000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */

#define CMD10_SET_ENDP6 0x1C /* 设置USB端点2/主机端点的接收器 */

/* 输入: 工作方式 */

/* 位7为1则位6为同步触发位, 否则同步触发位不变 */

/* 位3~位0为事务响应方式: 0000-就绪ACK, 1101-就绪但不返回ACK, 1110-正忙NAK, 1111-错误STALL */

#define CMD10_SET_ENDP7 0x1D /* 设置USB端点2/主机端点的发送器 */

/* 输入: 工作方式 */

/* 位7为1则位6为同步触发位, 否则同步触发位不变 */

/* 位3~位0为事务响应方式: 0000-就绪ACK, 1101-就绪但无须应答, 1110-正忙NAK, 1111-错误STALL */

#define CMD00_DIRTY_BUFFER 0x25 冲区 */

#define CMD10_WR_USB_DATA3 的发送缓冲区写入数据块 */ /* 输入: 长度, 数据流 */

/* 主机文件模式: 清除内部的磁盘和文件缓

0x29 /* 设备方式(串口不支持): 向USB端点0

#define CMD10_WR_USB_DATA5 0x2A /* 设备方式(串口不支持): 向USB端点1的发送缓冲区写入数据块 */ /* 输入: 长度, 数据流 */ /*

********************************************************************************************************************* */

/* 辅助命令(手册二), 不太常用或者是为了与CH375和CH372兼容, 以下命令总是在操作结束时产生中断通知, 并且总是没有输出数据 */

#define CMD1H_CLR_STALL 0x41 /* 输入: 端点号 */ /* 输出中断 */

#define CMD1H_SET_ADDRESS 0x45 /* 输入: 地址值 */ /* 输出中断 */

/* 主机方式: 控制传输-清除端点错误 */

/* 主机方式: 控制传输-设置USB地址 */

#define CMD1H_GET_DESCR 0x46 /* 输入: 描述符类型 */ /* 输出中断 */

#define CMD1H_SET_CONFIG 0x49 /* 输入: 配置值 */ /* 输出中断 */

#define CMD0H_AUTO_SETUP 0x4D

/* 主机方式: 控制传输-获取描述符 */

/* 主机方式: 控制传输-设置USB配置 */

/* 主机方式/不支持SD卡: 自动配置

USB设备 */ /* 输出中断 */

#define CMD2H_ISSUE_TKN_X 0x4E /* 主机方式: 发出同步令牌, 执行事务, 该命令可代替 CMD10_SET_ENDP6/CMD10_SET_ENDP7 + CMD1H_ISSUE_TOKEN */ /* 输入: 同步标志, 事务属性 */

/* 同步标志的位7为主机端点IN的同步触发位, 位6为主机端点OUT的同步触发位, 位5~位0必须为0 */

/* 事务属性的低4位是令牌, 高4位是端点号 */ /* 输出中断 */

#define CMD1H_ISSUE_TOKEN 0x4F /* 主机方式: 发出令牌, 执行事务, 建议用CMD2H_ISSUE_TKN_X命令 */ /* 输入: 事务属性 */

/* 低4位是令牌, 高4位是端点号 */ /* 输出中断 */

#define CMD0H_DISK_INIT 器 */

/* 输出中断 */

#define CMD0H_DISK_RESET USB存储器 */ /* 输出中断 */

0x51

/* 主机方式/不支持SD卡: 初始化USB存储

0x52 /* 主机方式/不支持SD卡: 控制传输-复位

#define CMD0H_DISK_SIZE 0x53 的容量 */

/* 输出中断 */

#define CMD0H_DISK_INQUIRY 0x58 特性 */

/* 输出中断 */

#define CMD0H_DISK_READY 0x59 就绪 */

/* 输出中断 */

#define CMD0H_DISK_R_SENSE 0x5A 储器错误 */ /* 输出中断 */

#define CMD0H_RD_DISK_SEC 0x5B 据到内部缓冲区 */ /* 输出中断 */

/* 主机方式/不支持SD卡: 获取USB存储器

/* 主机方式/不支持SD卡: 查询USB存储器

/* 主机方式/不支持SD卡: 检查USB存储器

/* 主机方式/不支持SD卡: 检查USB存

/* 主机文件模式: 从磁盘读取一个扇区的数

#define CMD0H_WR_DISK_SEC 0x5C 的数据写入磁盘 */ /* 输出中断 */

/* 主机文件模式: 将内部缓冲区的一个扇区

#define CMD0H_DISK_MAX_LUN 0x5D /* 主机方式: 控制传输-获取USB存储器最大逻辑单元号 */ /* 输出中断 */ /*

********************************************************************************************************************* */

/* 以下定义只是为了兼容CH375的INCLUDE文件中的命令名称格式 */

#ifndef _NO_CH375_COMPATIBLE_ #define CMD_GET_IC_VER CMD01_GET_IC_VER #define CMD_SET_BAUDRATE CMD21_SET_BAUDRATE #define CMD_ENTER_SLEEP CMD00_ENTER_SLEEP #define CMD_RESET_ALL CMD00_RESET_ALL #define CMD_CHECK_EXIST CMD11_CHECK_EXIST #define CMD_CHK_SUSPEND CMD20_CHK_SUSPEND #define CMD_SET_SDO_INT CMD20_SET_SDO_INT #define CMD_GET_FILE_SIZE CMD14_GET_FILE_SIZE #define CMD_SET_FILE_SIZE CMD50_SET_FILE_SIZE #define CMD_SET_USB_MODE CMD11_SET_USB_MODE #define CMD_GET_STATUS CMD01_GET_STATUS #define CMD_UNLOCK_USB CMD00_UNLOCK_USB #define CMD_RD_USB_DATA0 CMD01_RD_USB_DATA0 #define CMD_RD_USB_DATA CMD01_RD_USB_DATA #define CMD_WR_USB_DATA7 CMD10_WR_USB_DATA7 #define CMD_WR_HOST_DATA CMD10_WR_HOST_DATA #define CMD_WR_REQ_DATA CMD01_WR_REQ_DATA #define CMD_WR_OFS_DATA CMD20_WR_OFS_DATA #define CMD_SET_FILE_NAME CMD10_SET_FILE_NAME #define CMD_DISK_CONNECT CMD0H_DISK_CONNECT #define CMD_DISK_MOUNT CMD0H_DISK_MOUNT #define CMD_FILE_OPEN CMD0H_FILE_OPEN

#define CMD_FILE_ENUM_GO CMD0H_FILE_ENUM_GO #define CMD_FILE_CREATE CMD0H_FILE_CREATE #define CMD_FILE_ERASE CMD0H_FILE_ERASE #define CMD_FILE_CLOSE CMD1H_FILE_CLOSE #define CMD_DIR_INFO_READ CMD1H_DIR_INFO_READ #define CMD_DIR_INFO_SAVE CMD0H_DIR_INFO_SAVE #define CMD_BYTE_LOCATE CMD4H_BYTE_LOCATE

#define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define CMD_BYTE_READ CMD_BYTE_RD_GO CMD_BYTE_WRITE CMD_BYTE_WR_GO CMD_DISK_CAPACITY CMD_DISK_QUERY CMD_DIR_CREATE CMD_SEC_LOCATE CMD_SEC_READ CMD_SEC_WRITE CMD_DISK_BOC_CMD CMD_DISK_READ CMD_DISK_RD_GO CMD_DISK_WRITE CMD_DISK_WR_GO CMD_SET_USB_SPEED CMD_GET_DEV_RATE CMD_GET_TOGGLE CMD_READ_VAR8 CMD_SET_RETRY CMD_WRITE_VAR8 CMD_READ_VAR32 CMD_WRITE_VAR32 CMD_DELAY_100US CMD_SET_USB_ID CMD_SET_USB_ADDR CMD_TEST_CONNECT CMD_ABORT_NAK CMD_SET_ENDP2 CMD_SET_ENDP3 CMD_SET_ENDP4 CMD_SET_ENDP5 CMD_SET_ENDP6 CMD_SET_ENDP7 CMD_DIRTY_BUFFER CMD_WR_USB_DATA3 CMD_WR_USB_DATA5 CMD_CLR_STALL CMD_SET_ADDRESS CMD_GET_DESCR CMD_SET_CONFIG CMD_AUTO_SETUP CMD_ISSUE_TKN_X CMD_ISSUE_TOKEN CMD2H_BYTE_READ CMD0H_BYTE_RD_GO CMD2H_BYTE_WRITE CMD0H_BYTE_WR_GO CMD0H_DISK_CAPACITY CMD0H_DISK_QUERY CMD0H_DIR_CREATE CMD4H_SEC_LOCATE CMD1H_SEC_READ CMD1H_SEC_WRITE CMD0H_DISK_BOC_CMD CMD5H_DISK_READ CMD0H_DISK_RD_GO CMD5H_DISK_WRITE CMD0H_DISK_WR_GO CMD10_SET_USB_SPEED CMD11_GET_DEV_RATE CMD11_GET_TOGGLE CMD11_READ_VAR8 CMD20_SET_RETRY CMD20_WRITE_VAR8 CMD14_READ_VAR32 CMD50_WRITE_VAR32 CMD01_DELAY_100US CMD40_SET_USB_ID CMD10_SET_USB_ADDR CMD01_TEST_CONNECT CMD00_ABORT_NAK CMD10_SET_ENDP2 CMD10_SET_ENDP3 CMD10_SET_ENDP4 CMD10_SET_ENDP5 CMD10_SET_ENDP6 CMD10_SET_ENDP7 CMD00_DIRTY_BUFFER CMD10_WR_USB_DATA3 CMD10_WR_USB_DATA5 CMD1H_CLR_STALL CMD1H_SET_ADDRESS CMD1H_GET_DESCR CMD1H_SET_CONFIG CMD0H_AUTO_SETUP CMD2H_ISSUE_TKN_X CMD1H_ISSUE_TOKEN

#define CMD_DISK_INIT CMD0H_DISK_INIT #define CMD_DISK_RESET CMD0H_DISK_RESET #define CMD_DISK_SIZE CMD0H_DISK_SIZE #define CMD_DISK_INQUIRY CMD0H_DISK_INQUIRY #define CMD_DISK_READY CMD0H_DISK_READY #define CMD_DISK_R_SENSE CMD0H_DISK_R_SENSE #define CMD_RD_DISK_SEC CMD0H_RD_DISK_SEC #define CMD_WR_DISK_SEC CMD0H_WR_DISK_SEC #define CMD_DISK_MAX_LUN CMD0H_DISK_MAX_LUN #endif /*

********************************************************************************************************************* */ /* 并口方式, 状态端口(读命令端口)的位定义 */ #ifndef PARA_STATE_INTB

#define PARA_STATE_INTB 0x80 /* 并口方式状态端口的位7: 中断标志,低有效 */

#define PARA_STATE_BUSY 0x10 /* 并口方式状态端口的位4: 忙标志,高有效 */ #endif /*

********************************************************************************************************************* */ /* 串口方式, 操作命令前的引导同步码 */ #ifndef SER_CMD_TIMEOUT

#define SER_CMD_TIMEOUT 32 /* 串口命令超时时间, 单位为mS, 同步码之间及同步码与命令码之间的间隔应该尽量短, 超时后的处理方式为丢弃 */ #define SER_SYNC_CODE1 0x57 /* 启动操作的第1个串口同步码 */ #define SER_SYNC_CODE2 0xAB /* 启动操作的第2个串口同步码 */ #endif /*

********************************************************************************************************************* */ /* 操作状态 */

#ifndef CMD_RET_SUCCESS #define CMD_RET_SUCCESS 0x51 /* 命令操作成功 */ #define CMD_RET_ABORT 0x5F /* 命令操作失败 */ #endif /*

********************************************************************************************************************* */ /* USB中断状态 */

#ifndef USB_INT_EP0_SETUP

/* 以下状态代码为特殊事件中断, 如果通过CMD20_CHK_SUSPEND启用USB总线挂起检查, 那么必须处理USB总线挂起和睡眠唤醒的中断状态 */ #define USB_INT_USB_SUSPEND0x05 /* USB总线挂起事件 */ #define USB_INT_WAKE_UP 0x06 /* 从睡眠中被唤醒事件 */

/* 以下状态代码0XH用于USB设备方式 */

/* 内置固件模式下只需要处理: USB_INT_EP1_OUT, USB_INT_EP1_IN, USB_INT_EP2_OUT, USB_INT_EP2_IN */

/* 位7-位4为0000 */

/* 位3-位2指示当前事务, 00=OUT, 10=IN, 11=SETUP */

/* 位1-位0指示当前端点, 00=端点0, 01=端点1, 10=端点2, 11=USB总线复位 */ #define USB_INT_EP0_SETUP 0x0C /* USB端点0的SETUP */ #define USB_INT_EP0_OUT 0x00 /* USB端点0的OUT */ #define USB_INT_EP0_IN 0x08 /* USB端点0的IN */ #define USB_INT_EP1_OUT 0x01 /* USB端点1的OUT */ #define USB_INT_EP1_IN 0x09 /* USB端点1的IN */ #define USB_INT_EP2_OUT 0x02 /* USB端点2的OUT */ #define USB_INT_EP2_IN 0x0A /* USB端点2的IN */ /* USB_INT_BUS_RESET 0x0000XX11B */ /* USB总线复位 */ #define USB_INT_BUS_RESET1 0x03 /* USB总线复位 */ #define USB_INT_BUS_RESET2 0x07 /* USB总线复位 */ #define USB_INT_BUS_RESET3 0x0B /* USB总线复位 */ #define USB_INT_BUS_RESET4 0x0F /* USB总线复位 */

#endif

/* 以下状态代码2XH-3XH用于USB主机方式的通讯失败代码 */ /* 位7-位6为00 */ /* 位5为1 */

/* 位4指示当前接收的数据包是否同步 */

/* 位3-位0指示导致通讯失败时USB设备的应答: 0010=ACK, 1010=NAK, 1110=STALL, 0011=DATA0, 1011=DATA1, XX00=超时 */ /* USB_INT_RET_ACK 0x001X0010B */ /* 错误:对于IN事务返回ACK */ /* USB_INT_RET_NAK 0x001X1010B */ /* 错误:返回NAK */ /* USB_INT_RET_STALL 0x001X1110B */ /* 错误:返回STALL */ /* USB_INT_RET_DATA0 0x001X0011B */ /* 错误:对于OUT/SETUP事务返回DATA0 */ /* USB_INT_RET_DATA1 0x001X1011B */ /* 错误:对于OUT/SETUP事务返回DATA1 */ /* USB_INT_RET_TOUT 0x001XXX00B */ /* 错误:返回超时 */

/* USB_INT_RET_TOGX 0x0010X011B */ /* 错误:对于IN事务返回数据不同步 */ /* USB_INT_RET_PID 0x001XXXXXB */ /* 错误:未定义 */

/* 以下状态代码1XH用于USB主机方式的操作状态代码 */ #ifndef USB_INT_SUCCESS #define USB_INT_SUCCESS #define USB_INT_CONNECT 连接或者断开后重新连接 */ #define USB_INT_DISCONNECT #define USB_INT_BUF_OVER 溢出 */

#define USB_INT_USB_READY */

0x14 0x15 0x16 0x17 0x18

/* USB事务或者传输操作成功 */ /* 检测到USB设备连接事件, 可能是新/* 检测到USB设备断开事件 */

/* USB传输的数据有误或者数据太多缓冲区/* USB设备已经被初始化(已经分配USB地址)

#define USB_INT_DISK_READ 0x1D /* USB存储器请求数据读出 */ #define USB_INT_DISK_WRITE 0x1E /* USB存储器请求数据写入 */ #define USB_INT_DISK_ERR 0x1F /* USB存储器操作失败 */ #endif

/* 以下状态代码用于主机文件模式下的文件系统错误码 */ #ifndef ERR_DISK_DISCON

#define ERR_DISK_DISCON 0x82 /* 磁盘尚未连接,可能磁盘已经断开 */ #define ERR_LARGE_SECTOR 0x84 /* 磁盘的扇区太大,只支持每扇区512字节 */

#define ERR_TYPE_ERROR 0x92 /* 磁盘分区类型不支持,只支持FAT12/FAT16/BigDOS/FAT32,需要由磁盘管理工具重新分区 */ #define ERR_BPB_ERROR 0xA1 /* 磁盘尚未格式化,或者参数错误,需要由WINDOWS采用默认参数重新格式化 */ #define ERR_DISK_FULL 0xB1 /* 磁盘文件太满,剩余空间太少或者已经没有,需要磁盘整理 */

#define ERR_FDT_OVER 0xB2 /* 目录(文件夹)内文件太多,没有空闲的目录项,FAT12/FAT16根目录下的文件数应该少于512个,需要磁盘整理 */ #define ERR_FILE_CLOSE 0xB4 /* 文件已经关闭,如果需要使用,应该重新打开文件 */

#define ERR_OPEN_DIR 0x41 /* 指定路径的目录(文件夹)被打开 */ #define ERR_MISS_FILE 0x42 /* 指定路径的文件没有找到,可能是文件名称错误 */

#define ERR_FOUND_NAME 0x43 /* 搜索到相匹配的文件名,或者是要求打开目录(文件夹)而实际结果却打开了文件 */ /* 以下文件系统错误码用于文件系统子程序 */ #define ERR_MISS_DIR 0xB3 /* 指定路径的某个子目录(文件夹)没有找到,可能是目录名称错误 */

#define ERR_LONG_BUF_OVER 0x48 /* 长文件缓冲区溢出 */ #define ERR_LONG_NAME_ERR 0x49 /* 短文件名没有对应的长文件名或者长文件名错误 */

#define ERR_NAME_EXIST 0x4A /* 同名的短文件已经存在,建议重新生成另外一个短文件名 */ #endif /*

********************************************************************************************************************* */

/* 以下状态代码用于主机文件模式下的磁盘及文件状态, VAR_DISK_STATUS */ #ifndef DEF_DISK_UNKNOWN #define DEF_DISK_UNKNOWN #define DEF_DISK_DISCONN #define DEF_DISK_CONNECT 识别该磁盘 */

#define DEF_DISK_MOUNTED 系统或者文件系统不支持 */ #define DEF_DISK_READY */

0x00 0x01 0x02 0x03 0x10

/* 尚未初始化,未知状态 */

/* 磁盘没有连接或者已经断开 */

/* 磁盘已经连接,但是尚未初始化或者无法/* 磁盘已经初始化成功,但是尚未分析文件/* 已经分析磁盘的文件系统并且能够支持

#define DEF_DISK_OPEN_ROOT 0x12 /* 已经打开根目录,使用后必须关闭,注意FAT12/FAT16根目录是固定长度 */ #define DEF_DISK_OPEN_DIR 0x13 /* 已经打开子目录(文件夹) */ #define DEF_DISK_OPEN_FILE 0x14 /* 已经打开文件 */ #endif /*

********************************************************************************************************************* */ /* 文件系统常用定义 */

#ifndef DEF_SECTOR_SIZE #define DEF_SECTOR_SIZE 512 /* U盘或者SD卡默认的物理扇区的大小 */ #endif

#ifndef DEF_WILDCARD_CHAR

#define DEF_WILDCARD_CHAR 0x2A /* 路径名的通配符 '*' */ #define DEF_SEPAR_CHAR1 0x5C /* 路径名的分隔符 '\\' */ #define DEF_SEPAR_CHAR2 0x2F /* 路径名的分隔符 '/' */ #define DEF_FILE_YEAR 2004 /* 默认文件日期: 2004年 */ #define DEF_FILE_MONTH 1 /* 默认文件日期: 1月 */ #define DEF_FILE_DATE 1 /* 默认文件日期: 1日 */ #endif

#ifndef ATTR_DIRECTORY

/* FAT数据区中文件目录信息 */ typedef struct _FAT_DIR_INFO { UINT8 DIR_Name[11]; */

UINT8 DIR_Attr; UINT8 DIR_NTRes; UINT8 DIR_CrtTimeTenth; UINT16 DIR_CrtTime; UINT16 DIR_CrtDate; UINT16 DIR_LstAccDate; UINT16 DIR_FstClusHI; UINT16 DIR_WrtTime; MAKE_FILE_TIME */ UINT16 DIR_WrtDate; MAKE_FILE_DATE */ UINT16 DIR_FstClusLO;

/* 00H,文件名,共11字节,不足处填空格

/* 0BH,文件属性,参考后面的说明 */ /* 0CH */

/* 0DH,文件创建的时间,以0.1秒单位计数 */ /* 0EH,文件创建的时间 */ /* 10H,文件创建的日期 */ /* 12H,最近一次存取操作的日期 */ /* 14H */

/* 16H,文件修改时间,参考前面的宏/* 18H,文件修改日期,参考前面的宏

/* 1AH */

UINT32 DIR_FileSize; /* 1CH,文件长度 */ } FAT_DIR_INFO, *P_FAT_DIR_INFO; /* 20H */

/* 文件属性 */

#define ATTR_READ_ONLY 0x01 /* 文件为只读属性 */ #define ATTR_HIDDEN 0x02 /* 文件为隐含属性 */ #define ATTR_SYSTEM 0x04 /* 文件为系统属性 */ #define ATTR_VOLUME_ID 0x08 /* 卷标 */ #define ATTR_DIRECTORY 0x10 /* 子目录(文件夹) */ #define ATTR_ARCHIVE 0x20 /* 文件为存档属性 */ #define ATTR_LONG_NAME ( ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID ) /* 长文件名属性 */ #define ATTR_LONG_NAME_MASK ( ATTR_LONG_NAME ATTR_ARCHIVE )

/* 文件属性 UINT8 */

/* bit0 bit1 bit2 bit3 bit4 bit5 bit6 bit7 */

/* 只 隐 系 卷 目 存 未定义 */ /* 读 藏 统 标 录 档 */ /* 文件时间 UINT16 */

/* Time = (Hour<<11) + (Minute<<5) + (Second>>1) */ #define MAKE_FILE_TIME( h, m, s ) ( (h<<11) + (m<<5) + (s>>1) ) /* 生成指定时分秒的文件时间数据 */

/* 文件日期 UINT16 */

/* Date = ((Year-1980)<<9) + (Month<<5) + Day */ #define MAKE_FILE_DATE( y, m, d ) ( ((y-1980)<<9) + (m<<5) + d ) /* 生成指定年月日的文件日期数据 */

#define LONE_NAME_MAX_CHAR (255*2) /* 长文件名最多字符数/字节数 */

|

ATTR_DIRECTORY

|

#define LONG_NAME_PER_DIR (13*2) /* 长文件名在每个文件目录信息结构中的字符数/字节数 */

#endif /*

********************************************************************************************************************* */ /* SCSI命令和数据输入输出结构 */

#ifndef SPC_CMD_INQUIRY

/* SCSI命令码 */

#define SPC_CMD_INQUIRY #define SPC_CMD_READ_CAPACITY #define SPC_CMD_READ10 #define SPC_CMD_WRITE10 #define SPC_CMD_TEST_READY #define SPC_CMD_REQUEST_SENSE #define SPC_CMD_MODESENSE6 #define SPC_CMD_MODESENSE10 #define SPC_CMD_START_STOP

/* BulkOnly协议的命令块 */ typedef struct _BULK_ONLY_CBW { UINT32 CBW_Sig; UINT32 CBW_Tag;

0x12

0x25 0x28 0x2A 0x00 0x03 0x1A 0x5A 0x1B

UINT8 CBW_DataLen0; /* 08H,输入: 数据传输长度,对于输入数据其有效值是0到48,对于输出数据其有效值为0到33 */ UINT8 CBW_DataLen1; UINT16 CBW_DataLen2; UINT8 CBW_Flag; /* 0CH,输入: 传输方向等标志,位7为1则输入数据,位为0则输出数据或者没有数据 */ UINT8 CBW_LUN; UINT8 CBW_CB_Len; /* 0EH,输入: 命令块的长度,有效值是1到16 */ UINT8 CBW_CB_Buf[16]; /* 0FH,输入: 命令块,该缓冲区最多为16个字节 */

} BULK_ONLY_CBW, *P_BULK_ONLY_CBW; /* BulkOnly协议的命令块, 输入CBW结构 */

/* INQUIRY命令的返回数据 */ typedef struct _INQUIRY_DATA { UINT8 DeviceType; /* 00H, 设备类型 */

UINT8 RemovableMedia; UINT8 Versions; UINT8 DataFormatAndEtc; UINT8 AdditionalLength; UINT8 Reserved1; UINT8 Reserved2; UINT8 MiscFlag; UINT8 VendorIdStr[8]; UINT8 ProductIdStr[16]; UINT8 ProductRevStr[4]; } INQUIRY_DATA, *P_INQUIRY_DATA;

/* 01H, 位7为1说明是移动存储 */ /* 02H, 协议版本 */

/* 03H, 指定返回数据格式 */ /* 04H, 后续数据的长度 */

/* 07H, 一些控制标志 */ /* 08H, 厂商信息 */ /* 10H, 产品信息 */ /* 20H, 产品版本 */ /* 24H */

/* REQUEST SENSE命令的返回数据 */ typedef struct _SENSE_DATA {

UINT8 UINT8

ErrorCode; SegmentNumber;

/* 00H, 错误代码及有效位 */

UINT8 SenseKeyAndEtc; /* 02H, 主键码 */ UINT8 Information0; UINT8 Information1; UINT8 Information2; UINT8 Information3; UINT8 AdditSenseLen; /* 07H, 后续数据的长度 */ UINT8 CmdSpecInfo[4]; UINT8 AdditSenseCode; /* 0CH, 附加键码 */ UINT8 AddSenCodeQual; /* 0DH, 详细的附加键码 */ UINT8 FieldReplaUnit; UINT8 SenseKeySpec[3]; } SENSE_DATA, *P_SENSE_DATA; /* 12H */

#endif /*

********************************************************************************************************************* */ /* 主机文件模式下的数据输入和输出结构 */

#ifndef MAX_FILE_NAME_LEN

#define MAX_FILE_NAME_LEN (13+1) /* 文件名最大长度,最大长度是1个根目录符+8个主文件名+1个小数点+3个类型名+结束符=14 */

/* 命令的输入数据和输出数据 */ typedef union _CH376_CMD_DATA { struct {

UINT8 mBuffer[ MAX_FILE_NAME_LEN ]; } Default; INQUIRY_DATA DiskMountInq; /* 返回: INQUIRY命令的返回数据 */ /* CMD0H_DISK_MOUNT: 初始化磁盘并测试磁盘是否就绪,首次执行时 */ FAT_DIR_INFO OpenDirInfo; /* 返回: 枚举到的文件目录信息 */ /* CMD0H_FILE_OPEN: 枚举文件和目录(文件夹) */ FAT_DIR_INFO EnumDirInfo; /* 返回: 枚举到的文件目录信息 */ /* CMD0H_FILE_ENUM_GO: 继续枚举文件和目录(文件夹) */ struct { UINT8 mUpdateFileSz; 则禁止更新长度 */ } FileCLose; 文件 */ struct {

/* 输入参数: 是否允许更新文件长度, 0

/* CMD1H_FILE_CLOSE: 关闭当前已经打开的

UINT8 mDirInfoIndex; /* 输入参数: 指定需要读取的目录信息结构在扇区内的索引号, 0FFH则为当前已经打开的文件 */ } DirInfoRead; /* CMD1H_DIR_INFO_READ: 读取文件的目录信息 */ union { UINT32 mByteOffset; /* 输入参数: 偏移字节数,以字节为单位的偏移量(总长度32位,低字节在前) */ UINT32 mSectorLba; /* 返回: 当前文件指针对应的绝对线性扇区号,0FFFFFFFFH则已到文件尾(总长度32位,低字节在前) */ } ByteLocate; /* CMD4H_BYTE_LOCATE: 以字节为单位移动当前文件指针 */ struct { UINT16 mByteCount; /* 输入参数: 请求读取的字节数(总长度16位,低字节在前) */ } ByteRead; /* CMD2H_BYTE_READ: 以字节为单位从当前位置读取数据块 */ struct { UINT16 mByteCount; /* 输入参数: 请求写入的字节数(总长度16位,低字节在前) */

} ByteWrite; 前位置写入数据块 */ union {

/* CMD2H_BYTE_WRITE: 以字节为单位向当

UINT32 mSectorOffset; /* 输入参数: 偏移扇区数,以扇区为单位的偏移量(总长度32位,低字节在前) */ UINT32 mSectorLba; /* 返回: 当前文件指针对应的绝对线性扇区号,0FFFFFFFFH则已到文件尾(总长度32位,低字节在前) */ } SectorLocate; 动当前文件指针 */ struct { UINT8 mSectorCount;

UINT8 mReserved1; UINT8 mReserved2;

UINT8

mReserved3;

UINT32 mStartSector; 扇区号(总长度32位,低字节在前) */ } SectorRead;

位置读取数据块 */ struct { UINT8 mSectorCount; UINT8 mReserved1; UINT8 mReserved2; UINT8 mReserved3; UINT32 mStartSector; 扇区号(总长度32位,低字节在前) */ } SectorWrite;

位置写入数据块 */ struct { UINT32 mDiskSizeSec; 32位,低字节在前) */ } DiskCapacity;

量 */ struct { UINT32 mTotalSector; 位,低字节在前) */ UINT32 mFreeSector;

32位,低字节在前) */

/* CMD4H_SEC_LOCATE: 以扇区为单位移 /* 输入参数: 请求读取的扇区数 */

/* 返回: 允许读取的扇区数 */

/* 返回: 允许读取的扇区块的起始绝对线性/* CMD1H_SEC_READ: 以扇区为单位从当前

/* 输入参数: 请求写入的扇区数 */ /* 返回: 允许写入的扇区数 */

/* 返回: 允许写入的扇区块的起始绝对线性/* CMD1H_SEC_WRITE: 以扇区为单位在当前

/* 返回: 整个物理磁盘的总扇区数(总长度/* CMD0H_DISK_CAPACITY: 查询磁盘物理容

/* 返回: 当前逻辑盘的总扇区数(总长度32/* 返回: 当前逻辑盘的剩余扇区数(总长度

UINT8 mDiskFat; 型,1-FAT12,2-FAT16,3-FAT32 */ } DiskQuery;

BULK_ONLY_CBW DiskBocCbw;

器执行BulkOnly传输协议的命令 */ struct { UINT8 mMaxLogicUnit; */ } DiskMaxLun;

USB存储器最大逻辑单元号 */

INQUIRY_DATA DiskInitInq;

*/ INQUIRY_DATA DiskInqData;

器特性 */

SENSE_DATA ReqSenseData;

*/

器错误 */ struct { UINT32 mDiskSizeSec; 32位,高字节在前) */ } DiskSize;

容量 */ struct { UINT32 mStartSector; 节在前) */ UINT8 mSectorCount;

} DiskRead;

数据块(以扇区为单位) */ struct { UINT32 mStartSector; 节在前) */ UINT8 mSectorCount;

/* 返回: 当前逻辑盘的FAT类

/* CMD_DiskQuery, 查询磁盘信息 */ /* 输入参数: CBW命令结构 */

/* CMD0H_DISK_BOC_CMD: 对USB存储

/* 返回: USB存储器的最大逻辑单元号/* CMD0H_DISK_MAX_LUN: 控制传输-获取

/* 返回: INQUIRY命令的返回数据 */ /* CMD0H_DISK_INIT: 初始化USB存储器/* 返回: INQUIRY命令的返回数据 */ /* CMD0H_DISK_INQUIRY: 查询USB存储

/* 返回: REQUEST SENSE命令的返回数据

/* CMD0H_DISK_R_SENSE: 检查USB存储

/* 返回: 整个物理磁盘的总扇区数(总长度

/* CMD0H_DISK_SIZE: 获取USB存储器的

/* 输入参数: LBA扇区地址(总长度32位,低字 /* 输入参数: 请求读取的扇区数 */

/* CMD5H_DISK_READ: 从USB存储器读

/* 输入参数: LBA扇区地址(总长度32位,低字

/* 输入参数: 请求写入的扇区数 */

} DiskWrite; /* CMD5H_DISK_WRITE: 向USB存储器写数据块(以扇区为单位) */

} CH376_CMD_DATA, *P_CH376_CMD_DATA;

#endif /*

********************************************************************************************************************* */ /* 主机文件模式下的文件系统变量的地址 */

#ifndef VAR_FILE_SIZE

/* 8位/单字节变量 */

#define VAR_SYS_BASE_INFO 0x20 /* 当前系统的基本信息 */

/* 位6用于指示USB存储设备的子类别SubClass-Code, 位6为0则说明子类别为6, 位6为1则说明子类别是非6的其它值 */

/* 位5用于指示USB设备方式下的USB配置状态和USB主机方式下的USB设备连接状态 */

/* USB设备方式下, 位5为1则USB配置完成, 位5位0则尚未配置 */ /* USB主机方式下, 位5为1则USB端口存在USB设备, 位5位0则USB端口没有USB设备 */

/* 位4用于指示USB设备方式下的缓冲区锁定状态, 位4为1则说明USB缓冲区处于锁定状态, 位6为1则说明已经释放 */ /* 其它位, 保留,请勿修改 */ #define VAR_RETRY_TIMES 0x25 /* USB事务操作的重试次数 */

/* 位7为0则收到NAK时不重试, 位7为1位6为0则收到NAK时无限重试(可以用CMD_ABORT_NAK命令放弃重试), 位7为1位6为1则收到NAK时最多重试3秒 */ /* 位5~位0为超时后的重试次数 */ #define VAR_FILE_BIT_FLAG 0x26 /* 主机文件模式下的位标志 */

/* 位1和位0, 逻辑盘的FAT文件系统标志, 00-FAT12, 01-FAT16, 10-FAT32, 11-非法 */

/* 位2, 当前缓冲区中的FAT表数据是否被修改标志, 0-未修改, 1-已修改 */ /* 位3, 文件长度需要修改标志, 当前文件被追加数据, 0-未追加无需修改, 1-已追加需要修改 */

/* 其它位, 保留,请勿修改 */ #define VAR_DISK_STATUS 0x2B /* 主机文件模式下的磁盘及文件状态 */ #define VAR_SD_BIT_FLAG 0x30 /* 主机文件模式下SD卡的位标志 */ /* 位0, SD卡版本, 0-只支持SD第一版,1-支持SD第二版 */ /* 位1, 自动识别, 0-SD卡, 1-MMC卡 */

/* 位2, 自动识别, 0-标准容量SD卡, 1-大容量SD卡(HC-SD) */ /* 位4, ACMD41命令超时 */ /* 位5, CMD1命令超时 */ /* 位6, CMD58命令超时 */

/* 其它位, 保留,请勿修改 */ #define VAR_UDISK_TOGGLE 0x31 /* USB存储设备的BULK-IN/BULK-OUT端点的同步标志 */

/* 位7, Bulk-In端点的同步标志 */ /* 位6, Bulk-In端点的同步标志 */ /* 位5~位0, 必须为0 */ #define VAR_UDISK_LUN 0x34 /* USB存储设备的逻辑单元号 */

/* 位7~位4, USB存储设备的当前逻辑单元号,CH376初始化USB存储设备后,默认是访问0#逻辑单元 */

/* 位3~位0, USB存储设备的最大逻辑单元号,加1后等于逻辑单元数 */ #define VAR_SEC_PER_CLUS 0x38 /* 逻辑盘的每簇扇区数 */ #define VAR_FILE_DIR_INDEX 0x3B /* 当前文件目录信息在扇区内的索引号 */ #define VAR_CLUS_SEC_OFS 0x3C /* 当前文件指针在簇内的扇区偏移,为0xFF则指向文件末尾,簇结束 */

/* 32位/4字节变量 */

#define VAR_DISK_ROOT 0x44 /* 对于FAT16盘为根目录占用扇区数,对于FAT32盘为根目录起始簇号(总长度32位,低字节在前) */ #define VAR_DSK_TOTAL_CLUS 0x48 /* 逻辑盘的总簇数(总长度32位,低字节在前) */

#define VAR_DSK_START_LBA 0x4C /* 逻辑盘的起始绝对扇区号LBA(总长度32位,低字节在前) */

#define VAR_DSK_DAT_START 0x50 /* 逻辑盘的数据区域的起始LBA(总长度32位,低字节在前) */

#define VAR_LBA_BUFFER 0x54 /* 当前磁盘数据缓冲区的数据对应的LBA(总长度32位,低字节在前) */ #define VAR_LBA_CURRENT 0x58 /* 当前读写的磁盘起始LBA地址(总长度32位,低字节在前) */

#define VAR_FAT_DIR_LBA 0x5C /* 当前文件目录信息所在的扇区LBA地址(总长度32位,低字节在前) */

#define VAR_START_CLUSTER 0x60 /* 当前文件或者目录(文件夹)的起始簇号(总长度32位,低字节在前) */

#define VAR_CURRENT_CLUST 0x64 /* 当前文件的当前簇号(总长度32位,低字节在前) */

#define VAR_FILE_SIZE 0x68 /* 当前文件的长度(总长度32位,低字节在前) */ #define VAR_CURRENT_OFFSET 0x6C /* 当前文件指针,当前读写位置的字节偏移(总长度32位,低字节在前) */

#endif /*

********************************************************************************************************************* */ /* 常用USB定义 */

/* USB的包标识PID, 主机方式可能用到 */ #ifndef DEF_USB_PID_SETUP #define DEF_USB_PID_NULL 0x00 #define DEF_USB_PID_SOF 0x05 #define DEF_USB_PID_SETUP 0x0D #define DEF_USB_PID_IN 0x09 #define DEF_USB_PID_OUT 0x01 #define DEF_USB_PID_ACK 0x02 #define DEF_USB_PID_NAK 0x0A #define DEF_USB_PID_STALL 0x0E #define DEF_USB_PID_DATA0 0x03 #define DEF_USB_PID_DATA1 0x0B #define DEF_USB_PID_PRE 0x0C #endif

/* USB请求类型, 外置固件模式可能用到 */ #ifndef DEF_USB_REQ_TYPE

#define DEF_USB_REQ_READ 0x80 #define DEF_USB_REQ_WRITE 0x00 #define DEF_USB_REQ_TYPE 0x60 #define DEF_USB_REQ_STAND 0x00 #define DEF_USB_REQ_CLASS 0x20 #define DEF_USB_REQ_VENDOR 0x40 #define DEF_USB_REQ_RESERVE 0x60 #endif

/* 保留PID, 未定义 */

/* 控制读操作 */ /* 控制写操作 */ /* 控制请求类型 */ /* 标准请求 */ /* 设备类请求 */ /* 厂商请求 */ /* 保留请求 */

/* USB标准设备请求, RequestType的位6位5=00(Standard), 外置固件模式可能用到 */ #ifndef DEF_USB_GET_DESCR

#define DEF_USB_CLR_FEATURE 0x01 #define DEF_USB_SET_FEATURE 0x03 #define DEF_USB_GET_STATUS 0x00 #define DEF_USB_SET_ADDRESS 0x05 #define DEF_USB_GET_DESCR 0x06 #define DEF_USB_SET_DESCR 0x07 #define DEF_USB_GET_CONFIG 0x08 #define DEF_USB_SET_CONFIG 0x09 #define DEF_USB_GET_INTERF 0x0A #define DEF_USB_SET_INTERF 0x0B #define DEF_USB_SYNC_FRAME 0x0C #endif /*

*******************************************************************************

************************************** */

#ifdef __cplusplus }

#endif

#endif

CH376HFT.C文件

/* 2008.10.18

**************************************** ** Copyright (C) W.ch 1999-2009 ** ** Web: http://www.winchiphead.com ** **************************************** ** USB Host File Interface for CH376 **

** TC2.0@PC, KC7.0@MCS51 ** **************************************** */

/* CH376 主机文件系统接口 */

/* MCS-51单片机C语言的U盘文件读写示例程序 */

/* 本程序演示字节读写,文件枚举,文件复制, 用于将U盘中的/C51/CH376HFT.C文件中的小写字母转成大写字母后, 写到新建的文件NEWFILE.TXT中,

如果找不到原文件CH376HFT.C, 那么该程序将显示C51子目录下所有以CH376开头的文件名, 并新建NEWFILE.TXT文件并写入提示信息,

如果找不到C51子目录, 那么该程序将显示根目录下的所有文件名, 并新建NEWFILE.TXT文件并写入提示信息 */

/* C51 CH376HFT.C */ /* LX51 CH376HFT.OBJ */ /* OHX51 CH376HFT */

#include #include #include

#define EN_DISK_QUERY 1 /* 启用磁盘查询 */

#include \

#include \#include \

#include \

#include \ /* 软件模拟SPI方式 */ #include \#include \

UINT8 idata buf[64];

void main(void) { UINT8 i, s; UINT16 len; P_FAT_DIR_INFO pDir; UINT8 xdata SrcName[64]; UINT8 xdata TarName[64];

mDelaymS( 100 ); /* 延时100毫秒 */

mInitSTDIO( ); /* 为了让计算机通过串口监控演示过程 */ printf( \系统启动---Start\\n\

s = mInitCH376Host( ); /* 初始化CH376 */ mStopIfError( s ); /* 其它电路初始化 */ while ( 1 ) {

printf( \等待U盘或者SD卡插入---Wait Udisk/SD\\n\while ( CH376DiskConnect( ) != USB_INT_SUCCESS ) {

/* 检查U盘是否连接,等待U盘插入,对于SD卡,可以由单片机直接查询SD卡座的插拔状态引脚 */ mDelaymS( 100 ); } mDelaymS( 200 ); /* 延时,可选操作,有的USB存储器需要几十毫秒的延时 */ /* 对于检测到USB设备的,最多等待100*50mS,主要针对有些MP3太慢,对于检测到USB设备并且连接DISK_MOUNTED的,最多等待5*50mS,主要针对DiskReady不过的 */ for ( i = 0; i < 100; i ++ ) { /* 最长等待时间,100*50mS */ mDelaymS( 50 ); printf( \准备好了? ---- Ready ?\\n\ s = CH376DiskMount( ); /* 初始化磁盘并测试磁盘是否就绪 */ if ( s == USB_INT_SUCCESS ) break; /* 准备好 */ else

if ( s == ERR_DISK_DISCON )

break; /* 检测到断开,重新检测并计时 */

if ( CH376GetDiskStatus( ) >= DEF_DISK_MOUNTED && i >= 5 )

break; /* 有的U盘总是返回未准备好,不过可以忽略,只要其建立连接MOUNTED且尝试5*50mS */ } if ( s == ERR_DISK_DISCON ) {

}

/* 检测到断开,重新检测并计时 */ printf( \设备已断开---Device gone\\n\continue;

if ( CH376GetDiskStatus( ) < DEF_DISK_MOUNTED ) {

/* 未知USB设备,例如USB键盘、打印机等 */ printf( \ goto UnknownUsbDevice; } i = CH376ReadBlock( buf ); /* 如果需要,可以读取数据块CH376_CMD_DATA.DiskMountInq,返回长度 */ if ( i == sizeof( INQUIRY_DATA ) ) {

}

/* U盘的厂商和产品信息 */ buf[ i ] = 0;

printf( \盘厂商---UdiskInfo: %s\\n\

/* 读取文件 */ strcpy( SrcName, \ /* 源文件名,多级目录下的文件名和路径名必须复制到RAM中再处理,而根目录或者当前目录下的文件名可以在RAM或者ROM中 */ strcpy( TarName, \ /* 目标文件名 */ printf( \打开文件 --- Open\\n\ s = CH376FileOpenPath( SrcName ); /* 打开文件,该文件在C51子目录下 */ if ( s == ERR_MISS_DIR || s == ERR_MISS_FILE ) { /* 没有找到目录或者没有找到文件 */ /* 列出文件,完整枚举可以参考EXAM13全盘枚举 */ if ( s == ERR_MISS_DIR ) strcpy( buf, \ /* C51子目录不存在则列出根目录下的文件 */ else strcpy( buf, \); /* CH376HFT.C文件不存在则列出\\C51子

目录下的以CH376开头的文件 */ printf( \列举所有文件---List file %s\\n\ s = CH376FileOpenPath( buf ); /* 枚举多级目录下的文件或者目录,输入缓冲区必须在RAM中 */ while ( s == USB_INT_DISK_READ ) { /* 枚举到匹配的文件 */ CH376ReadBlock( buf ); /* 读取枚举到的文件的FAT_DIR_INFO结构,返回长度总是sizeof( FAT_DIR_INFO ) */ pDir = (P_FAT_DIR_INFO)buf; /* 当前文件目录信息 */ if ( pDir -> DIR_Name[0] != '.' ) { /* 不是本级或者上级目录名则继续,否则必须丢弃不处理 */ if ( pDir -> DIR_Name[0] == 0x05 ) pDir -> DIR_Name[0] = 0xE5; /* 特殊字符替换 */ pDir -> DIR_Attr = 0; /* 强制文件名字符串结束以便打印输出 */ /* 打印名称,原始8+3格式,未整理成含小数点分隔符 */ printf( \ } xWriteCH376Cmd( CMD0H_FILE_ENUM_GO ); /* 继续枚举文件和目录 */ xEndCH376Cmd( ); s = Wait376Interrupt( ); } if ( s != ERR_MISS_FILE ) mStopIfError( s ); /* 操作出错 */ /*--- 新建一个文件 ---*/ printf( \新文件被创建---Create\\n\ s = CH376FileCreatePath( TarName ); /* 新建多级目录下的文件,支持多级目录路径,输入缓冲区必须在RAM中 */ mStopIfError( s ); printf( \新文件被写入---Write\\n\ strcpy( buf, \找不到/C51/CH376HFT.C文件,欢迎使用一鸣电子模块!\\xd\\n\ s = CH376ByteWrite( buf, strlen(buf), NULL ); /* 以字节为单位向当前位置写入数据块 */ mStopIfError( s ); printf( \新文件被关闭---Close\\n\ s = CH376FileClose( TRUE ); /* 关闭文件,对于字节读写建议自动更新文件长度 */ mStopIfError( s ); printf(\

strcpy( TarName, \ /* 目标文件名 */

/*--- 新建另外一个文件;文件名:yimingtest.txt ---*/ printf( \创建另外一个文件---Create\\n\s = CH376FileCreatePath( TarName ); mStopIfError( s );

printf( \新文件被写入----Write\\n\strcpy( buf, \恭喜发财了!\\xd\\n\

s = CH376ByteWrite( buf, strlen(buf) , NULL); mStopIfError ( s );

printf( \文件被关闭 --- Close\\n\s = CH376FileClose(TRUE); mStopIfError( s );

/*--- 追加文件数据的例子 ---*/ printf( \

strcpy( SrcName, \

s = CH376FileOpenPath( SrcName ); printf( \ if( s == USB_INT_SUCCESS ) {

//成功打开文件

strcpy( buf, \是不是要请哥们吃饭了呢?\\xd\\n\CH376ByteLocate(0xFFFFFFFF);

s = CH376ByteWrite( buf, strlen(buf) , NULL); mStopIfError ( s );

printf( \文件被关闭 --- Close\\n\ s = CH376FileClose(TRUE); mStopIfError( s ); } else mStopIfError( s ); /*--- 读取文件数据的例子 ---*/ printf( \

printf( \读取文件数据的例子:\\n\strcpy( SrcName, \

s = CH376FileOpenPath( SrcName ); printf( \ if( s == USB_INT_SUCCESS ) { len = CH376GetFileSize(); CH376ByteLocate( 0 ); CH376ByteRead(buf,len,NULL); printf( \

mStopIfError ( s ); printf( \文件被关闭 --- Close\\n\ s = CH376FileClose(TRUE); mStopIfError( s ); } else mStopIfError( s ); } else { /* 找到文件或者出错 */ mStopIfError( s ); }

UnknownUsbDevice: }

}

printf( \设备拔出 --- Take out\\n\

while ( CH376DiskConnect( ) == USB_INT_SUCCESS ) { /* 检查U盘是否连接,等待U盘拔出 */ mDelaymS( 100 ); }

mDelaymS( 200 );

SPI_SW.C 文件

/* CH376芯片 软件模拟SPI串行连接的硬件抽象层 V1.0 */ /* 提供I/O接口子程序 */

#include \

/* 本例中的硬件连接方式如下(实际应用电路可以参照修改下述定义及子程序) */ /* 单片机的引脚 CH376芯片的引脚 P1.4 SCS P1.5 SDI P1.6 SDO

P1.7 SCK */ sbit P24 = P2^4; sbit P25 = P2^5; sbit P26 = P2^6;

sbit P27 = P2^7;

#define CH376_SPI_SCS P24 /* 假定CH376的SCS引脚 */ #define CH376_SPI_SDI P25 /* 假定CH376的SDI引脚 */ #define CH376_SPI_SDO P26 /* 假定CH376的SDO引脚 */ #define CH376_SPI_SCK P27 /* 假定CH376的SCK引脚 */

#define CH376_INT_WIRE INT0 /* 假定CH376的INT#引脚,如果未连接那么也可以通过查询兼做中断输出的SDO引脚状态实现 */

void CH376_PORT_INIT( void ) /* 由于使用软件模拟SPI读写时序,所以进行初始化 */ {

/* 如果是硬件SPI接口,那么可使用mode3(CPOL=1&CPHA=1)或mode0(CPOL=0&CPHA=0),CH376在时钟上升沿采样输入,下降沿输出,数据位是高位在前 */ CH376_SPI_SCS = 1; /* 禁止SPI片选 */ CH376_SPI_SCK = 1; /* 默认为高电平,SPI模式3,也可以用SPI模式0,但模拟程序可能需稍做修改 */

/* 对于双向I/O引脚模拟SPI接口,那么必须在此设置SPI_SCS,SPI_SCK,SPI_SDI为输出方向,SPI_SDO为输入方向 */ }

void mDelay0_5uS( void ) /* 至少延时0.5uS,根据单片机主频调整 */ { }

void Spi376OutByte( UINT8 d ) /* SPI输出8个位数据 */ { /* 如果是硬件SPI接口,应该是先将数据写入SPI数据寄存器,然后查询SPI状态寄存器以等待SPI字节传输完成 */ UINT8 i; for ( i = 0; i < 8; i ++ ) { CH376_SPI_SCK = 0; if ( d & 0x80 ) CH376_SPI_SDI = 1; else CH376_SPI_SDI = 0; d <<= 1; /* 数据位是高位在前 */ CH376_SPI_SCK = 1; /* CH376在时钟上升沿采样输入 */ } }

UINT8 Spi376InByte( void ) /* SPI输入8个位数据 */ {

/* 如果是硬件SPI接口,应该是先查询SPI状态寄存器以等待SPI字节传输完成,然后从SPI数据寄存器读出数据 */ UINT8 i, d; d = 0; for ( i = 0; i < 8; i ++ ) { CH376_SPI_SCK = 0; /* CH376在时钟下降沿输出 */ d <<= 1; /* 数据位是高位在前 */ if ( CH376_SPI_SDO ) d ++; CH376_SPI_SCK = 1; } return( d ); }

#define xEndCH376Cmd( ) { CH376_SPI_SCS = 1; } /* SPI片选无效,结束CH376命令,仅用于SPI接口方式 */

void xWriteCH376Cmd( UINT8 mCmd ) /* 向CH376写命令 */ {

CH376_SPI_SCS = 1; /* 防止之前未通过xEndCH376Cmd禁止SPI片选 */ mDelay0_5uS( );

/* 对于双向I/O引脚模拟SPI接口,那么必须确保已经设置SPI_SCS,SPI_SCK,SPI_SDI为输出方向,SPI_SDO为输入方向 */ CH376_SPI_SCS = 0; /* SPI片选有效 */ Spi376OutByte( mCmd ); /* 发出命令码 */

/* 延时1.5uS确保读写周期大于1.5uS,或者用上面一行的状态查询代替 */ mDelay0_5uS( ); mDelay0_5uS( ); mDelay0_5uS( ); }

#ifdef FOR_LOW_SPEED_MCU /* 不需要延时 */

#define xWriteCH376Data( d ) { Spi376OutByte( d ); } /* 向CH376写数据 */ #define xReadCH376Data( ) ( Spi376InByte( ) ) /* 从CH376读数据 */ #else

void xWriteCH376Data( UINT8 mData ) /* 向CH376写数据 */ { Spi376OutByte( mData ); }

UINT8 xReadCH376Data( void ) /* 从CH376读数据 */ { return( Spi376InByte( ) );

}

#endif

/* 查询CH376中断(INT#低电平) */ UINT8 Query376Interrupt( void ) { /* 如果连接了CH376的中断引脚则直接查询中断引脚 */ return( CH376_INT_WIRE ? FALSE : TRUE ); }

UINT8 mInitCH376Host( void ) /* 初始化CH376 */ { UINT8 res;

CH376_PORT_INIT( ); /* 接口硬件初始化 */ xWriteCH376Cmd( CMD11_CHECK_EXIST ); /* 测试单片机与CH376之间的通讯接口 */ xWriteCH376Data( 0x65 ); //0110 0101 res = xReadCH376Data( ); xEndCH376Cmd( ); if ( res != 0x9A ) //1001 1010 return( ERR_USB_UNKNOWN ); /* 通讯接口不正常,可能原因有:接口连接异常,其它设备影响(片选不唯一),串口波特率,一直在复位,晶振不工作 */ }

xWriteCH376Cmd( CMD11_SET_USB_MODE ); /* 设备USB工作模式 */ xWriteCH376Data( 0x06 ); mDelayuS( 20 );

/*--- 设置CH376工作模式之后,读取其结果状态 ---*/ res = xReadCH376Data( ); xEndCH376Cmd( );

if ( res == CMD_RET_SUCCESS ) return( USB_INT_SUCCESS ); else

return( ERR_USB_UNKNOWN ); /* 设置模式错误 */

FILE_SYS.H文件

/* CH376芯片 文件系统层 V1.0 */

/* 提供文件系统常用子程序,提供命令打包 */

/* 不使用的子程序可以注释掉,从而节约单片机的程序ROM空间和数据RAM空间 */

/* 这里的子程序是通过括号中的变量传递参数,如果参数较多,为了节约RAM,也可以参考CH375子程序库改成通过同一全局变量/联合结构CH376_CMD_DATA传递 */

/* name 参数是指短文件名, 可以包括根目录符, 但不含有路径分隔符, 总长度不超过

1+8+1+3+1字节 */

/* PathName 参数是指全路径的短文件名, 包括根目录符、多级子目录及路径分隔符、文件名/目录名 */

/* LongName 参数是指长文件名, 以UNICODE小端顺序编码, 以两个0字节结束, 使用长文件名子程序必须先定义全局缓冲区GlobalBuf, 长度不小于64字节, 可以与其它子程序共用 */

/* 定义 NO_DEFAULT_CH376_INT 用于禁止默认的Wait376Interrupt子程序,禁止后,应用程序必须自行定义一个同名子程序 */

/* 定义 DEF_INT_TIMEOUT 用于设置默认的Wait376Interrupt子程序中的等待中断的超时时间/循环计数值, 0则不检查超时而一直等待 */

/* 定义 EN_DIR_CREATE 用于提供新建多级子目录的子程序,默认是不提供 */

/* 定义 EN_DISK_QUERY 用于提供磁盘容量查询和剩余空间查询的子程序,默认是不提供 */

/* 定义 EN_SECTOR_ACCESS 用于提供以扇区为单位读写文件的子程序,默认是不提供 */ /* 定义 EN_LONG_NAME 用于提供支持长文件名的子程序,默认是不提供 */

#ifndef __CH376_FS_H__ #define __CH376_FS_H__

#include \

#define STRUCT_OFFSET( s, m ) ( (UINT8)( & ((s *)0) -> m ) ) /* 定义获取结构成员相对偏移地址的宏 */

#ifdef EN_LONG_NAME

#ifndef LONG_NAME_BUF_LEN

#define LONG_NAME_BUF_LEN ( LONG_NAME_PER_DIR * 20 ) /* 自行定义的长文件名缓冲区长度,最小值为LONG_NAME_PER_DIR*1 */ #endif #endif

UINT8 CH376ReadBlock( PUINT8 buf ); /* 从当前主机端点的接收缓冲区读取数据块,返回长度 */

UINT8 CH376WriteReqBlock( PUINT8 buf ); /* 向内部指定缓冲区写入请求的数据块,返回长度 */

void CH376WriteHostBlock( PUINT8 buf, UINT8 len ); /* 向USB主机端点的发送缓冲区写入数据块 */

void CH376WriteOfsBlock( PUINT8 buf, UINT8 ofs, UINT8 len ); /* 向内部缓冲区指定偏移地址写入数据块 */

void CH376SetFileName( PUINT8 name ); /* 设置将要操作的文件的文件名 */

UINT32 CH376Read32bitDat( void ); /* 从CH376芯片读取32位的数据并结束命令 */

UINT8 CH376ReadVar8( UINT8 var ); /* 读CH376芯片内部的8位变量 */

void CH376WriteVar8( UINT8 var, UINT8 dat ); /* 写CH376芯片内部的8位变量 */

UINT32 CH376ReadVar32( UINT8 var ); /* 读CH376芯片内部的32位变量 */

void CH376WriteVar32( UINT8 var, UINT32 dat ); /* 写CH376芯片内部的32位变量 */

void CH376EndDirInfo( void ); /* 在调用CH376DirInfoRead获取FAT_DIR_INFO结构之后应该通知CH376结束 */

UINT32 CH376GetFileSize( void ); /* 读取当前文件长度 */

UINT8 CH376GetDiskStatus( void ); /* 获取磁盘和文件系统的工作状态 */

UINT8 CH376GetIntStatus( void ); /* 获取中断状态并取消中断请求 */

#ifndef NO_DEFAULT_CH376_INT

UINT8 Wait376Interrupt( void ); /* 等待CH376中断(INT#低电平),返回中断状态码, 超时则返回ERR_USB_UNKNOWN */ #endif

UINT8 CH376SendCmdWaitInt( UINT8 mCmd ); /* 发出命令码后,等待中断 */

UINT8 CH376SendCmdDatWaitInt( UINT8 mCmd, UINT8 mDat ); /* 发出命令码和一字节数据后,等待中断 */

UINT8 CH376DiskReqSense( void ); /* 检查USB存储器错误 */

UINT8 CH376DiskConnect( void ); /* 检查U盘是否连接,不支持SD卡 */

UINT8 CH376DiskMount( void ); /* 初始化磁盘并测试磁盘是否就绪 */

UINT8 CH376FileOpen( PUINT8 name ); /* 在根目录或者当前目录下打开文件或者目录(文件夹) */

UINT8 CH376FileCreate( PUINT8 name ); /* 在根目录或者当前目录下新建文件,如果文件已经存在那么先删除 */

UINT8 CH376DirCreate( PUINT8 name ); /* 在根目录下新建目录(文件夹)并打开,如果目录已经存在那么直接打开 */

UINT8 CH376SeparatePath( PUINT8 path ); /* 从路径中分离出最后一级文件名或者目录(文件夹)名,返回最后一级文件名或者目录名的字节偏移 */

UINT8 CH376FileOpenDir( PUINT8 PathName, UINT8 StopName ); /* 打开多级目录下的文件或者目录的上级目录,支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */ /* StopName 指向最后一级文件名或者目录名 */

UINT8 CH376FileOpenPath( PUINT8 PathName ); /* 打开多级目录下的文件或者目录(文件夹),支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */

UINT8 CH376FileCreatePath( PUINT8 PathName ); /* 新建多级目录下的文件,支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */

#ifdef EN_DIR_CREATE

UINT8 CH376DirCreatePath( PUINT8 PathName ); /* 新建多级目录下的目录(文件夹)并打开,支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */ #endif

UINT8 CH376FileErase( PUINT8 PathName ); /* 删除文件,如果已经打开则直接删除,否则对于文件会先打开再删除,支持多级目录路径 */ UINT8 */

CH376FileClose( UINT8 UpdateSz ); /* 关闭当前已经打开的文件或者目录(文件夹)

UINT8 CH376DirInfoRead( void ); /* 读取当前文件的目录信息 */

UINT8 CH376DirInfoSave( void ); /* 保存文件的目录信息 */

UINT8 CH376ByteLocate( UINT32 offset ); /* 以字节为单位移动当前文件指针 */

UINT8 CH376ByteRead( PUINT8 buf, UINT16 ReqCount, PUINT16 RealCount ); /* 以字节为单位从当前位置读取数据块 */

UINT8 CH376ByteWrite( PUINT8 buf, UINT16 ReqCount, PUINT16 RealCount ); /* 以字节为单位向当前位置写入数据块 */

#ifdef EN_DISK_QUERY

UINT8 CH376DiskCapacity( PUINT32 DiskCap ); /* 查询磁盘物理容量,扇区数 */

UINT8 CH376DiskQuery( PUINT32 DiskFre ); /* 查询磁盘剩余空间信息,扇区数 */

#endif

UINT8 CH376SecLocate( UINT32 offset ); /* 以扇区为单位移动当前文件指针 */

#ifdef EN_SECTOR_ACCESS

UINT8 CH376DiskReadSec( PUINT8 buf, UINT32 iLbaStart, UINT8 iSectorCount ); /* 从U盘读取多个扇区的数据块到缓冲区,不支持SD卡 */

UINT8 CH376DiskWriteSec( PUINT8 buf, UINT32 iLbaStart, UINT8 iSectorCount ); /* 将缓冲区中的多个扇区的数据块写入U盘,不支持SD卡 */

UINT8 CH376SecRead( PUINT8 buf, UINT8 ReqCount, PUINT8 RealCount ); /* 以扇区为单位从当前位置读取数据块,不支持SD卡 */

UINT8 CH376SecWrite( PUINT8 buf, UINT8 ReqCount, PUINT8 RealCount ); /* 以扇区为单位在当前位置写入数据块,不支持SD卡 */

#endif

#ifdef EN_LONG_NAME

UINT8 CH376LongNameWrite( PUINT8 buf, UINT16 ReqCount ); /* 长文件名专用的字节写子程序 */

UINT8 CH376CheckNameSum( PUINT8 DirName ); /* 计算长文件名的短文件名检验和,输入为无小数点分隔符的固定11字节格式 */

UINT8 CH376LocateInUpDir( PUINT8 PathName ); /* 在上级目录(文件夹)中移动文件指针到当前文件目录信息所在的扇区 */

/* 另外,顺便将当前文件目录信息所在的扇区的前一个扇区的LBA地址写入CH376内部VAR_FAT_DIR_LBA变量(为了方便收集长文件名时向前搜索,否则要多移动一次) */ /* 使用了全局缓冲区GlobalBuf的前12个字节 */

UINT8 CH376GetLongName( PUINT8 PathName, PUINT8 LongName ); /* 由短文件名或者目录(文件夹)名获得相应的长文件名 */

/* 需要输入短文件名的完整路径PathName,需要提供缓冲区接收长文件名LongName(以UNICODE小端编码,以双0结束) */

/* 使用了全局缓冲区GlobalBuf的前34个字节,sizeof(GlobalBuf)>=sizeof(FAT_DIR_INFO)+2 */

UINT8 CH376CreateLongName( PUINT8 PathName, PUINT8 LongName ); /* 新建具有长文件名的文件,关闭文件后返回,LongName输入路径必须在RAM中 */

/* 需要输入短文件名的完整路径PathName(请事先参考FAT规范由长文件名自行产生),需要

输入以UNICODE小端编码的以双0结束的长文件名LongName */

/* 使用了全局缓冲区GlobalBuf的前64个字节,sizeof(GlobalBuf)>=sizeof(FAT_DIR_INFO)*2 */

#endif

#endif

FILE_SYS.C文件

/* CH376芯片 文件系统层 V1.1 */

/* 提供文件系统常用子程序,提供命令打包 */

/* 不使用的子程序可以注释掉,从而节约单片机的程序ROM空间和数据RAM空间 */

/* 这里的子程序是通过括号中的变量传递参数,如果参数较多,为了节约RAM,也可以参考CH375子程序库改成通过同一全局变量/联合结构CH376_CMD_DATA传递 */

/* name 参数是指短文件名, 可以包括根目录符, 但不含有路径分隔符, 总长度不超过1+8+1+3+1字节 */

/* PathName 参数是指全路径的短文件名, 包括根目录符、多级子目录及路径分隔符、文件名/目录名 */

/* LongName 参数是指长文件名, 以UNICODE小端顺序编码, 以两个0字节结束, 使用长文件名子程序必须先定义全局缓冲区GlobalBuf, 长度不小于64字节, 可以与其它子程序共用 */

/* 定义 NO_DEFAULT_CH376_INT 用于禁止默认的Wait376Interrupt子程序,禁止后,应用程序必须自行定义一个同名子程序 */

/* 定义 DEF_INT_TIMEOUT 用于设置默认的Wait376Interrupt子程序中的等待中断的超时时间/循环计数值, 0则不检查超时而一直等待 */

/* 定义 EN_DIR_CREATE 用于提供新建多级子目录的子程序,默认是不提供 */

/* 定义 EN_DISK_QUERY 用于提供磁盘容量查询和剩余空间查询的子程序,默认是不提供 */

/* 定义 EN_SECTOR_ACCESS 用于提供以扇区为单位读写文件的子程序,默认是不提供 */ /* 定义 EN_LONG_NAME 用于提供支持长文件名的子程序,默认是不提供 */

#include \

UINT8 CH376ReadBlock( PUINT8 buf ) /* 从当前主机端点的接收缓冲区读取数据块,返回长度 */ { UINT8 s, l; xWriteCH376Cmd( CMD01_RD_USB_DATA0 ); s = l = xReadCH376Data( ); /* 长度 */ if ( l ) { do

}

{ *buf = xReadCH376Data( ); buf ++; }while ( -- l ); }

xEndCH376Cmd( ); return( s );

UINT8 CH376WriteReqBlock( PUINT8 buf ) /* 向内部指定缓冲区写入请求的数据块,返回长度 */ { UINT8 s, l; xWriteCH376Cmd( CMD01_WR_REQ_DATA ); }

s = l = xReadCH376Data( ); /* 长度 */ if ( l ) { do { xWriteCH376Data( *buf ); buf ++; } while ( -- l ); }

xEndCH376Cmd( ); return( s );

void CH376WriteHostBlock( PUINT8 buf, UINT8 len ) /* 向USB主机端点的发送缓冲区写入数据块 */ { xWriteCH376Cmd( CMD10_WR_HOST_DATA ); xWriteCH376Data( len ); /* 长度 */ if ( len ) { do { xWriteCH376Data( *buf ); buf ++; } while ( -- len ); } xEndCH376Cmd( ); }

void CH376WriteOfsBlock( PUINT8 buf, UINT8 ofs, UINT8 len ) /* 向内部缓冲区指定偏移地址写入数据块 */ { xWriteCH376Cmd( CMD20_WR_OFS_DATA ); xWriteCH376Data( ofs ); /* 偏移地址 */

}

xWriteCH376Data( len ); /* 长度 */ if ( len ) { do { xWriteCH376Data( *buf ); buf ++; } while ( -- len ); }

xEndCH376Cmd( );

void CH376SetFileName( PUINT8 name ) /* 设置将要操作的文件的文件名 */ { UINT8 c; xWriteCH376Cmd( CMD10_SET_FILE_NAME ); c = *name; xWriteCH376Data( c ); while ( c ) { name ++; c = *name; if ( c == DEF_SEPAR_CHAR1 || c == DEF_SEPAR_CHAR2 )

c = 0; /* 强行将文件名截止 */ xWriteCH376Data( c ); } xEndCH376Cmd( ); }

UINT32 CH376Read32bitDat( void ) /* 从CH376芯片读取32位的数据并结束命令 */ { UINT8 c0, c1, c2, c3; c0 = xReadCH376Data( ); c1 = xReadCH376Data( ); c2 = xReadCH376Data( ); c3 = xReadCH376Data( ); xEndCH376Cmd( ); return( c0 | (UINT16)c1 << 8 | (UINT32)c2 << 16 | (UINT32)c3 << 24 ); }

UINT8 CH376ReadVar8( UINT8 var ) /* 读CH376芯片内部的8位变量 */ { UINT8 c0; xWriteCH376Cmd( CMD11_READ_VAR8 ); xWriteCH376Data( var );

}

c0 = xReadCH376Data( ); xEndCH376Cmd( ); return( c0 );

void CH376WriteVar8( UINT8 var, UINT8 dat ) /* 写CH376芯片内部的8位变量 */ { xWriteCH376Cmd( CMD20_WRITE_VAR8 ); xWriteCH376Data( var ); xWriteCH376Data( dat ); xEndCH376Cmd( ); }

UINT32 CH376ReadVar32( UINT8 var ) /* 读CH376芯片内部的32位变量 */ { xWriteCH376Cmd( CMD14_READ_VAR32 ); xWriteCH376Data( var ); }

return( CH376Read32bitDat( ) ); /* 从CH376芯片读取32位的数据并结束命令 */

void CH376WriteVar32( UINT8 var, UINT32 dat ) /* 写CH376芯片内部的32位变量 */ { xWriteCH376Cmd( CMD50_WRITE_VAR32 ); xWriteCH376Data( var ); xWriteCH376Data( (UINT8)dat ); xWriteCH376Data( (UINT8)( (UINT16)dat >> 8 ) ); xWriteCH376Data( (UINT8)( dat >> 16 ) ); xWriteCH376Data( (UINT8)( dat >> 24 ) ); xEndCH376Cmd( ); }

void CH376EndDirInfo( void ) /* 在调用CH376DirInfoRead获取FAT_DIR_INFO结构之后应该通知CH376结束 */ { CH376WriteVar8( 0x0D, 0x00 ); }

UINT32 CH376GetFileSize( void ) /* 读取当前文件长度 */ { return( CH376ReadVar32( VAR_FILE_SIZE ) ); }

UINT8 CH376GetDiskStatus( void ) /* 获取磁盘和文件系统的工作状态 */ {

return( CH376ReadVar8( VAR_DISK_STATUS ) ); }

UINT8 CH376GetIntStatus( void ) /* 获取中断状态并取消中断请求 */ { UINT8 s; xWriteCH376Cmd( CMD01_GET_STATUS ); s = xReadCH376Data( ); xEndCH376Cmd( ); return( s ); }

UINT8 Wait376Interrupt( void ) /* 等待CH376中断(INT#低电平),返回中断状态码, 超时则返回ERR_USB_UNKNOWN */ { UINT32 i; for ( i = 0; i < 5000000; i ++ ) { /* 计数防止超时,默认的超时时间,与单片机主频有关 */ if ( Query376Interrupt( ) ) return( CH376GetIntStatus( ) ); /* 检测到中断 */ /* 在等待CH376中断的过程中,可以做些需要及时处理的其它事情 */ } }

return( ERR_USB_UNKNOWN ); /* 不应该发生的情况 */

UINT8 CH376SendCmdWaitInt( UINT8 mCmd ) /* 发出命令码后,等待中断 */ { xWriteCH376Cmd( mCmd ); xEndCH376Cmd( ); return( Wait376Interrupt( ) ); }

UINT8 CH376SendCmdDatWaitInt( UINT8 mCmd, UINT8 mDat ) /* 发出命令码和一字节数据后,等待中断 */ { xWriteCH376Cmd( mCmd ); xWriteCH376Data( mDat ); xEndCH376Cmd( ); return( Wait376Interrupt( ) ); }

UINT8 CH376DiskReqSense( void ) /* 检查USB存储器错误 */

{ }

UINT8 s; mDelaymS( 5 );

s = CH376SendCmdWaitInt( CMD0H_DISK_R_SENSE ); mDelaymS( 5 ); return( s );

UINT8 { }

CH376DiskConnect( void ) /* 检查U盘是否连接,不支持SD卡 */

if( Query376Interrupt( ) ) /*--- 就是简单的查询中断口的电平状态 ---*/ CH376GetIntStatus( ); /* 检测到中断 */

return( CH376SendCmdWaitInt( CMD0H_DISK_CONNECT ) );

UINT8 CH376DiskMount( void ) /* 初始化磁盘并测试磁盘是否就绪 */ { return( CH376SendCmdWaitInt( CMD0H_DISK_MOUNT ) ); }

UINT8 CH376FileOpen( PUINT8 name ) /* 在根目录或者当前目录下打开文件或者目录(文件夹) */ { }

CH376SetFileName( name ); /* 设置将要操作的文件的文件名 */ if ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 ) CH376WriteVar32( VAR_CURRENT_CLUST, 0 );

return( CH376SendCmdWaitInt( CMD0H_FILE_OPEN ) );

UINT8 CH376FileCreate( PUINT8 name ) /* 在根目录或者当前目录下新建文件,如果文件已经存在那么先删除 */ { if ( name ) CH376SetFileName( name ); /* 设置将要操作的文件的文件名 */ return( CH376SendCmdWaitInt( CMD0H_FILE_CREATE ) ); }

UINT8 CH376DirCreate( PUINT8 name ) /* 在根目录下新建目录(文件夹)并打开,如果目录已经存在那么直接打开 */ { CH376SetFileName( name ); /* 设置将要操作的文件的文件名 */ if ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 ) CH376WriteVar32( VAR_CURRENT_CLUST, 0 ); return( CH376SendCmdWaitInt( CMD0H_DIR_CREATE ) );

}

UINT8 CH376SeparatePath( PUINT8 path ) /* 从路径中分离出最后一级文件名或者目录(文件夹)名,返回最后一级文件名或者目录名的字节偏移 */ { PUINT8 pName; for ( pName = path; *pName != 0; ++ pName ); /* 到文件名字符串结束位置 */ while ( *pName != DEF_SEPAR_CHAR1 && *pName != DEF_SEPAR_CHAR2 && pName != path ) pName --; /* 搜索倒数第一个路径分隔符 */ if ( pName != path ) pName ++; /* 找到了路径分隔符,则修改指向目标文件的最后一级文件名,跳过前面的多级目录名及路径分隔符 */ return( pName - path ); }

/* 打开多级目录下的文件或者目录的上级目录,支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */

UINT8 CH376FileOpenDir( PUINT8 PathName, UINT8 StopName )

/* StopName 指向最后一级文件名或者目录名 */ { UINT8 i, s; s = 0; i = 1; /* 跳过有可能的根目录符 */ while ( 1 ) { while ( PathName[i] != DEF_SEPAR_CHAR1 && PathName[i] != DEF_SEPAR_CHAR2 && PathName[i] != 0 ) ++ i; /* 搜索下一个路径分隔符或者路径结束符 */ if ( PathName[i] ) i ++; /* 找到了路径分隔符,修改指向目标文件的最后一级文件名 */ else i = 0; /* 路径结束 */ s = CH376FileOpen( &PathName[s] ); /* 打开文件或者目录 */ if ( i && i != StopName ) { /* 路径尚未结束 */ if ( s != ERR_OPEN_DIR ) { /* 因为是逐级打开,尚未到路径结束,所以,如果不是成功打开了目录,那么说明有问题 */ if ( s == USB_INT_SUCCESS ) return( ERR_FOUND_NAME ); /* 中间路径必须是目录名,如果是文件名则出错 */

else if ( s == ERR_MISS_FILE ) return( ERR_MISS_DIR ); /* 中间路径的某个子目录没有找到,可能是目录名称错误 */ else

return( s ); /* 操作出错 */ } s = i; /* 从下一级目录开始继续 */ } else

return( s ); /* 路径结束,USB_INT_SUCCESS为成功打开文件,ERR_OPEN_DIR为成功打开目录(文件夹),其它为操作出错 */ } }

UINT8 CH376FileOpenPath( PUINT8 PathName ) /* 打开多级目录下的文件或者目录(文件夹),支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */ { return( CH376FileOpenDir( PathName, 0xFF ) ); }

UINT8 CH376FileCreatePath( PUINT8 PathName ) /* 新建多级目录下的文件,支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */ { UINT8 s; UINT8 Name; Name = CH376SeparatePath( PathName ); /* 从路径中分离出最后一级文件名,返回最后一级文件名的偏移 */ if ( Name ) { /* 是多级目录 */ s = CH376FileOpenDir( PathName, Name ); /* 打开多级目录下的最后一级目录,即打开新建文件的上级目录 */ if ( s != ERR_OPEN_DIR ) { /* 因为是打开上级目录,所以,如果不是成功打开了目录,那么说明有问题 */ if ( s == USB_INT_SUCCESS ) return( ERR_FOUND_NAME ); /* 中间路径必须是目录名,如果是文件名则出错 */ else if ( s == ERR_MISS_FILE ) return( ERR_MISS_DIR ); /* 中间路径的某个子目录没有找到,可能是目录名称错误 */ else return( s ); /* 操作出错 */ } } return( CH376FileCreate( &PathName[Name] ) ); /* 在根目录或者当前目录下新建文件 */ }

#ifdef EN_DIR_CREATE

UINT8 CH376DirCreatePath( PUINT8 PathName ) /* 新建多级目录下的目录(文件夹)并打开,支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */ { UINT8 s; UINT8 Name; UINT8 ClustBuf[4]; Name = CH376SeparatePath( PathName ); /* 从路径中分离出最后一级目录名,返回最后一级文件名的偏移 */ if ( Name ) { /* 是多级目录 */ s = CH376FileOpenDir( PathName, Name ); /* 打开多级目录下的最后一级目录,即打开新建目录的上级目录 */ if ( s != ERR_OPEN_DIR ) { /* 因为是打开上级目录,所以,如果不是成功打开了目录,那么说明有问题 */ if ( s == USB_INT_SUCCESS ) return( ERR_FOUND_NAME ); /* 中间路径必须是目录名,如果是文件名则出错 */ else if ( s == ERR_MISS_FILE ) return( ERR_MISS_DIR ); /* 中间路径的某个子目录没有找到,可能是目录名称错误 */ else return( s ); /* 操作出错 */ } xWriteCH376Cmd( CMD14_READ_VAR32 ); xWriteCH376Data( VAR_START_CLUSTER ); /* 上级目录的起始簇号 */ for ( s = 0; s != 4; s ++ ) ClustBuf[ s ] = xReadCH376Data( ); xEndCH376Cmd( );

s = CH376DirCreate( &PathName[Name] ); /* 在当前目录下新建目录 */ if ( s != USB_INT_SUCCESS ) return( s );

s = CH376ByteLocate( sizeof(FAT_DIR_INFO) + STRUCT_OFFSET( FAT_DIR_INFO,

DIR_FstClusHI ) ); /* 移动文件指针 */ if ( s != USB_INT_SUCCESS ) return( s ); s = CH376ByteWrite( &ClustBuf[2], 2, NULL ); /* 写入上级目录的起始簇号的高16位 */ if ( s != USB_INT_SUCCESS ) return( s ); s = CH376ByteLocate( sizeof(FAT_DIR_INFO) + STRUCT_OFFSET( FAT_DIR_INFO, DIR_FstClusLO ) ); /* 移动文件指针 */ if ( s != USB_INT_SUCCESS ) return( s ); s = CH376ByteWrite( ClustBuf, 2, NULL ); /* 写入上级目录的起始簇号的低16位 */ if ( s != USB_INT_SUCCESS ) return( s ); s = CH376ByteLocate( 0 ); /* 移动文件指针,恢复到目录头位置 */ if ( s != USB_INT_SUCCESS ) return( s ); } else { /* 不是多级目录 */ if ( PathName[0] == DEF_SEPAR_CHAR1 || PathName[0] == DEF_SEPAR_CHAR2 ) return( CH376DirCreate( PathName ) ); /* 在根目录下新建目录 */ else return( ERR_MISS_DIR ); /* 必须提供完整路径才能实现在当前目录下新建目

录 */ } }

#endif

UINT8 CH376FileErase( PUINT8 PathName ) /* 删除文件,如果已经打开则直接删除,否则对于文件会先打开再删除,支持多级目录路径 */ { UINT8 s; if ( PathName ) { /* 文件尚未打开 */ for ( s = 1; PathName[s] != DEF_SEPAR_CHAR1 && PathName[s] != DEF_SEPAR_CHAR2 && PathName[s] != 0; ++ s ); /* 搜索下一个路径分隔符或者路径结束符 */ if ( PathName[s] ) { /* 有路径分隔符,是多级目录下的文件或者目录 */ s = CH376FileOpenPath( PathName ); /* 打开多级目录下的文件或者目录 */ if ( s != USB_INT_SUCCESS && s != ERR_OPEN_DIR ) return( s ); /* 操作出错 */ } else CH376SetFileName( PathName ); /* 没有路径分隔符,是根目录或者当前目录下的文件或者目录,设置将要操作的文件的文件名 */ } return( CH376SendCmdWaitInt( CMD0H_FILE_ERASE ) ); }

UINT8 CH376FileClose( UINT8 UpdateSz ) /* 关闭当前已经打开的文件或者目录(文件夹) */ { return( CH376SendCmdDatWaitInt( CMD1H_FILE_CLOSE, UpdateSz ) ); }

UINT8 CH376DirInfoRead( void ) /* 读取当前文件的目录信息 */ { return( CH376SendCmdDatWaitInt( CMD1H_DIR_INFO_READ, 0xFF ) ); }

UINT8 CH376DirInfoSave( void ) /* 保存文件的目录信息 */ { return( CH376SendCmdWaitInt( CMD0H_DIR_INFO_SAVE ) ); }

UINT8 CH376ByteLocate( UINT32 offset ) /* 以字节为单位移动当前文件指针 */ { xWriteCH376Cmd( CMD4H_BYTE_LOCATE ); xWriteCH376Data( (UINT8)offset ); xWriteCH376Data( (UINT8)((UINT16)offset>>8) ); xWriteCH376Data( (UINT8)(offset>>16) );

}

xWriteCH376Data( (UINT8)(offset>>24) ); xEndCH376Cmd( );

return( Wait376Interrupt( ) );

UINT8 CH376ByteRead( PUINT8 buf, UINT16 ReqCount, PUINT16 RealCount ) /* 以字节为单位从当前位置读取数据块 */ { UINT8 s; xWriteCH376Cmd( CMD2H_BYTE_READ ); xWriteCH376Data( (UINT8)ReqCount ); xWriteCH376Data( (UINT8)(ReqCount>>8) ); xEndCH376Cmd( ); if ( RealCount ) *RealCount = 0; while ( 1 ) { s = Wait376Interrupt( ); if ( s == USB_INT_DISK_READ ) { 长度 */

}

s = CH376ReadBlock( buf ); /* 从当前主机端点的接收缓冲区读取数据块,返回xWriteCH376Cmd( CMD0H_BYTE_RD_GO ); xEndCH376Cmd( ); buf += s;

if ( RealCount ) *RealCount += s;

/* else if ( s == USB_INT_SUCCESS ) return( s );*/ /* 结束 */ else return( s ); /* 错误 */ } }

UINT8 CH376ByteWrite( PUINT8 buf, UINT16 ReqCount, PUINT16 RealCount ) /* 以字节为单位向当前位置写入数据块 */ { UINT8 s; xWriteCH376Cmd( CMD2H_BYTE_WRITE ); xWriteCH376Data( (UINT8)ReqCount ); xWriteCH376Data( (UINT8)(ReqCount>>8) ); xEndCH376Cmd( ); if ( RealCount ) *RealCount = 0; while ( 1 ) { s = Wait376Interrupt( ); if ( s == USB_INT_DISK_WRITE ) { s = CH376WriteReqBlock( buf ); /* 向内部指定缓冲区写入请求的数据块,返回