📄 ch375hf1.c
字号:
/* 串口标准版,只支持三线制串口和4+1线串口,支持看门狗,只能使用CH专用单片机 */
/* 2004.07.05, 2004.8.25, 2004.9.1, 2004.9.15, 2004.09.23, 2004.10.13, 2004.10.23, 2004.11.20, 2004.12.12, 2004.12.28,
2005.01.04, 2005.01.12, 2005.01.26, 2005.03.01, 2005.03.09, 2005.05.31, 2005.07.29, 2005.12.28
****************************************
** Copyright (C) W.ch 1999-2005 **
** Web: http://www.winchiphead.com **
****************************************
** USB Host File Module @CH375 **
** TC2.0@PC, KC7.0@MCS51 **
****************************************
*/
/* CH375 主机文件系统接口 */
/* 支持: FAT12/FAT16/FAT32 */
/* CH375的INT#引脚采用查询方式处理, 磁盘数据复制方式为"双DPTR复制", 文件数据复制方式为"外部子程序" */
/* 适用于具有双DPTR及DPS的ATMEL/PHILIPS/SST等单片机 */
/* MCS-51单片机C语言的U盘文件读写模块程序, 适用于89C52或者更大程序空间的单片机 */
/* C51 CH375HF1.C */
/* LX51 CH375HF1.OBJ , CH375HF6.LIB 如果将CH375HF6换成CH375HF4那么效率高些但是不支持FAT32 */
/* OHX51 CH375HF1 */
//#pragma CODE
#pragma code symbols optimize(5)
#include <reg52.h>
#include <intrins.h>
#include <absacc.h>
#define FILE_MODULE_VER 0x29 /* 当前模块的版本号 */
#define MAX_PATH_LEN 65 /* 最大路径长度,含所有斜杠分隔符和小数点间隔符以及路径结束符00H */
#define MAX_BYTE_IO 64 /* 以字节为单位单次读写文件时的最大长度,超过该长度可以分多次读写 */
#define CMD_QueryStatus 0x60 /* 查询当前模块的状态 */
#define CMD_DiskQuery 0x61 /* 查询磁盘信息 */
#define CMD_FileEnumer 0x63 /* 枚举文件,返回文件名 */
#define CMD_FileOpen 0x64 /* 打开文件 */
#define CMD_FileCreate 0x65 /* 新建文件并打开,如果文件已经存在则先删除后再新建 */
#define CMD_FileErase 0x66 /* 删除文件并关闭 */
#define CMD_FileClose 0x67 /* 关闭当前文件 */
#define CMD_FileQuery 0x68 /* 查询当前文件的信息 */
#define CMD_FileModify 0x69 /* 查询或者修改当前文件的信息 */
#define CMD_FileLocate 0x6A /* 移动当前文件指针 */
#define CMD_FileRead 0x6B /* 从当前文件读取数据 */
#define CMD_FileWrite 0x6C /* 向当前文件写入数据 */
#define CMD_BulkOnlyCmd 0x70 /* 执行基于BulkOnly协议的命令 */
#define CMD_DiskReady 0x71 /* 查询磁盘是否准备好 */
#define CMD_DiskSize 0x72 /* 查询磁盘容量 */
#define CMD_FileDirInfo 0x75 /* 存取当前已打开文件的目录信息 */
#define CMD_DirCreate 0x76 /* 新建目录并打开,如果目录已经存在则直接打开 */
#define CMD_FileReadLast 0x77 /* 从当前文件的尾部读取不足一个扇区长度的零碎数据 */
#define CMD_SetFileSize 0x78 /* 修改系统子程序库的文件长度变量 */
#define CMD_ByteLocate 0x7A /* 以字节为单位移动当前文件指针 */
#define CMD_ByteRead 0x7B /* 以字节为单位从当前文件读取数据块 */
#define CMD_ByteWrite 0x7C /* 以字节为单位向当前文件写入数据块 */
#define CMD_StreamRead 0x7E /* 数据流模式读文件,只支持串口,只支持文本 */
#define CMD_StreamWrite 0x7F /* 数据流模式写文件,只支持串口,只支持文本 */
#define CMD_GetVer 0x0A /* 获取当前模块的版本号 */
#define CMD_PowerDown 0x0D /* 进入低功耗省电状态 */
#define CMD_ResetInit 0x0B /* 复位并重新初始化CH375以及模块 */
#define CMD_BaudRate 0xA5 /* 设置串口通讯波特率 */
#define CMD_SetupModule 0xA6 /* 设置模块配置 */
#define CMD_DirectWrCmd 0xB9 /* 直接传递给CH375,写命令 */
#define CMD_DirectRdDat 0xB5 /* 直接传递给CH375,读数据 */
#define CMD_DirectWrDat 0xB6 /* 直接传递给CH375,写数据 */
#define CMD_DebugAccess 0xAB /* 调试模式存取 */
#define CMD_GetStringSN 0xA0 /* 获取产品序列号字符串 */
#define CMD_SetUsbId 0x12 /* USB设备模式: 设置USB设备的厂商VID和产品PID */
#define CMD_SetUsbMode 0x15 /* USB设备模式: 设置USB主机/设备工作模式,只支持串口 */
#define CMD_ReadUsbData 0x28 /* USB设备模式: 从模块的数据下传端点读取数据块 */
#define CMD_WriteUsbData 0x2B /* USB设备模式: 向模块的数据上传端点写入数据块 */
#define CMD_SerialPortTest 0x01 /* 用于出厂时模块串口通讯测试 */
/* 以下定义的详细说明请看CH375HF4.H文件 */
#define LIB_CFG_DISK_IO 2 /* 磁盘读写的数据的复制方式,1为"单DPTR复制",2为"双DPTR复制",3为"单DPTR和P2+R0复制" */
#define LIB_CFG_FILE_IO 0 /* 文件读写的数据的复制方式,0为"外部子程序",1为"单DPTR复制",2为"双DPTR复制",3为"单DPTR和P2+R0复制" */
#define LIB_CFG_INT_EN 0 /* CH375的INT#引脚连接方式,0为"查询方式",1为"中断方式" */
/*#define LIB_CFG_FILE_IO_DEFAULT 1*/ /* 使用CH375HF4.H提供的默认"外部子程序" */
/*#define LIB_CFG_UPD_SIZE 1*/ /* 在添加数据后是否自动更新文件长度: 0为"不更新",1为"自动更新" */
#define CH375_CMD_PORT_ADDR 0xBDF1 /* CH375命令端口的I/O地址 */
#define CH375_DAT_PORT_ADDR 0xBCF0 /* CH375数据端口的I/O地址 */
#define DISK_BASE_BUF_ADDR 0x0000 /* 外部RAM的磁盘数据缓冲区的首字节,从该单元开始的缓冲区长度为SECTOR_SIZE */
#define CH375_INT_WIRE INT0 /* P3.2, INT0, CH375的中断线INT#引脚,连接CH375的INT#引脚,用于查询中断状态 */
#define WATCHDOG_TIMEOUT 0x0E /* 14,在18.432MHz时钟下是4.5秒看门狗周期 */
#ifdef WATCHDOG_TIMEOUT
sfr WDTD = 0x85;
sfr WDTC = 0xC0;
sbit WDT = 0xC1;
#endif
#define EN_CH375LIB_MORE 1
#define NO_DEFAULT_CH375_INT 1
#include "CH375HF1.H"
void xQueryInterrupt( void ) /* 查询CH375中断并更新中断状态 */
{
UINT16 i;
for ( i = 0xFFFF; CH375_INT_WIRE != 0; i -- ) { /* 如果CH375的中断引脚输出高电平则等待 */
if ( CH375_INT_WIRE == 0 ) break;
if ( CH375_INT_WIRE == 0 ) break;
#ifdef WATCHDOG_TIMEOUT
WDT = 1; /* 清除看门狗计时 */
#endif
if ( CH375_INT_WIRE == 0 ) break;
if ( ( i >> 8 ) == 0 ) {
if ( i == 0 ) {
CH375DiskStatus = DISK_UNKNOWN;
CH375_CMD_PORT = CMD_RESET_ALL;
}
else if ( ( i & 0xFF ) == 0xFF ) CH375_CMD_PORT = CMD_ABORT_NAK;
}
}
CH375_CMD_PORT = CMD_GET_STATUS; /* 获取当前中断状态 */
_nop_( ); _nop_( ); _nop_( ); _nop_( ); _nop_( ); /* 至少延时2uS */
CH375IntStatus = CH375_DAT_PORT; /* 获取中断状态 */
if ( CH375IntStatus == USB_INT_DISCONNECT ) CH375DiskStatus = DISK_DISCONNECT; /* 检测到USB设备断开事件 */
else if ( CH375IntStatus == USB_INT_CONNECT ) CH375DiskStatus = DISK_CONNECT; /* 检测到USB设备连接事件 */
}
typedef unsigned char pdata *PUINT8P;
sfr AUXR = 0x8E; /* 辅助寄存器 */
sfr AUXR1 = 0xA2; /* 辅助寄存器1 */
#define ERR_UNKNOWN_CMD 0xFF /* 不支持的命令 */
#define USB_INT_DISK_RETRY 0xEE /* USB存储器读写数据块失败重试,只用于CMD_FileRead命令和CMD_FileRead命令,操作失败重试 */
sbit PIN_AUTO_DEMO = P2^4; /* P2.4 低电平为自动演示 */
#define BUSY_OUT T0 /* T0 忙状态输出:0空闲,1正忙,低电平驱动LED显示 */
#define INT_OUT T1 /* T1 中断请求输出引脚,低电平有效 */
#define PIN_SER_MODE T1 /* T1 低电平设置接口方式为3线制串口方式 */
#define EXT_INT_PIN INT1 /* INT1 中断请求输入引脚,下降沿有效 */
#define EXT_INT_FLAG IE1 /* INT1 中断标志 */
#define EXT_INT_ENABLE EX1 /* INT1 中断使能 */
#define DEFAULT_BAUDRATE 0x78 /* 120,在18.432MHz时钟下是4800bps */
#define DISABLE_RESET 0xF8 /* 禁止硬复位CH375芯片的P1端口值 */
UINT8 bdata mWorkMode; /* 模块的工作模式 */
sbit mModeBigEndian = mWorkMode^7; /* 数据字节顺序: 0-小端LITTLE_ENDIAN,1-大端BIG_ENDIAN */
sbit mModeAutoNotice = mWorkMode^5; /* 空闲时查询U盘连接状态并自动中断通知:0禁止,1允许 */
sbit mModeUpdateSize = mWorkMode^4; /* 向文件写入数据后自动更新文件长度:0禁止,1允许 */
sbit mModeTimeout = mWorkMode^2; /* 串口超时使能: 0-禁止超时检查, 1-允许超时检查 */
sbit mModeSerial = mWorkMode^1; /* 接口方式: 0-并口, 1-串口 */
sbit mModePortSpec = mWorkMode^0; /* 并口/专用接口方式选择: 0-8位并口,1-专用接口 */
sbit mModeSerialSync = mWorkMode^0; /* 串口同步方式/启动操作的方式: 0-由外部中断启动操作/4+1线串口,1-由串口同步码启动操作/3线制串口 */
BOOL1 mCmdAction; /* 命令激活位:0无效,1有效 */
BOOL1 mSetBaudRate; /* 设置串口的通讯波特率:0否,1是 */
BOOL1 mUsbModeDevice; /* USB工作模式:0主机模式,1设备模式 */
UINT8 mCmdCode; /* 命令码 */
/*UINT8 mCmdLength;*/ /* 命令包的参数长度 */
#define mLastState TH1 /* 保存上次操作的状态码 */
UINT8I mBuffer[ 64 ]; /* 串口数据收发缓冲区 */
sbit ACC_B7 = ACC^7;
sbit ACC_B6 = ACC^6;
sbit ACC_B5 = ACC^5;
sbit ACC_B4 = ACC^4;
sbit ACC_B3 = ACC^3;
sbit ACC_B2 = ACC^2;
sbit ACC_B1 = ACC^1;
sbit ACC_B0 = ACC^0;
UINT8 R6X _at_ 0X06;
UINT8 R7X _at_ 0X07;
#define SER_SYNC_CODE1 0x57 /* 启动操作的第1个串口同步码 */
#define SER_SYNC_CODE2 0xAB /* 启动操作的第2个串口同步码 */
#define SER_STREAM_END 0x1A /* 数据流模式文件读写:结束 */
#define SER_STREAM_ERROR 0x15 /* 数据流模式文件读写:错误 */
#define SER_STREAM_ACK 0x06 /* 数据流模式文件读写:应答 */
#define SER_STREAM_FLUSH 0x00 /* 数据流模式文件读写:刷新 */
#define AUTO_DEMO_FILE "/模块演示.TXT" /* 模块自动演示的文件名 */
#define STREAM_DEFAULT_FILE "/模块数据.TXT" /* 模块数据流模式的默认文件名 */
UINT32 code xPresetSig _at_ 0x3F00;
UINT8 code xWorkMode _at_ 0x3F08;
UINT8 code xBaudRate _at_ 0x3F09;
UINT8 code xStringSN[0x10] _at_ 0x3F10;
UINT32 code zPresetSig _at_ 0x7000;
UINT8 code zWorkMode _at_ 0x7008;
UINT8 code zBaudRate _at_ 0x7009;
void SerialInterrupt( ) interrupt 4 using 1
{
UINT8 len;
PUINT8I buf;
if ( RI ) { /* 接收到串口数据 */
RI = 0;
if ( SBUF == SER_SYNC_CODE1 ) { /* 接收到启动操作的第1个串口同步码 */
SerSyncCode1:
TH0 = 0;
TF0 = 0; /* 清定时器0溢出标志 */
TR0 = 1; /* 打开定时器0检查超时 */
#ifdef WATCHDOG_TIMEOUT
while ( RI == 0 && TF0 == 0 ) WDT = 1; /* 清除看门狗计时 */
#else
while ( RI == 0 && TF0 == 0 );
#endif
if ( RI ) { /* 接收到串口数据 */
RI = 0;
if ( SBUF == SER_SYNC_CODE2 ) { /* 接收到启动操作的第2个串口同步码,启动操作 */
INT_OUT = 1; /* 取消中断请求输出 */
TH0 = 0;
TF0 = 0; /* 清定时器0溢出标志 */
TR0 = mModeTimeout; /* 打开定时器0检查超时 */
while ( RI == 0 && TF0 == 0 );
mCmdCode = SBUF; /* 首字节是命令码 */
RI = 0;
if ( TF0 == 0 ) { /* 尚未超时 */
TH0 = 0;
while ( RI == 0 && TF0 == 0 );
len = SBUF; /* 次字节是命令包的参数长度 */
RI = 0;
if ( TF0 == 0 && len <= sizeof( mCmdParam ) ) { /* 尚未超时并且命令参数的长度有效 */
/* mCmdLength = len;*/
if ( len ) { /* 有命令参数 */
buf = (PUINT8I)( &mCmdParam );
do {
TH0 = 0;
#ifdef WATCHDOG_TIMEOUT
while ( RI == 0 && TF0 == 0 ) WDT = 1; /* 清除看门狗计时 */
#else
while ( RI == 0 && TF0 == 0 );
#endif
*buf = SBUF; /* 保存命令参数到命令参数结构中 */
RI = 0;
buf ++;
if ( TF0 ) break;
} while ( -- len );
}
if ( TF0 == 0 ) mCmdAction = 1; /* 命令包有效 */
}
}
}
else if ( SBUF == SER_SYNC_CODE1 ) goto SerSyncCode1; /* 接收到启动操作的第1个串口同步码 */
}
TR0 = 0; /* 关闭定时器0 */
}
}
else TI = 0;
}
/* 外接接口中断服务程序,使用寄存器组1 */
void ExternalInterrupt( ) interrupt 2 using 1
{
UINT8 len;
PUINT8I buf;
INT_OUT = 1; /* 取消中断请求输出 */
RI = 0;
TH0 = 0;
TF0 = 0; /* 清定时器0溢出标志 */
TR0 = mModeTimeout; /* 打开定时器0检查超时 */
while ( RI == 0 && TF0 == 0 );
mCmdCode = SBUF; /* 首字节是命令码 */
RI = 0;
if ( TF0 == 0 ) { /* 尚未超时 */
TH0 = 0;
while ( RI == 0 && TF0 == 0 );
len = SBUF; /* 次字节是命令包的参数长度 */
RI = 0;
if ( TF0 == 0 && len <= sizeof( mCmdParam ) ) { /* 尚未超时并且命令参数的长度有效 */
/* mCmdLength = len;*/
if ( len ) { /* 有命令参数 */
buf = (PUINT8I)( &mCmdParam );
do {
TH0 = 0;
#ifdef WATCHDOG_TIMEOUT
while ( RI == 0 && TF0 == 0 ) WDT = 1; /* 清除看门狗计时 */
#else
while ( RI == 0 && TF0 == 0 );
#endif
*buf = SBUF; /* 保存命令参数到命令参数结构中 */
RI = 0;
buf ++;
if ( TF0 ) break;
} while ( -- len );
}
if ( TF0 == 0 ) mCmdAction = 1; /* 命令包有效 */
}
}
TR0 = 0; /* 关闭定时器0 */
EXT_INT_FLAG = 0; /* 清中断标志 */
}
/* 该子程序由CH375的子程序库调用,用于从CH375读取文件数据到外部缓冲区,被CH375FileReadX调用 */
void xWriteToExtBuf( UINT8 mLength )
{
UINT8 count;
UINT16 back;
INT_OUT = 0; /* 输出中断请求 */
TI = 0;
if ( mLength == 0 ) { /* 重试 */
SBUF = USB_INT_DISK_RETRY; /* 操作状态码: 重试 */
while ( TI == 0 ); /* 等待状态码发送完成 */
INT_OUT = 1;
back = 0 - (UINT16)mCmdParam.ReadX.mDataBuffer;
mCmdParam.ReadX.mDataBuffer = 0;
TI = 0;
SBUF = mModeBigEndian ? (UINT8)( back >> 8 ) : (UINT8)back;
while ( TI == 0 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -