?? ch375hft.c
字號:
/* 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 主機文件系統接口 */
/* 支持: FAT12/FAT16/FAT32 */
/* MCS-51單片機C語言的U盤文件讀寫示例程序, 適用于89C52或者更大程序空間的單片機 */
/* 本程序用于演示列出指定目錄下的所有文件,以及用于搜索/枚舉文件名 */
/* CH375的INT#引腳采用查詢方式處理, 數據復制方式為"單DPTR復制", 所以速度較慢, 適用于所有MCS51單片機
本例適用于V3.0及以上版本、或者V2.8及以上版本的CH375子程序庫 */
/* C51 CH375HFT.C */
/* LX51 CH375HFT.OBJ , CH375HF4.LIB 如果將CH375HF4換成CH375HF6就可以支持FAT32 */
/* OHX51 CH375HFT */
#include <reg52.h>
#include <stdio.h>
#include <string.h>
/* 以下定義的詳細說明請看CH375HF6.H文件 */
#define LIB_CFG_DISK_IO 1 /* 磁盤讀寫的數據的復制方式,1為"單DPTR復制",2為"雙DPTR復制",3為"單DPTR和P2+R0復制" */
#define LIB_CFG_FILE_IO 1 /* 文件讀寫的數據的復制方式,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*/ /* 使用CH375HF6.H提供的默認"外部子程序" */
/*#define LIB_CFG_UPD_SIZE 1*/ /* 在添加數據后是否自動更新文件長度: 0為"不更新",1為"自動更新" */
/* 默認情況下,如果扇區數/字節數不為0那么CH375FileWrite/CH375ByteWrite只負責寫入數據而不修改文件長度,
如果需要每次寫完數據后會自動修改/更新文件長度,那么可以使全局變量CH375LibConfig的位4為1,
如果長時間不寫入數據則應該更新文件長度,防止突然斷電后前面寫入的數據與文件長度不相符,
如果確定不會突然斷電或者后面很快有數據不斷寫入則不必更新文件長度,可以提高速度并減少U盤損耗(U盤內部的內存壽命有限,不宜頻繁改寫) */
#define CH375_CMD_PORT_ADDR 0xBDF1 /* CH375命令端口的I/O地址 */
#define CH375_DAT_PORT_ADDR 0xBCF0 /* CH375數據端口的I/O地址 */
/* 62256提供的32KB的RAM分為兩部分: 0000H-01FFH為磁盤讀寫緩沖區, 0200H-7FFFH為文件數據緩沖區 */
#define DISK_BASE_BUF_ADDR 0x0000 /* 外部RAM的磁盤數據緩沖區的起始地址,從該單元開始的緩沖區長度為SECTOR_SIZE */
#define DISK_BASE_BUF_LEN 4096 /* 默認的磁盤數據緩沖區大小為512字節,建議選擇為2048甚至4096以支持某些大扇區的U盤,為0則禁止在.H文件中定義緩沖區并由應用程序在pDISK_BASE_BUF中指定 */
/* 如果需要復用磁盤數據緩沖區以節約RAM,那么可將DISK_BASE_BUF_LEN定義為0以禁止在.H文件中定義緩沖區,而由應用程序在調用CH375Init之前將與其它程序合用的緩沖區起始地址置入pDISK_BASE_BUF變量 */
#define FILE_DATA_BUF_ADDR 0x1000 /* 外部RAM的文件數據緩沖區的起始地址,緩沖區長度不小于一次讀寫的數據長度,字節模式不用該緩沖區 */
#define FILE_DATA_BUF_LEN 4096
#define CH375_INT_WIRE INT0 /* P3.2, INT0, CH375的中斷線INT#引腳,連接CH375的INT#引腳,用于查詢中斷狀態 */
#define NO_DEFAULT_CH375_F_ENUM 1 /* 未調用CH375FileEnumer程序故禁止以節約代碼 */
#define NO_DEFAULT_CH375_F_QUERY 1 /* 未調用CH375FileQuery程序故禁止以節約代碼 */
#define NO_DEFAULT_FILE_ENUMER 1 /* 禁止默認的文件名枚舉回調程序,下面用自行編寫的程序代替它 */
#include "..\CH375HF6.H" /* 如果不需要支持FAT32,那么請選用CH375HF4.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顯示 */
/* 以毫秒為單位延時,不精確,適用于24MHz時鐘 */
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時鐘下延時500uS */
for ( j = 200; j != 0; j -- ) c += 3; /* 在24MHz時鐘下延時500uS */
}
}
/* 將程序空間的字符串復制到內部RAM中,返回字符串長度 */
UINT8 mCopyCodeStringToIRAM( UINT8 idata *iDestination, UINT8 code *iSource )
{
UINT8 i = 0;
while ( *iDestination = *iSource ) {
iDestination ++;
iSource ++;
i ++;
}
return( i );
}
/* 檢查操作狀態,如果錯誤則顯示錯誤代碼并停機,應該替換為實際的處理措施 */
void mStopIfError( UINT8 iError )
{
if ( iError == ERR_SUCCESS ) return; /* 操作成功 */
printf( "Error: %02X\n", (UINT16)iError ); /* 顯示錯誤 */
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及以上版本的子程序庫,只有V3.0及以上版本的子程序庫才能支持xFileNameEnumer回調程序 */
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\CH375*"等 */
mCmdParam.Open.mPathName[i] = 0xFF; /* 0xFF指定枚舉序號在CH375vFileSize中 */
CH375vFileSize = 0xFFFFFFFF; /* 快速連續枚舉,每找到一個文件調用一次xFileNameEnumer回調子程序,如果值小于0x80000000則每次只枚舉一個文件太慢 */
i = CH375FileOpen( ); /* 枚舉,由回調程序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 ); /* 目錄名,除根目錄外都是相對路徑 */
CH375vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 當前目錄的上級目錄的起始簇號,便于用相對路徑打開,比完整路徑名速度快 */
i = CH375FileOpen( ); /* 打開目錄,僅為了獲取目錄的起始簇號以提高速度 */
if ( i == ERR_SUCCESS ) return( ERR_MISS_DIR ); /* 應該是打開了目錄,但是返回結果是打開了文件 */
if ( i != ERR_OPEN_DIR ) return( i );
if ( OldFileCount ) CurrentDirStartClust = CH375vStartCluster; /* 不是根目錄,獲取目錄的起始簇號 */
else { /* 是根目錄,獲取根目錄的起始簇號 */
if ( CH375vDiskFat == DISK_FAT32 ) CurrentDirStartClust = CH375vDiskRoot; /* FAT32根目錄 */
else CurrentDirStartClust = 0; /* FAT12/FAT16根目錄 */
}
CH375FileClose( ); /* 對于根目錄一定要關閉 */
// strcpy( mCmdParam.Open.mPathName, FileNameBuffer[ OldFileCount ].Name ); /* 目錄名,由于mPathName未被修改所以無需再復制 */
CH375vStartCluster = 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 ); /* 相對路徑 */
CH375vStartCluster = FileNameBuffer[ OldFileCount ].DirStartClust; /* 當前文件的上級目錄的起始簇號,便于用相對路徑打開,比完整路徑名速度快 */
i = CH375FileOpen( ); /* 打開文件 */
if ( i == ERR_SUCCESS ) { /* 成功打開了文件 */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -