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

📄 file_sys.c

📁 基于CH376的U盘读写例子
💻 C
📖 第 1 页 / 共 3 页
字号:
/* CH376芯片 文件系统层 V1.1 */
/* 提供文件系统常用子程序,提供命令打包 */
/* 不使用的子程序可以注释掉,从而节约单片机的程序ROM空间和数据RAM空间 */
/* 这里的子程序是通过括号中的变量传递参数,如果参数较多,为了节约RAM,也可以参考CH375子程序库改成通过同一全局变量/联合结构CH376_CMD_DATA传递 */

/* name 参数是指短文件名, 可以包括根目录符, 但不含有路径分隔符, 总长度不超过1+8+1+3+1字节 */
/* PathName 参数是指全路径的短文件名, 包括根目录符、多级子目录及路径分隔符、文件名/目录名 */
/* LongName 参数是指长文件名, 以UNICODE小端顺序编码, 以两个0字节结束, 使用长文件名子程序必须先定义全局缓冲区GlobalBuf, 长度不小于64字节, 可以与其它子程序共用 */

/* 定义 NO_DEFAULT_CH376_INT 用于禁止默认的Wait376Interrupt子程序,禁止后,应用程序必须自行定义一个同名子程序 */
/* 定义 DEF_INT_TIMEOUT 用于设置默认的Wait376Interrupt子程序中的等待中断的超时时间/循环计数值, 0则不检查超时而一直等待 */
/* 定义 EN_DIR_CREATE 用于提供新建多级子目录的子程序,默认是不提供 */
/* 定义 EN_DISK_QUERY 用于提供磁盘容量查询和剩余空间查询的子程序,默认是不提供 */
/* 定义 EN_SECTOR_ACCESS 用于提供以扇区为单位读写文件的子程序,默认是不提供 */
/* 定义 EN_LONG_NAME 用于提供支持长文件名的子程序,默认是不提供 */

#include	"FILE_SYS.H"

UINT8	CH376ReadBlock( PUINT8 buf )  /* 从当前主机端点的接收缓冲区读取数据块,返回长度 */
{
	UINT8	s, l;
	xWriteCH376Cmd( CMD01_RD_USB_DATA0 );
	s = l = xReadCH376Data( );  /* 长度 */
	if ( l ) {
		do {
			*buf = xReadCH376Data( );
			buf ++;
		} while ( -- l );
	}
	xEndCH376Cmd( );
	return( s );
}

UINT8	CH376WriteReqBlock( PUINT8 buf )  /* 向内部指定缓冲区写入请求的数据块,返回长度 */
{
	UINT8	s, l;
	xWriteCH376Cmd( CMD01_WR_REQ_DATA );
	s = l = xReadCH376Data( );  /* 长度 */
	if ( l ) {
		do {
			xWriteCH376Data( *buf );
			buf ++;
		} while ( -- l );
	}
	xEndCH376Cmd( );
	return( s );
}

void	CH376WriteHostBlock( PUINT8 buf, UINT8 len )  /* 向USB主机端点的发送缓冲区写入数据块 */
{
	xWriteCH376Cmd( CMD10_WR_HOST_DATA );
	xWriteCH376Data( len );  /* 长度 */
	if ( len ) {
		do {
			xWriteCH376Data( *buf );
			buf ++;
		} while ( -- len );
	}
	xEndCH376Cmd( );
}

void	CH376WriteOfsBlock( PUINT8 buf, UINT8 ofs, UINT8 len )  /* 向内部缓冲区指定偏移地址写入数据块 */
{
	xWriteCH376Cmd( CMD20_WR_OFS_DATA );
	xWriteCH376Data( ofs );  /* 偏移地址 */
	xWriteCH376Data( len );  /* 长度 */
	if ( len ) {
		do {
			xWriteCH376Data( *buf );
			buf ++;
		} while ( -- len );
	}
	xEndCH376Cmd( );
}

void	CH376SetFileName( PUINT8 name )  /* 设置将要操作的文件的文件名 */
{
/*	UINT8	i;*/
	UINT8	c;
	xWriteCH376Cmd( CMD10_SET_FILE_NAME );
/*	for ( i = MAX_FILE_NAME_LEN; i != 0; -- i ) {
		c = *name;
		xWriteCH376Data( c );
		if ( c == 0 ) break;
		name ++;
	}*/
	c = *name;
	xWriteCH376Data( c );
	while ( c ) {
		name ++;
		c = *name;
		if ( c == DEF_SEPAR_CHAR1 || c == DEF_SEPAR_CHAR2 ) c = 0;  /* 强行将文件名截止 */
		xWriteCH376Data( c );
	}
	xEndCH376Cmd( );
}

