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

📄 ch375udevice.c

📁 USB 1.1 U Device for CH375 & USB 2.0 for CH375A 读写usb超精简的程序
💻 C
字号:
//=================================================================================================
//*************************************************************************************************
// Module Name  : CH375UDevice.C
// Device object: 
// Create date  : 2005-11-07 
// Modify date  : 2005-11-11 
// Description  : USB 1.1 U Device for CH375 
//                
// Author       : Li yuanzheng 
// Version      : V1.0  
//*************************************************************************************************
//=================================================================================================
// 
/* 这个程序用180行C代码就能够读取FAT16文件系统U盘的根目录,可以看到根目录下的文件
名,并可显示
首文件内容,不过,该程序很不严谨,也没有任何错误处理,对U盘兼容性较差,只是用于简单试
验,作为参考.
这个程序可以支持WINDOWS按FAT16格式化的U盘,因为程序精简,所以只兼容超过50%以上的U
盘品牌,如果换
成CH375A芯片则兼容性可提高到85%,当然,如果使用WCH公司的子程序库或者正式版本的C源
程序兼容性更好。
欢测试以下U盘通过:郎科/超稳经典64M/超稳迷你128M/U160-64M/超稳普及128M,爱国者/迷
你王16M/邮箱型,
黑匣子/64M,微闪/64M,飙王/32M/64M/128M,晶彩/C200-64M,新科/256M,昂达/128M...,欢迎
提供测试结果
未通过U盘:爱国者/智慧棒128M,清华普天/USB2.0-128M,当然,使用WCH的子程序库或CH375A
都可以测试通过 */
//-------------------------------------------------------------------------------------------------
// Includes 
//-------------------------------------------------------------------------------------------------

#include <regx52.h>  // 以下定义适用于MCS-51单片机,其它单片机参照修改 
#include <stdio.h>
#include "CH375H.H"
#include "CH375UDevice.H"

//=================================================================================================
// 
//UINT8X  FILE_DATA_BUF[512*32] _at_ 0x0000;  // 外部RAM数据缓冲区的起始地址 (DISK_BUFFER) 

UINT32  DiskStart;    // 逻辑盘的起始绝对扇区号LBA 
UINT8   SecPerClus;   // 逻辑盘的每簇扇区数 
UINT8   ResvdSecCnt;  // 逻辑盘的保留扇区数 
UINT16  FATSize16;    // FAT16逻辑盘的FAT表占用的扇区数 

//=================================================================================================
// 
//=================================================================================================
// 

//=================================================================================================
// BulkOnly传输协议层,被CH375内置了,无需编写单片机程序 
//=================================================================================================
// 
//=================================================================================================
//=================================================================================================
// RBC/SCSI命令层,虽然被CH375内置了,但是要写程序发出命令及收发数据 
//=================================================================================================
//=================================================================================================
// 
//-------------------------------------------------------------------------------------------------
// 初始化磁盘 
UINT8  mInitDisk( void ) 
{  
	xWriteCH375Cmd( CMD_GET_STATUS );     // 产生操作完成中断, 获取中断状态 
	xQueryInterrupt( );                   // 等待中断并获取状态 
	if( CH375IntStatus == USB_INT_DISCONNECT ) return( CH375IntStatus );  // USB设备断开 

	xWriteCH375Cmd( CMD_DISK_INIT );      // 初始化USB存储器     
	xQueryInterrupt( );                   // 等待中断并获取状态 
	if( CH375IntStatus != USB_INT_SUCCESS ) return( CH375IntStatus );     // 出现错误 

	xWriteCH375Cmd( CMD_DISK_SIZE );      // 获取USB存储器的容量 
	xQueryInterrupt( );                   // 等待中断并获取状态 
	if( CH375IntStatus != USB_INT_SUCCESS )     // 出错重试 
	{                                     // 对于CH375A芯片,建议在此执行一次CMD_DISK_R_SENSE命令 
		mDelaymS( 250 );
		xWriteCH375Cmd( CMD_DISK_SIZE );  // 获取USB存储器的容量 
		xQueryInterrupt( );               // 等待中断并获取状态 
	}
	if( CH375IntStatus != USB_INT_SUCCESS ) return( CH375IntStatus );     // 出现错误 
	
	return( 0 );                          // U盘已经成功初始化 
}

