ch376文件管理芯片,关于枚举U盘内所有文件名

       之前做过一个读取U盘内指定文件内数据的项目。读取方式有很多的限制,比如在程序中文件名是定死的,只有当程序中写的文件名跟U盘内的文件名一模一样时,才能从U盘内读取数据。这样,后期需要修改文件名的话还要在程序中修改成一模一样的名字,这样是很不方便的。

       我在寻找解决办法的时候看了看ch376数据手册,在这上面查到了有关方面的资料,找到了下面一段话:

     上面这段话是我在数据手册上看到的,里面提到可以搜索目标U盘内的所有文件名,并且包含了例程:

typedef struct _FILE_NAME {
	UINT32	DirStartClust;				/* 文件所在目录的起始簇号 */
//	UINT32	Size;						/* 文件长度 */
	UINT8	Name[8+1+3+1];				/* 文件名,共8+3字节,分隔符,结束符,因为未包含上级目录名所以是相对路径 */
	UINT8	Attr;						/* 文件属性 */
} FILE_NAME;
#define		MAX_FILE_COUNT		40
FILE_NAME	xdata	FileNameBuffer[ MAX_FILE_COUNT ];	/* 文件名结构 */
UINT16		FileCount;
UINT8		idata	buf[64];

/* 例子:列举指定序号的目录下的所有文件 */
UINT8	ListFile( UINT8 index )
/* 输入参数index是指目录在结构中的序号 */
{
	UINT8			s;
	P_FAT_DIR_INFO	pDir;
	PUINT8			pNameBuf;
	UINT32			CurrentDirStartClust;  /* 保存当前目录的起始簇号,用于加快文件枚举和打开速度 */
	CH376WriteVar32( VAR_START_CLUSTER, FileNameBuffer[ index ].DirStartClust );  /* 将当前目录的上级目录的起始簇号设置为当前簇号,相当于打开上级目录 */
	printf( "List Directory: %s\n", FileNameBuffer[ index ].Name );  /* 显示当前要列举的目录名 */
	s = CH376FileOpen( FileNameBuffer[ index ].Name );  /* 打开目录,仅为了获取目录的起始簇号以提高速度 */
	if ( s == USB_INT_SUCCESS ) return( ERR_FOUND_NAME );  /* 应该是打开了目录,但是返回结果是打开了文件 */
	else if ( s != ERR_OPEN_DIR ) return( s );
	if ( index ) CurrentDirStartClust = CH376ReadVar32( VAR_START_CLUSTER );  /* 不是根目录,获取目录的起始簇号 */
	else CurrentDirStartClust = 0;  /* 是根目录 */
	CH376FileClose( FALSE );  /* 对于根目录一定要关闭 */
	CH376WriteVar32( VAR_START_CLUSTER, CurrentDirStartClust );  /* 当前目录的起始簇号,相当于打开当前目录 */
	CH376SetFileName( "*" );  /* 设置将要操作的文件的文件名,通配符支持所有文件和子目录 */
	xWriteCH376Cmd( CMD0H_FILE_OPEN );  /* 枚举文件和目录 */
	xEndCH376Cmd( );
	while ( 1 ) {
		s = Wait376Interrupt( );
		if ( s == USB_INT_DISK_READ ) {  /* 请求数据读出 */
/* 在文件枚举过程中,不能执行其它可能产生中断的操作命令,例如,如果需要获取长文件名,那么可以将枚举出的文件名保存并在枚举结束后获取其长文件名 */
			CH376ReadBlock( buf );  /* 读取枚举到的文件的FAT_DIR_INFO结构,返回长度总是sizeof( FAT_DIR_INFO ) */
			xWriteCH376Cmd( CMD0H_FILE_ENUM_GO );  /* 继续枚举文件和目录,先发出下一个命令再分析上行读出的数据可以让CH376与单片机分别同时工作,提高速度 */
			xEndCH376Cmd( );
			pDir = (P_FAT_DIR_INFO)buf;  /* 当前文件目录信息 */
			if ( pDir -> DIR_Name[0] != '.' ) {  /* 不是本级或者上级目录名则继续,否则必须丢弃不处理 */
				if ( pDir -> DIR_Name[0] == 0x05 ) pDir -> DIR_Name[0] = 0xE5;  /* 特殊字符替换 */
				if ( pDir -> DIR_Name[8] == 'H' && pDir -> DIR_Name[9] == ' '  /* 比较文件扩展名分析文件类型的范例 */
					|| pDir -> DIR_Name[8] == 'E' && pDir -> DIR_Name[9] == 'X' && pDir -> DIR_Name[10] == 'E' ) {
					printf( "This is a .H or .EXE file\n" );
				}
				if ( FileCount < MAX_FILE_COUNT ) {  /* 文件名结构缓冲区足够 */
					pNameBuf = & FileNameBuffer[ FileCount ].Name;  /* 文件名结构中的文件名缓冲区 */
					for ( s = 0; s < 11; s ++ ) {  /* 复制文件名,长度为11个字符 */
						if ( pDir -> DIR_Name[ s ] != 0x20 ) {  /* 有效字符 */
							if ( s == 8 ) {  /* 处理扩展名 */
								*pNameBuf = '.';  /* 分隔符 */
								pNameBuf ++;
							}
							*pNameBuf = pDir -> DIR_Name[ s ];  /* 复制文件名的一个字符 */
							pNameBuf ++;
						}
					}
					*pNameBuf = 0;  /* 当前文件名完整路径的结束符 */
					FileNameBuffer[ FileCount ].DirStartClust = CurrentDirStartClust;  /* 记录当前目录的起始簇号,用于加快文件打开速度 */
					FileNameBuffer[ FileCount ].Attr = pDir -> DIR_Attr;  /* 记录文件属性 */
					if ( pDir -> DIR_Attr & ATTR_DIRECTORY ) printf( "Dir %4d#: %s\n", FileCount, FileNameBuffer[ FileCount ].Name );  /* 判断是目录名 */
					else printf( "File%4d#: %s\n", FileCount, FileNameBuffer[ FileCount ].Name );  /* 判断是文件名 */
					FileCount ++;  /* 子目录计数 */
				}
				else {  /* 文件名结构缓冲区太小,结构数量不足 */
					printf( "FileName Structure Full\n" );
					s = Wait376Interrupt( );
					CH376EndDirInfo( );  /* 获取完FAT_DIR_INFO结构 */
					break;  /* 强行终止枚举 */
				}
			}
		}
		else {
			if ( s == ERR_MISS_FILE ) s = USB_INT_SUCCESS;  /* 没有找到更多的匹配文件 */
			break;
		}
	}
/*	if ( s == USB_INT_SUCCESS ) return( s );*/  /* 操作成功 */
	return( s );
}