UINT32	CH376Read32bitDat( void )  /* 从CH376芯片读取32位的数据并结束命令 */
{
	UINT8	c0, c1, c2, c3;
	c0 = xReadCH376Data( );
	c1 = xReadCH376Data( );
	c2 = xReadCH376Data( );
	c3 = xReadCH376Data( );
	xEndCH376Cmd( );
	return( c0 | (UINT16)c1 << 8 | (UINT32)c2 << 16 | (UINT32)c3 << 24 );
}

UINT8	CH376ReadVar8( UINT8 var )  /* 读CH376芯片内部的8位变量 */
{
	UINT8	c0;
	xWriteCH376Cmd( CMD11_READ_VAR8 );
	xWriteCH376Data( var );
	c0 = xReadCH376Data( );
	xEndCH376Cmd( );
	return( c0 );
}

void	CH376WriteVar8( UINT8 var, UINT8 dat )  /* 写CH376芯片内部的8位变量 */
{
	xWriteCH376Cmd( CMD20_WRITE_VAR8 );
	xWriteCH376Data( var );
	xWriteCH376Data( dat );
	xEndCH376Cmd( );
}

UINT32	CH376ReadVar32( UINT8 var )  /* 读CH376芯片内部的32位变量 */
{
	xWriteCH376Cmd( CMD14_READ_VAR32 );
	xWriteCH376Data( var );
	return( CH376Read32bitDat( ) );  /* 从CH376芯片读取32位的数据并结束命令 */
}

void	CH376WriteVar32( UINT8 var, UINT32 dat )  /* 写CH376芯片内部的32位变量 */
{
	xWriteCH376Cmd( CMD50_WRITE_VAR32 );
	xWriteCH376Data( var );
	xWriteCH376Data( (UINT8)dat );
	xWriteCH376Data( (UINT8)( (UINT16)dat >> 8 ) );
	xWriteCH376Data( (UINT8)( dat >> 16 ) );
	xWriteCH376Data( (UINT8)( dat >> 24 ) );
	xEndCH376Cmd( );
}

void	CH376EndDirInfo( void )  /* 在调用CH376DirInfoRead获取FAT_DIR_INFO结构之后应该通知CH376结束 */
{
	CH376WriteVar8( 0x0D, 0x00 );
}

UINT32	CH376GetFileSize( void )  /* 读取当前文件长度 */
{
	return( CH376ReadVar32( VAR_FILE_SIZE ) );
}

UINT8	CH376GetDiskStatus( void )  /* 获取磁盘和文件系统的工作状态 */
{
	return( CH376ReadVar8( VAR_DISK_STATUS ) );
}

UINT8	CH376GetIntStatus( void )  /* 获取中断状态并取消中断请求 */
{
	UINT8	s;
	xWriteCH376Cmd( CMD01_GET_STATUS );
	s = xReadCH376Data( );
	xEndCH376Cmd( );
	return( s );
}

#ifndef	NO_DEFAULT_CH376_INT
UINT8	Wait376Interrupt( void )  /* 等待CH376中断(INT#低电平),返回中断状态码, 超时则返回ERR_USB_UNKNOWN */
{
#ifdef	DEF_INT_TIMEOUT
#if		DEF_INT_TIMEOUT < 1
	while ( Query376Interrupt( ) == FALSE );  /* 一直等中断 */
	return( CH376GetIntStatus( ) );  /* 检测到中断 */
#else
	UINT32	i;
	for ( i = 0; i < DEF_INT_TIMEOUT; i ++ ) {  /* 计数防止超时 */
		if ( Query376Interrupt( ) ) return( CH376GetIntStatus( ) );  /* 检测到中断 */
/* 在等待CH376中断的过程中,可以做些需要及时处理的其它事情 */
	}
	return( ERR_USB_UNKNOWN );  /* 不应该发生的情况 */
#endif
#else
	UINT32	i;
	for ( i = 0; i < 5000000; i ++ ) {  /* 计数防止超时,默认的超时时间,与单片机主频有关 */
		if ( Query376Interrupt( ) ) return( CH376GetIntStatus( ) );  /* 检测到中断 */
/* 在等待CH376中断的过程中,可以做些需要及时处理的其它事情 */
	}
	return( ERR_USB_UNKNOWN );  /* 不应该发生的情况 */
#endif
}
#endif

UINT8	CH376SendCmdWaitInt( UINT8 mCmd )  /* 发出命令码后,等待中断 */
{
	xWriteCH376Cmd( mCmd );
	xEndCH376Cmd( );
	return( Wait376Interrupt( ) );
}

UINT8	CH376SendCmdDatWaitInt( UINT8 mCmd, UINT8 mDat )  /* 发出命令码和一字节数据后,等待中断 */
{
	xWriteCH376Cmd( mCmd );
	xWriteCH376Data( mDat );
	xEndCH376Cmd( );
	return( Wait376Interrupt( ) );
}

