?? ch375hft.c
字號(hào):
/* 2004.06.05
****************************************
** Copyright (C) W.ch 1999-2004 **
** Web: http://www.winchiphead.com **
****************************************
** USB Host File Interface for CH375 **
** TC2.0@PC, KC7.0@MCS51 **
****************************************
*/
/* CH375 主機(jī)文件系統(tǒng)接口 */
/* 支持: FAT12/FAT16/FAT32 */
/* MCS-51單片機(jī)C語言的U盤文件讀寫示例程序, 適用于89C52或者更大程序空間的單片機(jī) */
/* 本程序用于演示列出指定目錄下的所有文件,以及用于搜索/枚舉文件名 */
/* CH375的INT#引腳采用查詢方式處理, 數(shù)據(jù)復(fù)制方式為"單DPTR復(fù)制", 所以速度較慢, 適用于所有MCS51單片機(jī)
本例適用于V3.0及以上版本、或者V2.8及以上版本的CH375子程序庫(kù) */
/* C51 CH375HFT.C */
/* LX51 CH375HFT.OBJ , CH375HF4.LIB 如果將CH375HF4換成CH375HF6就可以支持FAT32 */
/* OHX51 CH375HFT */
#include <reg52.h>
#include <stdio.h>
#include <string.h>
/* 以下定義的詳細(xì)說明請(qǐng)看CH375HF6.H文件 */
#define LIB_CFG_DISK_IO 1 /* 磁盤讀寫的數(shù)據(jù)的復(fù)制方式,1為"單DPTR復(fù)制",2為"雙DPTR復(fù)制",3為"單DPTR和P2+R0復(fù)制" */
#define LIB_CFG_FILE_IO 1 /* 文件讀寫的數(shù)據(jù)的復(fù)制方式,0為"外部子程序",1為"單DPTR復(fù)制",2為"雙DPTR復(fù)制",3為"單DPTR和P2+R0復(fù)制" */
#define LIB_CFG_INT_EN 0 /* CH375的INT#引腳連接方式,0為"查詢方式",1為"中斷方式" */
/*#define LIB_CFG_FILE_IO_DEFAULT 1*/ /* 使用CH375HF6.H提供的默認(rèn)"外部子程序" */
/*#define LIB_CFG_UPD_SIZE 1*/ /* 在添加數(shù)據(jù)后是否自動(dòng)更新文件長(zhǎng)度: 0為"不更新",1為"自動(dòng)更新" */
/* 默認(rèn)情況下,如果扇區(qū)數(shù)/字節(jié)數(shù)不為0那么CH375FileWrite/CH375ByteWrite只負(fù)責(zé)寫入數(shù)據(jù)而不修改文件長(zhǎng)度,
如果需要每次寫完數(shù)據(jù)后會(huì)自動(dòng)修改/更新文件長(zhǎng)度,那么可以使全局變量CH375LibConfig的位4為1,
如果長(zhǎng)時(shí)間不寫入數(shù)據(jù)則應(yīng)該更新文件長(zhǎng)度,防止突然斷電后前面寫入的數(shù)據(jù)與文件長(zhǎng)度不相符,
如果確定不會(huì)突然斷電或者后面很快有數(shù)據(jù)不斷寫入則不必更新文件長(zhǎng)度,可以提高速度并減少U盤損耗(U盤內(nèi)部的內(nèi)存壽命有限,不宜頻繁改寫) */
#define CH375_CMD_PORT_ADDR 0xBDF1 /* CH375命令端口的I/O地址 */
#define CH375_DAT_PORT_ADDR 0xBCF0 /* CH375數(shù)據(jù)端口的I/O地址 */
/* 62256提供的32KB的RAM分為兩部分: 0000H-01FFH為磁盤讀寫緩沖區(qū), 0200H-7FFFH為文件數(shù)據(jù)緩沖區(qū) */
#define DISK_BASE_BUF_ADDR 0x0000 /* 外部RAM的磁盤數(shù)據(jù)緩沖區(qū)的起始地址,從該單元開始的緩沖區(qū)長(zhǎng)度為SECTOR_SIZE */
#define DISK_BASE_BUF_LEN 4096 /* 默認(rèn)的磁盤數(shù)據(jù)緩沖區(qū)大小為512字節(jié),建議選擇為2048甚至4096以支持某些大扇區(qū)的U盤,為0則禁止在.H文件中定義緩沖區(qū)并由應(yīng)用程序在pDISK_BASE_BUF中指定 */
/* 如果需要復(fù)用磁盤數(shù)據(jù)緩沖區(qū)以節(jié)約RAM,那么可將DISK_BASE_BUF_LEN定義為0以禁止在.H文件中定義緩沖區(qū),而由應(yīng)用程序在調(diào)用CH375Init之前將與其它程序合用的緩沖區(qū)起始地址置入pDISK_BASE_BUF變量 */
#define FILE_DATA_BUF_ADDR 0x1000 /* 外部RAM的文件數(shù)據(jù)緩沖區(qū)的起始地址,緩沖區(qū)長(zhǎng)度不小于一次讀寫的數(shù)據(jù)長(zhǎng)度,字節(jié)模式不用該緩沖區(qū) */
#define FILE_DATA_BUF_LEN 4096
#define CH375_INT_WIRE INT0 /* P3.2, INT0, CH375的中斷線INT#引腳,連接CH375的INT#引腳,用于查詢中斷狀態(tài) */
#define NO_DEFAULT_CH375_F_ENUM 1 /* 未調(diào)用CH375FileEnumer程序故禁止以節(jié)約代碼 */
#define NO_DEFAULT_CH375_F_QUERY 1 /* 未調(diào)用CH375FileQuery程序故禁止以節(jié)約代碼 */
#define NO_DEFAULT_FILE_ENUMER 1 /* 禁止默認(rèn)的文件名枚舉回調(diào)程序,下面用自行編寫的程序代替它 */
#include "..\CH375HF6.H" /* 如果不需要支持FAT32,那么請(qǐng)選用CH375HF4.H */
/* 在P1.4連接一個(gè)LED用于監(jiān)控演示程序的進(jìn)度,低電平LED亮,當(dāng)U盤插入后亮 */
sbit P1_4 = P1^4;
#define LED_OUT_INIT( ) { P1_4 = 1; } /* P1.4 高電平 */
#define LED_OUT_ACT( ) { P1_4 = 0; } /* P1.4 低電平驅(qū)動(dòng)LED顯示 */
#define LED_OUT_INACT( ) { P1_4 = 1; } /* P1.4 低電平驅(qū)動(dòng)LED顯示 */
sbit P1_5 = P1^5;
/* 在P1.5連接一個(gè)LED用于監(jiān)控演示程序的進(jìn)度,低電平LED亮,當(dāng)對(duì)U盤操作時(shí)亮 */
#define LED_RUN_ACT( ) { P1_5 = 0; } /* P1.5 低電平驅(qū)動(dòng)LED顯示 */
#define LED_RUN_INACT( ) { P1_5 = 1; } /* P1.5 低電平驅(qū)動(dòng)LED顯示 */
sbit P1_6 = P1^6;
/* 在P1.6連接一個(gè)LED用于監(jiān)控演示程序的進(jìn)度,低電平LED亮,當(dāng)對(duì)U盤寫操作時(shí)亮 */
#define LED_WR_ACT( ) { P1_6 = 0; } /* P1.6 低電平驅(qū)動(dòng)LED顯示 */
#define LED_WR_INACT( ) { P1_6 = 1; } /* P1.6 低電平驅(qū)動(dòng)LED顯示 */
/* 以毫秒為單位延時(shí),不精確,適用于24MHz時(shí)鐘 */
void mDelaymS( unsigned char delay )
{
unsigned char i, j, c;
for ( i = delay; i != 0; i -- ) {
for ( j = 200; j != 0; j -- ) c += 3; /* 在24MHz時(shí)鐘下延時(shí)500uS */
for ( j = 200; j != 0; j -- ) c += 3; /* 在24MHz時(shí)鐘下延時(shí)500uS */
}
}
/* 將程序空間的字符串復(fù)制到內(nèi)部RAM中,返回字符串長(zhǎng)度 */
UINT8 mCopyCodeStringToIRAM( UINT8 idata *iDestination, UINT8 code *iSource )
{
UINT8 i = 0;
while ( *iDestination = *iSource ) {
iDestination ++;
iSource ++;
i ++;
}
return( i );
}
/* 檢查操作狀態(tài),如果錯(cuò)誤則顯示錯(cuò)誤代碼并停機(jī),應(yīng)該替換為實(shí)際的處理措施 */
void mStopIfError( UINT8 iError )
{
if ( iError == ERR_SUCCESS ) return; /* 操作成功 */
printf( "Error: %02X\n", (UINT16)iError ); /* 顯示錯(cuò)誤 */
while ( 1 ) {
LED_OUT_ACT( ); /* LED閃爍 */
mDelaymS( 200 );
LED_OUT_INACT( );
mDelaymS( 200 );
}
}
/* 為printf和getkey輸入輸出初始化串口 */
void mInitSTDIO( )
{
SCON = 0x50;
PCON = 0x80;
TMOD = 0x21;
TH1 = 0xf3; /* 24MHz晶振, 9600bps */
TR1 = 1;
TI = 1;
}
#if CH375_LIB_VER >= 0x30
/* V3.0及以上版本的子程序庫(kù),只有V3.0及以上版本的子程序庫(kù)才能支持xFileNameEnumer回調(diào)程序 */
typedef struct _FILE_NAME {
UINT32 DirStartClust; /* 文件所在目錄的起始簇號(hào) */
// UINT32 Size; /* 文件長(zhǎng)度 */
UINT8 Name[8+3+1+1]; /* 文件名,共8+3字節(jié),分隔符,結(jié)束符,因?yàn)槲窗夸浢允窍鄬?duì)路徑 */
UINT8 Attr; /* 文件屬性 */
} FILE_NAME;
#define MAX_FILE_COUNT 200
FILE_NAME xdata FileNameBuffer[ MAX_FILE_COUNT ]; /* 文件名結(jié)構(gòu) */
UINT16 FileCount;
UINT32 CurrentDirStartClust; /* 保存當(dāng)前目錄的起始簇號(hào),用于加快文件枚舉和打開速度 */
/* 例子:列舉指定目錄下的所有文件 */
UINT8 ListFile( void )
// 輸入?yún)?shù)mCmdParam.Open.mPathName[]為目錄名字符串,形式與文件名相同,單個(gè)斜線則代表根目錄
{
UINT8 i;
printf( "List Directory: %s\n", mCmdParam.Open.mPathName ); /* 顯示目錄名 */
// for ( i = 0; i < MAX_PATH_LEN; i ++ ) { /* 找目錄名的結(jié)束符 */
// if ( mCmdParam.Open.mPathName[i] == 0 ) break;
// }
i = strlen( mCmdParam.Open.mPathName ); /* 計(jì)算路徑的長(zhǎng)度,找目錄名的結(jié)束符 */
if ( i && mCmdParam.Open.mPathName[i-1] == '/' ) { } /* 是根目錄,或者是已經(jīng)有路徑分隔符 */
else mCmdParam.Open.mPathName[i++] = '/'; /* 在當(dāng)前目錄下進(jìn)行枚舉,除根目錄外都是相對(duì)路徑,不是根目錄則加路徑分隔符 */
mCmdParam.Open.mPathName[i++] = '*'; /* 枚舉通配符,完整的路徑例如"\*"或者"\C51\*"或者"\C51\CH375*"等 */
mCmdParam.Open.mPathName[i] = 0xFF; /* 0xFF指定枚舉序號(hào)在CH375vFileSize中 */
CH375vFileSize = 0xFFFFFFFF; /* 快速連續(xù)枚舉,每找到一個(gè)文件調(diào)用一次xFileNameEnumer回調(diào)子程序,如果值小于0x80000000則每次只枚舉一個(gè)文件太慢 */
i = CH375FileOpen( ); /* 枚舉,由回調(diào)程序xFileNameEnumer產(chǎn)生記錄保存到結(jié)構(gòu)中 */
if ( i == ERR_SUCCESS || i == ERR_FOUND_NAME || i == ERR_MISS_FILE ) { /* 操作成功,通常不會(huì)返回ERR_SUCCESS,僅在xFileNameEnumer提前退出時(shí)才會(huì)返回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 ) /* 以廣度優(yōu)先的算法枚舉整個(gè)U盤中的所有文件及目錄 */
{
UINT8 i;
UINT16 OldFileCount;
OldFileCount = FileCount = 0; /* 清文件結(jié)構(gòu)計(jì)數(shù) */
FileNameBuffer[ 0 ].Name[0] = '/'; /* 根目錄,是完整路徑名,除根目錄是絕對(duì)路徑之外都是相對(duì)路徑 */
FileNameBuffer[ 0 ].Name[1] = 0;
FileNameBuffer[ 0 ].DirStartClust = 0; /* 根目錄的這個(gè)參數(shù)無意義 */
FileNameBuffer[ 0 ].Attr = ATTR_DIRECTORY; /* 根目錄也是目錄,作為第一個(gè)記錄保存 */
for ( FileCount = 1; OldFileCount < FileCount; OldFileCount ++ ) { /* 尚有新枚舉到的文件名結(jié)構(gòu)未進(jìn)行分析 */
if ( FileNameBuffer[ OldFileCount ].Attr & ATTR_DIRECTORY ) { /* 是目錄則繼續(xù)進(jìn)行深度搜索 */
strcpy( mCmdParam.Open.mPathName, FileNameBuffer[ OldFileCount ].Name ); /* 目錄名,除根目錄外都是相對(duì)路徑 */
CH375vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 當(dāng)前目錄的上級(jí)目錄的起始簇號(hào),便于用相對(duì)路徑打開,比完整路徑名速度快 */
i = CH375FileOpen( ); /* 打開目錄,僅為了獲取目錄的起始簇號(hào)以提高速度 */
if ( i == ERR_SUCCESS ) return( ERR_MISS_DIR ); /* 應(yīng)該是打開了目錄,但是返回結(jié)果是打開了文件 */
if ( i != ERR_OPEN_DIR ) return( i );
if ( OldFileCount ) CurrentDirStartClust = CH375vStartCluster; /* 不是根目錄,獲取目錄的起始簇號(hào) */
else { /* 是根目錄,獲取根目錄的起始簇號(hào) */
if ( CH375vDiskFat == DISK_FAT32 ) CurrentDirStartClust = CH375vDiskRoot; /* FAT32根目錄 */
else CurrentDirStartClust = 0; /* FAT12/FAT16根目錄 */
}
CH375FileClose( ); /* 對(duì)于根目錄一定要關(guān)閉 */
// strcpy( mCmdParam.Open.mPathName, FileNameBuffer[ OldFileCount ].Name ); /* 目錄名,由于mPathName未被修改所以無需再?gòu)?fù)制 */
CH375vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 當(dāng)前目錄的上級(jí)目錄的起始簇號(hào),便于用相對(duì)路徑打開,比完整路徑名速度快 */
i = ListFile( ); /* 枚舉目錄,由回調(diào)程序xFileNameEnumer產(chǎn)生記錄保存到結(jié)構(gòu)中 */
if ( i != ERR_SUCCESS ) return( i );
}
}
// U盤中的文件及目錄全部枚舉完畢,下面開始根據(jù)結(jié)構(gò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 ); /* 相對(duì)路徑 */
CH375vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 當(dāng)前文件的上級(jí)目錄的起始簇號(hào),便于用相對(duì)路徑打開,比完整路徑名速度快 */
i = CH375FileOpen( ); /* 打開文件 */
if ( i == ERR_SUCCESS ) { /* 成功打開了文件 */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -