📄 ch374hft.c
字号:
/* 2004.06.05
****************************************
** Copyright (C) W.ch 1999-2004 **
** Web: http://www.winchiphead.com **
****************************************
** USB Host File Interface for CH374 **
** TC2.0@PC, KC7.0@MCS51 **
****************************************
*/
/* CH374 主机文件系统接口 */
/* 支持: FAT12/FAT16/FAT32 */
/* MCS-51单片机C语言的U盘文件读写示例程序, 适用于89C52或者更大程序空间的单片机 */
/* 本程序用于演示列出指定目录下的所有文件,以及用于搜索/枚举文件名 */
/* CH374的INT#引脚采用查询方式处理, 数据复制方式为"单DPTR复制", 所以速度较慢, 适用于所有MCS51单片机 */
/* C51 CH374HFT.C */
/* LX51 CH374HFT.OBJ , CH374HF6.LIB, C51DPTR1.LIB */
/* OHX51 CH374HFT */
#include <reg52.h>
#include <stdio.h>
#include <string.h>
/* 以下定义的详细说明请看CH374HF6.H文件 */
#define LIB_CFG_INT_EN 0 /* CH374的INT#引脚连接方式,0为"查询方式",1为"中断方式" */
#define CH374_IDX_PORT_ADDR 0xBDF1 /* CH374索引端口的I/O地址 */
#define CH374_DAT_PORT_ADDR 0xBCF0 /* CH374数据端口的I/O地址 */
/* 62256提供的32KB的RAM分为两部分: 0000H-01FFH为磁盘读写缓冲区, 0200H-7FFFH为文件数据缓冲区 */
#define DISK_BASE_BUF_ADDR 0x0000 /* 外部RAM的磁盘数据缓冲区的起始地址,从该单元开始的缓冲区长度为SECTOR_SIZE */
#define CH374_INT_WIRE INT0 /* P3.2, INT0, CH374的中断线INT#引脚,连接CH374的INT#引脚,用于查询中断状态 */
/* 如果未连接CH374的中断引脚,那么应该去掉上述定义,自动使用寄存器查询方式 */
#define DISK_BASE_BUF_LEN 2048 /* 默认的磁盘数据缓冲区大小为512字节,建议选择为2048甚至4096以支持某些大扇区的U盘,为0则禁止在.H文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */
/* 如果需要复用磁盘数据缓冲区以节约RAM,那么可将DISK_BASE_BUF_LEN定义为0以禁止在.H文件中定义缓冲区,而由应用程序在调用CH375Init之前将与其它程序合用的缓冲区起始地址置入pDISK_BASE_BUF变量 */
#define NO_DEFAULT_CH374_F_ENUM 1 /* 未调用CH374FileEnumer程序故禁止以节约代码 */
#define NO_DEFAULT_CH374_F_QUERY 1 /* 未调用CH374FileQuery程序故禁止以节约代码 */
#define NO_DEFAULT_CH374_RESET 1 /* 未调用CH374Reset程序故禁止以节约代码 */
#define NO_DEFAULT_FILE_ENUMER 1 /* 禁止默认的文件名枚举回调程序,下面用自行编写的程序代替它 */
#include "..\CH374HF6.H" /* 如果不需要支持FAT32,那么请选用CH374HF6.H */
/* 在P1.4连接一个LED用于监控演示程序的进度,低电平LED亮,当U盘插入后亮 */
sbit P1_4 = P1^4;
#define LED_OUT_INIT( ) { P1_4 = 1; } /* P1.4 高电平 */
#define LED_OUT_ACT( ) { P1_4 = 0; } /* P1.4 低电平驱动LED显示 */
#define LED_OUT_INACT( ) { P1_4 = 1; } /* P1.4 低电平驱动LED显示 */
sbit P1_5 = P1^5;
/* 在P1.5连接一个LED用于监控演示程序的进度,低电平LED亮,当对U盘操作时亮 */
#define LED_RUN_ACT( ) { P1_5 = 0; } /* P1.5 低电平驱动LED显示 */
#define LED_RUN_INACT( ) { P1_5 = 1; } /* P1.5 低电平驱动LED显示 */
sbit P1_6 = P1^6;
/* 在P1.6连接一个LED用于监控演示程序的进度,低电平LED亮,当对U盘写操作时亮 */
#define LED_WR_ACT( ) { P1_6 = 0; } /* P1.6 低电平驱动LED显示 */
#define LED_WR_INACT( ) { P1_6 = 1; } /* P1.6 低电平驱动LED显示 */
/* 检查操作状态,如果错误则显示错误代码并停机,应该替换为实际的处理措施 */
void mStopIfError( UINT8 iError )
{
if ( iError == ERR_SUCCESS ) return; /* 操作成功 */
printf( "Error: %02X\n", (UINT16)iError ); /* 显示错误 */
/* 遇到错误后,应该分析错误码以及CH374DiskStatus状态,例如调用CH374DiskConnect查询当前U盘是否连接,如果U盘已断开那么就重新等待U盘插上再操作,
建议出错后的处理步骤:
1、调用一次CH374DiskReady,成功则继续操作,例如Open,Read/Write等,在CH374DiskReady中会自动调用CH374DiskConnect,不必另外调用
2、如果CH374DiskReady不成功,那么强行将CH374DiskStatus置为DISK_CONNECT状态,然后从头开始操作(等待U盘连接CH374DiskConnect,CH374DiskReady等) */
while ( 1 ) {
LED_OUT_ACT( ); /* LED闪烁 */
CH374DelaymS( 200 );
LED_OUT_INACT( );
CH374DelaymS( 200 );
}
}
/* 为printf和getkey输入输出初始化串口 */
void mInitSTDIO( )
{
SCON = 0x50;
PCON = 0x80;
TMOD = 0x21;
TH1 = 0xf3; /* 24MHz晶振, 9600bps */
TR1 = 1;
TI = 1;
}
typedef struct _FILE_NAME {
UINT32 DirStartClust; /* 文件所在目录的起始簇号 */
// UINT32 Size; /* 文件长度 */
UINT8 Name[8+3+1+1]; /* 文件名,共8+3字节,分隔符,结束符,因为未包含目录名所以是相对路径 */
UINT8 Attr; /* 文件属性 */
} FILE_NAME;
#define MAX_FILE_COUNT 200
FILE_NAME xdata FileNameBuffer[ MAX_FILE_COUNT ]; /* 文件名结构 */
UINT16 FileCount;
UINT32 CurrentDirStartClust; /* 保存当前目录的起始簇号,用于加快文件枚举和打开速度 */
/* 例子:列举指定目录下的所有文件 */
UINT8 ListFile( void )
// 输入参数mCmdParam.Open.mPathName[]为目录名字符串,形式与文件名相同,单个斜线则代表根目录
{
UINT8 i;
printf( "List Directory: %s\n", mCmdParam.Open.mPathName ); /* 显示目录名 */
// for ( i = 0; i < MAX_PATH_LEN; i ++ ) { /* 找目录名的结束符 */
// if ( mCmdParam.Open.mPathName[i] == 0 ) break;
// }
i = strlen( mCmdParam.Open.mPathName ); /* 计算路径的长度,找目录名的结束符 */
if ( i && mCmdParam.Open.mPathName[i-1] == '/' ) { } /* 是根目录,或者是已经有路径分隔符 */
else mCmdParam.Open.mPathName[i++] = '/'; /* 在当前目录下进行枚举,除根目录外都是相对路径,不是根目录则加路径分隔符 */
mCmdParam.Open.mPathName[i++] = '*'; /* 枚举通配符,完整的路径例如"\*"或者"\C51\*"或者"\C51\CH374*"等 */
mCmdParam.Open.mPathName[i] = 0xFF; /* 0xFF指定枚举序号在CH374vFileSize中 */
CH374vFileSize = 0xFFFFFFFF; /* 快速连续枚举,每找到一个文件调用一次xFileNameEnumer回调子程序,如果值小于0x80000000则每次只枚举一个文件太慢 */
i = CH374FileOpen( ); /* 枚举,由回调程序xFileNameEnumer产生记录保存到结构中 */
if ( i == ERR_SUCCESS || i == ERR_FOUND_NAME || i == ERR_MISS_FILE ) { /* 操作成功,通常不会返回ERR_SUCCESS,仅在xFileNameEnumer提前退出时才会返回ERR_FOUND_NAME */
printf( "Success, new FileCount = %d\n", FileCount );
return( ERR_SUCCESS );
}
else {
printf( "Failed, new FileCount = %d\n", FileCount );
return( i );
}
}
UINT8 ListAll( void ) /* 以广度优先的算法枚举整个U盘中的所有文件及目录 */
{
UINT8 i;
UINT16 OldFileCount;
OldFileCount = FileCount = 0; /* 清文件结构计数 */
FileNameBuffer[ 0 ].Name[0] = '/'; /* 根目录,是完整路径名,除根目录是绝对路径之外都是相对路径 */
FileNameBuffer[ 0 ].Name[1] = 0;
FileNameBuffer[ 0 ].DirStartClust = 0; /* 根目录的这个参数无意义 */
FileNameBuffer[ 0 ].Attr = ATTR_DIRECTORY; /* 根目录也是目录,作为第一个记录保存 */
for ( FileCount = 1; OldFileCount < FileCount; OldFileCount ++ ) { /* 尚有新枚举到的文件名结构未进行分析 */
if ( FileNameBuffer[ OldFileCount ].Attr & ATTR_DIRECTORY ) { /* 是目录则继续进行深度搜索 */
strcpy( mCmdParam.Open.mPathName, FileNameBuffer[ OldFileCount ].Name ); /* 目录名,除根目录外都是相对路径 */
CH374vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 当前目录的上级目录的起始簇号,便于用相对路径打开,比完整路径名速度快 */
i = CH374FileOpen( ); /* 打开目录,仅为了获取目录的起始簇号以提高速度 */
if ( i == ERR_SUCCESS ) return( ERR_MISS_DIR ); /* 应该是打开了目录,但是返回结果是打开了文件 */
if ( i != ERR_OPEN_DIR ) return( i );
if ( OldFileCount ) CurrentDirStartClust = CH374vStartCluster; /* 不是根目录,获取目录的起始簇号 */
else { /* 是根目录,获取根目录的起始簇号 */
if ( CH374vDiskFat == DISK_FAT32 ) CurrentDirStartClust = CH374vDiskRoot; /* FAT32根目录 */
else CurrentDirStartClust = 0; /* FAT12/FAT16根目录 */
}
CH374FileClose( ); /* 对于根目录一定要关闭 */
// strcpy( mCmdParam.Open.mPathName, FileNameBuffer[ OldFileCount ].Name ); /* 目录名,由于mPathName未被修改所以无需再复制 */
CH374vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 当前目录的上级目录的起始簇号,便于用相对路径打开,比完整路径名速度快 */
i = ListFile( ); /* 枚举目录,由回调程序xFileNameEnumer产生记录保存到结构中 */
if ( i != ERR_SUCCESS ) return( i );
}
}
// U盘中的文件及目录全部枚举完毕,下面开始根据结构记录依次打开文件 */
printf( "Total file&dir = %d, Open every file:\n", FileCount );
for ( OldFileCount = 0; OldFileCount < FileCount; OldFileCount ++ ) {
if ( ( FileNameBuffer[ OldFileCount ].Attr & ATTR_DIRECTORY ) == 0 ) { /* 是文件则打开,目录则跳过 */
printf( "Open file: %s\n", FileNameBuffer[ OldFileCount ].Name );
strcpy( mCmdParam.Open.mPathName, FileNameBuffer[ OldFileCount ].Name ); /* 相对路径 */
CH374vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 当前文件的上级目录的起始簇号,便于用相对路径打开,比完整路径名速度快 */
i = CH374FileOpen( ); /* 打开文件 */
if ( i == ERR_SUCCESS ) { /* 成功打开了文件 */
mCmdParam.ReadX.mDataBuffer = 0x2000; /* 指向文件数据缓冲区的起始地址 */
mCmdParam.ReadX.mSectorCount = 1; /* 读取扇区数 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -