⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch375hf1.c

📁 u盘读写模块.C51单片机与USB接口芯片对U盘进行文件读写,支持FAT8,FAT16和FAT32磁盘格式.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 串口标准版,只支持三线制串口和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 + -