//-------------------------------------------------------------------------------------------------
// 从USB存储器的指定地点读数据块到外部缓冲区 
UINT8  mReadSector( UINT32 iLbaStart, UINT8 iSectorCount, UINT8X *DataBuffer ) 
{
	UINT16  mBlockCount;

	// 从USB存储器读数据块 
	xWriteCH375Cmd( CMD_DISK_READ );   

	xWriteCH375Data( (UINT8)iLbaStart           );  // LBA的最低8位 
	xWriteCH375Data( (UINT8)( iLbaStart >> 8  ) );
	xWriteCH375Data( (UINT8)( iLbaStart >> 16 ) );
	xWriteCH375Data( (UINT8)( iLbaStart >> 24 ) );  // LBA的最高8位 

	xWriteCH375Data( iSectorCount );      // 扇区数 
	for ( mBlockCount = iSectorCount * 8; mBlockCount != 0; mBlockCount -- ) 
	{
		xQueryInterrupt( );               // 等待中断并获取状态 
		if ( CH375IntStatus == USB_INT_DISK_READ )  // 等待中断并获取状态,请求数据读出 
		{  
			xWriteCH375Cmd( CMD_RD_USB_DATA );      // 从CH375缓冲区读取数据块 
			CH375IntStatus = xReadCH375Data( );     // 后续数据的长度 
			while ( CH375IntStatus -- ) *DataBuffer++ = xReadCH375Data( );
			xWriteCH375Cmd( CMD_DISK_RD_GO );       // 继续执行USB存储器的读操作 
		}
		else break;                       // 返回错误状态 
	}

	if ( mBlockCount == 0 ) 
	{
		xQueryInterrupt( );               // 等待中断并获取状态 
		if ( CH375IntStatus == USB_INT_SUCCESS ) return( 0 );     // 操作成功 
	}

	return( CH375IntStatus );             // 操作失败 
}

//=================================================================================================
//=================================================================================================
// FAT文件系统层,这层程序量实际较大,不过,该程序仅演示极简单的功能,所以精简 
//=================================================================================================
//=================================================================================================
// 
//-------------------------------------------------------------------------------------------------
// 获取字数据,因为MCS51是大端格式 
UINT16  mGetPointWord( UINT8X *iAddr ) 
{  
	return( iAddr[0] | (UINT16)iAddr[1] << 8 );
}

//-------------------------------------------------------------------------------------------------
// 以下是非常简单的FAT文件系统的分析,正式应用绝对不应该如此简单 
// 识别分析当前逻辑盘 
UINT8  mIdenDisk( void ) 
{
	UINT8  Status;

	DiskStart = 0; 
	Status = mReadSector( 0, 1, FILE_DATA_BUF );      // 读取逻辑盘引导信息 
	if ( Status != 0 ) return( Status );

//	if ( (FILE_DATA_BUF[0] != 0xEB) && (FILE_DATA_BUF[0] != 0xE9) )// 不是逻辑引导扇区 
	// 不是逻辑引导扇区( EB 3E 90 ) 
	if ( (FILE_DATA_BUF[0] != 0xEB) && (FILE_DATA_BUF[1] != 0x3E) && (FILE_DATA_BUF[2] != 0x90) )
	{
		DiskStart = FILE_DATA_BUF[0x1C6] | (UINT16)FILE_DATA_BUF[0x1C7] << 8 | (UINT32)FILE_DATA_BUF[0x1C8] << 16 | (UINT32)FILE_DATA_BUF[0x1C9] << 24;
		Status = mReadSector( DiskStart, 1, FILE_DATA_BUF );
		if ( Status != 0 ) return( Status );
	}
	SecPerClus  = FILE_DATA_BUF[0x0D];    // 每簇扇区数 
	ResvdSecCnt = FILE_DATA_BUF[0x0E];    // 逻辑盘的保留扇区数 
//	ResvdSecCnt = mGetPointWord( &FILE_DATA_BUF[0x0E] );  // 逻辑盘的保留扇区数 
	FATSize16   = mGetPointWord( &FILE_DATA_BUF[0x16] );  // FAT表占用扇区数 

	return( 0 );                          // 成功 
}