UINT8	CH376DiskReqSense( void )  /* 检查USB存储器错误 */
{
	UINT8	s;
	mDelaymS( 5 );
	s = CH376SendCmdWaitInt( CMD0H_DISK_R_SENSE );
	mDelaymS( 5 );
	return( s );
}

UINT8	CH376DiskConnect( void )  /* 检查U盘是否连接,不支持SD卡 */
{
	if ( Query376Interrupt( ) ) CH376GetIntStatus( );  /* 检测到中断 */
	return( CH376SendCmdWaitInt( CMD0H_DISK_CONNECT ) );
}

UINT8	CH376DiskMount( void )  /* 初始化磁盘并测试磁盘是否就绪 */
{
	return( CH376SendCmdWaitInt( CMD0H_DISK_MOUNT ) );
}

UINT8	CH376FileOpen( PUINT8 name )  /* 在根目录或者当前目录下打开文件或者目录(文件夹) */
{
	CH376SetFileName( name );  /* 设置将要操作的文件的文件名 */
	if ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 ) CH376WriteVar32( VAR_CURRENT_CLUST, 0 );
	return( CH376SendCmdWaitInt( CMD0H_FILE_OPEN ) );
}

UINT8	CH376FileCreate( PUINT8 name )  /* 在根目录或者当前目录下新建文件,如果文件已经存在那么先删除 */
{
	if ( name ) CH376SetFileName( name );  /* 设置将要操作的文件的文件名 */
	return( CH376SendCmdWaitInt( CMD0H_FILE_CREATE ) );
}

UINT8	CH376DirCreate( PUINT8 name )  /* 在根目录下新建目录(文件夹)并打开,如果目录已经存在那么直接打开 */
{
	CH376SetFileName( name );  /* 设置将要操作的文件的文件名 */
	if ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 ) CH376WriteVar32( VAR_CURRENT_CLUST, 0 );
	return( CH376SendCmdWaitInt( CMD0H_DIR_CREATE ) );
}

UINT8	CH376SeparatePath( PUINT8 path )  /* 从路径中分离出最后一级文件名或者目录(文件夹)名,返回最后一级文件名或者目录名的字节偏移 */
{
	PUINT8	pName;
	for ( pName = path; *pName != 0; ++ pName );  /* 到文件名字符串结束位置 */
	while ( *pName != DEF_SEPAR_CHAR1 && *pName != DEF_SEPAR_CHAR2 && pName != path ) pName --;  /*  搜索倒数第一个路径分隔符 */
	if ( pName != path ) pName ++;  /* 找到了路径分隔符,则修改指向目标文件的最后一级文件名,跳过前面的多级目录名及路径分隔符 */
	return( pName - path );
}

UINT8	CH376FileOpenDir( PUINT8 PathName, UINT8 StopName )  /* 打开多级目录下的文件或者目录的上级目录,支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */
/* StopName 指向最后一级文件名或者目录名 */
{
	UINT8	i, s;
	s = 0;
	i = 1;  /* 跳过有可能的根目录符 */
	while ( 1 ) {
		while ( PathName[i] != DEF_SEPAR_CHAR1 && PathName[i] != DEF_SEPAR_CHAR2 && PathName[i] != 0 ) ++ i;  /* 搜索下一个路径分隔符或者路径结束符 */
		if ( PathName[i] ) i ++;  /* 找到了路径分隔符,修改指向目标文件的最后一级文件名 */
		else i = 0;  /* 路径结束 */
		s = CH376FileOpen( &PathName[s] );  /* 打开文件或者目录 */
		if ( i && i != StopName ) {  /* 路径尚未结束 */
			if ( s != ERR_OPEN_DIR ) {  /* 因为是逐级打开,尚未到路径结束,所以,如果不是成功打开了目录,那么说明有问题 */
				if ( s == USB_INT_SUCCESS ) return( ERR_FOUND_NAME );  /* 中间路径必须是目录名,如果是文件名则出错 */
				else if ( s == ERR_MISS_FILE ) return( ERR_MISS_DIR );  /* 中间路径的某个子目录没有找到,可能是目录名称错误 */
				else return( s );  /* 操作出错 */
			}
			s = i;  /* 从下一级目录开始继续 */
		}
		else return( s );  /* 路径结束,USB_INT_SUCCESS为成功打开文件,ERR_OPEN_DIR为成功打开目录(文件夹),其它为操作出错 */
	}
}

UINT8	CH376FileOpenPath( PUINT8 PathName )  /* 打开多级目录下的文件或者目录(文件夹),支持多级目录路径,支持路径分隔符,路径长度不超过255个字符 */

⌨️ 快捷键说明

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