UINT8	ListAll( void )  /* 以广度优先的算法枚举整个U盘中的所有文件及目录 */
{
	UINT8	s;
	UINT16	OldFileCount;
	UINT16	RealReadCount;
	FileNameBuffer[ 0 ].Name[0] = '/';  /* 根目录,是完整路径名,除根目录是绝对路径之外都是相对路径 */
	FileNameBuffer[ 0 ].Name[1] = 0;
	FileNameBuffer[ 0 ].DirStartClust = 0;  /* 根目录的起始簇号 */
	FileNameBuffer[ 0 ].Attr = ATTR_DIRECTORY;  /* 根目录也是目录,作为第一个记录保存 */
	for ( OldFileCount = 0, FileCount = 1; OldFileCount < FileCount; OldFileCount ++ ) {  /* 尚有新枚举到的文件名结构未进行分析,FileCount处于变化之中 */
		if ( FileNameBuffer[ OldFileCount ].Attr & ATTR_DIRECTORY ) {  /* 是目录则继续进行深度搜索 */
			s = ListFile( OldFileCount );  /* 枚举目录,记录保存到结构中,FileCount可能会改变 */
			if ( s != USB_INT_SUCCESS ) return( s );
		}
	}

上面的代码中包含了两个函数, ListFile( UINT8 index ) 和    ListAll( void )   

 ListFile( UINT8 index ) 函数是搜索目标U盘内所有文件名及目录,而ListAll( void ) 是把所有搜索到的文件名列举出来,保存到一个结构体数组里面。这样的话,我们就可以在定义的数组里面看到目标U盘内所有的文件名了,stm32 debug调试的时候可以查看结构体数组里面存着的U盘内所有的文件名。

       然后我们回到一开始的解决每次都需要更改文件名的问题。解决方法就是我们只定死文件名的前几个字母(文件名不能用中文),然后在需要修改文件名的时候只修改后面几个就行,在需要读取目标文件内的数据时,程序可以写成把前几个字母和U盘内所有的文件名作比较,只要符合条件的文件名就可以读里面的数据。

       比如:程序中只比较 QWE 这三个字母,而U盘中的文件名是 QWERTY。前三个字母符合的话就可以读取 QWERTY 这个文件内的数据了。但是这样做也有一个缺点,就是U盘内不止有 QWERTY 这个文件,还有QWERTYU 这个文件,那这样的话该怎么办。是不是就没法读数据了。实际情况是, ListAll( void )函数把所有的文件是按一定顺序保存到一个数组里面的。那么系统在和文件名作比较时,只要搜索到符合条件的文件名就终止搜索了,直接读取符合条件的文件。但是你怎么确保你会把想让它读的文件排在前面呢。估计还有人会说我只在U盘内放入一个符合条件的文件不就行了吗,这样做也不是不可以,但你需要每次都把不需要的文件删掉再添加新的文件,这样不是很方便,而且万一哪次你忘记删掉呢。那么怎么解决这个问题呢。

       为了解决这个问题,我只能加入编号了,还是举例说明:可以这样定义文件名,QWE001,这样的话我只需要在符合前面三个字母的前提下再比较编号的大小就可以解决了(估计还会有人说干脆直接把文件名定成一串数字不就行了,这样有什么坏处你自己想想),所以你只需要把每次新的文件编号加1就可以放心的放到U盘内取读了。

     以上是我自己在实践中总结的东西,可能会有一些地方有出入的,还是希望读者指出有不足的地方,我们共同进步!!!!!!感谢!!!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要实现STM32与CH376S芯片进行U盘在线升级,需要以下步骤: 1. 硬件连接:将STM32的GPIO引脚与CH376S芯片的相应引脚连接,确保正常的通信和数据交换。 2. 初始化:在STM32中进行CH376S芯片的初始化配置,包括设置通信接口、传输模式等参数。 3. 打开设备:使用CH376S提供的命令来打开U盘设备。通过命令传输将CH376S的命令发送给芯片芯片通过USB接口与U盘进行通信。通过命令返回值判断是否成功打开U盘设备。 4. 读取文件:使用CH376S提供的命令来读取U盘中的升级文件。通过命令传输将读取文件的命令发送给芯片芯片通过USB接口与U盘进行通信,并将读取到的文件数据传输到STM32。 5. 处理文件数据:在STM32中接收到文件数据后,可以进行校验、解析等操作,确保文件数据的完整性和正确性。 6. 更新固件:将解析后的文件数据通过编程方式写入STM32的存储器中,完成固件的升级。 7. 关闭设备:在升级完成后,使用CH376S提供的命令来关闭U盘设备。 总结:通过硬件连接,初始化芯片,打开设备,读取文件,处理数据和更新固件等步骤,就可以实现STM32与CH376S芯片U盘在线升级。注意在整个过程中,要处理好通信和数据传输的问题,以确保升级过程的稳定和可靠性。 ### 回答2: STM32实现CH376S的U盘在线升级需要以下步骤: 1. 准备硬件:首先,需要准备STM32单片机和CH376S USB转串口模块。将CH376S模块通过串口连接到STM32的串口通信引脚。 2. 初始化串口:在STM32的代码中,需要初始化串口以便与CH376S进行通信。设置串口的波特率、数据位、停止位等参数。 3. 初始化CH376S模块:通过STM32向CH376S发送初始化命令,配置CH376S模块的工作模式为USB主机模式。可以使用SPI或者I2C协议与CH376S进行通信。 4. 检测U盘CH376S模块会自动检测USB设备的连接状态。在STM32的代码中,需要定期查询CH376S的状态寄存器以检测是否检测到U盘的连接。 5. 挂载U盘:当检测到U盘连接后,需要通过STM32发送命令给CH376S,挂载U盘。挂载成功后,CH376S会模拟出一个USB存储设备,就像是一个真实的U盘。 6. 读取固件文件:在U盘挂载成功后,可以使用STM32的文件系统库访问U盘上的固件文件。通过读取固件文件可以获取升级所需的固件数据。 7. 备份原始固件:在进行升级之前,为了避免升级失败对系统造成的影响,可以先备份原始固件。将原始固件拷贝到STM32的存储器中或者在U盘上创建一个备份文件。 8. 执行升级:将升级所需的固件数据写入到U盘模拟的USB存储设备中,通过STM32将固件数据发送给CH376S模块,然后CH376S将数据写入U盘。 9. 升级完成:完成固件写入后,可以通过STM32向CH376S发送升级完成的命令,CH376S模块会断开U盘的连接。此时,可以验证固件升级的效果。 需要注意的是,具体实现的细节会根据具体的STM32型号、CH376S模块以及使用的开发环境而有所不同。因此,在实际操作中,需要参考STM32和CH376S的相关文档以及示例代码来进行相应的开发。 ### 回答3: STM32实现CH376S的U盘在线升级的过程大致如下: 1. 硬件连接:首先,将STM32的串口和CH376S的串口相连,使得两者能够进行通信。此外,还需要将CH376S的SPI接口和STM32的SPI接口相连,以实现数据的传输。 2. 引入CH376S库:在STM32的开发环境中,引入CH376S的相关库文件,以便在代码中调用相关的API函数。 3. 初始化CH376S:在开发代码中,首先需要对CH376S进行初始化,包括复位操作和初始化寄存器等。 4. U盘识别:使用CH376S的相关功能函数,检测并识别连接的U盘设备。CH376S提供了读取U盘设备信息、读取文件列表等功能,可以通过这些操作来进一步确认U盘设备的连接情况。 5. 读取升级文件:在U盘中,存放有待升级的固件文件。通过CH376S提供的文件读取接口,从U盘中读取到固件文件的内容,并保存在STM32的内存中。 6. STM32固件升级:当固件文件读取完成后,将固件文件的内容通过串口发送给STM32。STM32接收到固件文件后,进行解析和处理,完成固件的更新操作。 7. 固件更新确认:更新完成后,可以通过CH376S进行U盘设备的重新识别,确认固件更新是否成功。如果更新成功,可返回相应的状态值,通知用户升级已完成。 总结起来,使用STM32实现CH376S的U盘在线升级的过程,主要包括硬件连接、引入CH376S库、初始化CH376S、U盘识别、读取升级文件、STM32固件升级以及固件更新确认等步骤。通过这个过程,可以实现方便快捷的U盘在线升级操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值