//-------------------------------------------------------------------------------------------------
// 获得指定簇号的链接簇 
// 输入: iCluster 当前簇号 
// 返回: 原链接簇号, 如果为 0 则说明错误 
UINT16  mLinkCluster( UINT16 iCluster ) 
{
	UINT8  Status;

	Status = mReadSector( DiskStart + ResvdSecCnt + iCluster / 256, 1, FILE_DATA_BUF );
	if ( Status != 0 ) return( 0 );       // 错误 
	
	return( mGetPointWord( &FILE_DATA_BUF[ ( iCluster + iCluster ) & 0x01FF ] ) );
}

//-------------------------------------------------------------------------------------------------
// 将簇号转换为绝对LBA扇区地址 
UINT32  mClusterToLba( UINT16 iCluster ) 
{
	return( DiskStart + ResvdSecCnt + FATSize16 * 2 + 32 + ( iCluster - 2 ) * SecPerClus );
}

//=================================================================================================
//=================================================================================================
// 用于调试 
//=================================================================================================
//=================================================================================================
// 
//-------------------------------------------------------------------------------------------------
// 仅用于调试用途及显示内容到PC机,与该程序功能完全无关 
void  mInitSTDIO( void ) 
{
	SCON = 0x50; PCON = 0x80; TMOD = 0x20; TH1 = 0xf3; TR1=1; TI=1;  // 24MHz, 9600bps 
}

//-------------------------------------------------------------------------------------------------
// 如果错误则停止运行并显示错误状态 
void  mStopIfError( UINT8 iErrCode ) 
{
	if ( iErrCode == 0 ) return;
	printf( "Error status, %02X\n", (UINT16)iErrCode );
}

//=================================================================================================
//=================================================================================================
// Main 
//=================================================================================================
//=================================================================================================
// 
void main( void ) 
{
	UINT8  Status;
	UINT8X  *CurrentDir;
	UINT16  Cluster;
	
	mDelaymS( 200 );                      // 延时200毫秒 
	mInitSTDIO( );
	
	xWriteCH375Cmd( CMD_SET_USB_MODE );   // 初始化CH375,设置USB工作模式 
	xWriteCH375Data( 6 );                 // 模式代码,自动检测USB设备连接 

	while ( 1 ) 
	{
		printf( "Insert USB disk\n" );
		while ( mWaitInterrupt( ) != USB_INT_CONNECT );    // 等待U盘连接 
		mDelaymS( 250 );                  // 延时等待U盘进入正常工作状态 

		Status = mInitDisk( );            // 初始化U盘,实际是识别U盘的类型,必须进行此步骤 
		mStopIfError( Status );
		Status = mIdenDisk( );            // 识别分析U盘文件系统,必要操作 
		mStopIfError( Status );
		
		// 读取FAT16逻辑盘的根目录,通常根目录占用32个扇区 
		Status = mReadSector( DiskStart + ResvdSecCnt + FATSize16 * 2, 32, FILE_DATA_BUF );
		mStopIfError( Status );           
		for ( CurrentDir = FILE_DATA_BUF; CurrentDir[0] != 0; CurrentDir += 32 ) 
		{
			if ( ( CurrentDir[0x0B] & 0x08 ) == 0 && CurrentDir[0] != 0xE5 ) 
			{
				CurrentDir[0x0B] = 0;     // 为了便于显示,设置文件名或者目录名的结束标志 
				printf( "Name: %s\n", CurrentDir ); // 通过串口输出显示 
			}
		}  
		
		// 以上显示根目录下的所有文件名,以下打开第一个文件,如果是C文件的话 
		if ( (FILE_DATA_BUF[0x0B]&0x08)==0 && FILE_DATA_BUF[0]!=0xE5 && FILE_DATA_BUF[8]=='C' ) 
		{
			Cluster = mGetPointWord( &FILE_DATA_BUF[0x1A] ); // 文件的首簇 
			while ( Cluster < 0xFFF8 )    // 文件簇未结束 
			{  
				if ( Cluster == 0 ) mStopIfError( 0x8F );  // 对于首簇,可能是0长度文件 
				Status = mReadSector( mClusterToLba( Cluster ), SecPerClus, FILE_DATA_BUF );
				mStopIfError( Status );   // 读取首簇到缓冲区 
				FILE_DATA_BUF[30] = 0; 
				printf( "Data: %s\n", FILE_DATA_BUF );// 显示首行 
				Cluster = mLinkCluster( Cluster );  // 获取链接簇,返回0说明错误 
			}
		}

		while ( mWaitInterrupt( ) != USB_INT_DISCONNECT ); // 等待U盘拔出 
		mDelaymS( 250 );
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -