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

📄 main.c

📁 基于CH376的U盘读写例子
💻 C
字号:
/****************************************************************************
* Copyright (C), 2010 安富莱电子 www.armfly.com
*
* 【本例程在安富莱STM32F103ZE-EK开发板上调试通过             】
* 【QQ: 1295744630, 旺旺:armfly, Email: armfly@qq.com       】
*
* 文件名: main.c
* 内容简述: 本例程演示如何通过CH376读写U盘。
*
*
* 文件历史:
* 版本号  日期       作者    说明
* v0.1    2010-10-30 armfly  创建该文件
*
*/

#include "stm32f10x.h"
#include <stdio.h>
#include "usart_printf.h"
#include "systick.h"
#include "button.h"
#include "FILE_SYS.H"
#include "string.h"

#define EXAMPLE_NAME	"CH376 USB DISK Demo"
#define EXAMPLE_DATE	"2010-10-30"

static void InitBoard(void);
static void DispLogo(void);
void TestCH376(void);

/*******************************************************************************
*	函数名:main
*	输  入:
*	输  出:
*	功能说明:用户程序入口
*/
int main(void)
{
	InitBoard();	/* 为了是main函数看起来更简洁些,我们将初始化的代码封装到这个函数 */
	DispLogo();		/* 显示例程Logo */

	mDelaymS(200);
	TestCH376();
}

/*******************************************************************************
*	函数名:mStopIfError
*	输  入:	iError, 错误代码
*	输  出:
*	功能说明:检查操作状态,如果错误则显示错误代码并停机,
*	应该替换为实际的处理措施,例如显示错误信息,等待用户确认后重试等
*/
void mStopIfError(uint8_t iError)
{
	if (iError == USB_INT_SUCCESS)
	{
		return;  /* 操作成功 */
	}
	printf("Error: %02X\n", iError );  /* 显示错误 */
	while(1)
	{
		/* LED闪烁 */
		GPIO_ResetBits(GPIOF,  GPIO_Pin_6);
		mDelaymS( 200 );
		GPIO_SetBits(GPIOF,  GPIO_Pin_6);
		mDelaymS( 200 );
	}
}

void TestCH376(void)
{
	uint8_t			i, s;
	P_FAT_DIR_INFO	pDir;
	char	SrcName[64];
	char	TarName[64];
	char	buf[64];

	printf( "Start\n\r" );

	s = mInitCH376Host( );  /* 初始化CH376 */
	mStopIfError( s );

	while(1) 
	{
		printf( "Wait Udisk\n\r" );
		while (CH376DiskConnect() != USB_INT_SUCCESS)
		{  /* 检查U盘是否连接,等待U盘插入,对于SD卡,可以由单片机直接查询SD卡座的插拔状态引脚 */
			mDelaymS(100 );
		}
		mDelaymS(250);  /* 延时,可选操作,有的USB存储器需要几十毫秒的延时 */
		mDelaymS(250); 

		/* 对于检测到USB设备的,最多等待100*50mS,主要针对有些MP3太慢,对于检测到USB设备并且连接DISK_MOUNTED的,最多等待5*50mS,主要针对DiskReady不过的 */
		for (i = 0; i < 100; i ++ )
		{  /* 最长等待时间,100*50mS */
			mDelaymS(50);
			printf( "Ready ?\n\r" );
			s = CH376DiskMount();  /* 初始化磁盘并测试磁盘是否就绪 */
			if (s == USB_INT_SUCCESS)
			{
				break;  /* 准备好 */
			}
			else if (s == ERR_DISK_DISCON)
			{
				break;  /* 检测到断开,重新检测并计时 */
			}
			if (CH376GetDiskStatus() >= DEF_DISK_MOUNTED && i >= 5)
			{
				break;  /* 有的U盘总是返回未准备好,不过可以忽略,只要其建立连接MOUNTED且尝试5*50mS */
			}
		}
		if (s == ERR_DISK_DISCON)
		{  /* 检测到断开,重新检测并计时 */
			printf("Device gone\n\r");
			continue;
		}
		if (CH376GetDiskStatus( ) < DEF_DISK_MOUNTED)
		{  /* 未知USB设备,例如USB键盘、打印机等 */
			printf("Unknown device\n\r");
			goto UnknownUsbDevice;
		}
		i = CH376ReadBlock((uint8_t *)buf );  /* 如果需要,可以读取数据块CH376_CMD_DATA.DiskMountInq,返回长度 */
		if (i == sizeof( INQUIRY_DATA))
		{	/* U盘的厂商和产品信息 */
			buf[i] = 0;
			printf("UdiskInfo: %s\n\r", ((P_INQUIRY_DATA)buf) -> VendorIdStr);
		}

		/* 读取原文件 */
		strcpy(SrcName, "\\C51\\CH376HFT.C");  /* 源文件名,多级目录下的文件名和路径名必须复制到RAM中再处理,而根目录或者当前目录下的文件名可以在RAM或者ROM中 */
		strcpy(TarName, "\\NEWFILE.TXT" );  /* 目标文件名 */
		printf("Open\n\r");
		mDelaymS(80);
		s = CH376FileOpenPath((uint8_t *)SrcName );  /* 打开文件,该文件在C51子目录下 */
		if ((s != ERR_MISS_DIR) && (s != ERR_MISS_FILE))
		{  
			printf("Open Error! Retry\n\r");
			//mStopIfError(s);
			s = CH376FileOpenPath((uint8_t *)SrcName );
		}
		if (s == ERR_MISS_DIR || s == ERR_MISS_FILE)
		{	/* 没有找到目录或者没有找到文件 */
			/* 列出文件,完整枚举可以参考EXAM13全盘枚举 */
			if ( s == ERR_MISS_DIR )
			{
				strcpy( buf, "\\*" );  /* C51子目录不存在则列出根目录下的文件 */
			}
			else 
			{
				strcpy( buf, "\\C51\\CH376*" );  /* CH376HFT.C文件不存在则列出\C51子目录下的以CH376开头的文件 */
			}
			printf("List file %s\n\r", buf);
			s = CH376FileOpenPath((uint8_t *)buf);  /* 枚举多级目录下的文件或者目录,输入缓冲区必须在RAM中 */
			while (s == USB_INT_DISK_READ)
			{	/* 枚举到匹配的文件 */
				CH376ReadBlock((uint8_t *)buf);  /* 读取枚举到的文件的FAT_DIR_INFO结构,返回长度总是sizeof( FAT_DIR_INFO ) */
				pDir = (P_FAT_DIR_INFO)buf;  /* 当前文件目录信息 */
				if (pDir -> DIR_Name[0] != '.')
				{  /* 不是本级或者上级目录名则继续,否则必须丢弃不处理 */
					if ( pDir -> DIR_Name[0] == 0x05 )
					{
						pDir -> DIR_Name[0] = 0xE5;  /* 特殊字符替换 */
					}
					pDir -> DIR_Attr = 0;  /* 强制文件名字符串结束以便打印输出 */
					printf( "*** EnumName: %s\n\r", pDir -> DIR_Name );  /* 打印名称,原始8+3格式,未整理成含小数点分隔符 */
				}
				xWriteCH376Cmd( CMD0H_FILE_ENUM_GO );  /* 继续枚举文件和目录 */
				xEndCH376Cmd( );
				s = Wait376Interrupt( );
			}
			if (s != ERR_MISS_FILE )
			{
				mStopIfError( s );  /* 操作出错 */
			}

			mDelaymS(80);

			printf( "Create\n\r" );
			s = CH376FileCreatePath((uint8_t *)TarName );  /* 新建多级目录下的文件,支持多级目录路径,输入缓冲区必须在RAM中 */
			mStopIfError( s );

			printf( "Write\n\r" );
			strcpy( buf, "找不到/C51/CH376HFT.C文件\xd\n\r" );
			s = CH376ByteWrite((uint8_t *)buf, strlen(buf), NULL );  /* 以字节为单位向当前位置写入数据块 */
			mStopIfError( s );

			printf( "Close\n\r" );
			s = CH376FileClose( TRUE );  /* 关闭文件,对于字节读写建议自动更新文件长度 */
			mStopIfError( s );
		}


/* 删除某文件 */
/*		printf( "Erase\n" );
		s = CH376FileErase( "/OLD" );  删除文件
		if ( s != USB_INT_SUCCESS ) printf( "Error: %02X\n", (UINT16)s );  显示错误
*/

/* 检查U盘或者SD卡的剩余空间 */
/*		printf( "DiskQuery: " );
		s = CH376DiskQuery( (PUINT32)buf );  查询磁盘剩余空间信息,扇区数
		mStopIfError( s );
//		printf( "free cap = %ld MB\n", *(PUINT32)buf * DEF_SECTOR_SIZE / 1000000 );  未用扇区数乘以扇区大小后,除以1M换算为兆字节单位
		printf( "free cap = %ld MB\n", *(PUINT32)buf / ( 1000000 / DEF_SECTOR_SIZE ) );  上面一行的计算可能会溢出,换个顺序计算 */

UnknownUsbDevice:
		printf( "Take out\n\r" );
		while ( CH376DiskConnect( ) == USB_INT_SUCCESS ) {  /* 检查U盘是否连接,等待U盘拔出 */
			mDelaymS( 100 );
		}
		mDelaymS(200 );
	}
}

/*******************************************************************************
	函数名:GPIO_Configuration
	输  入:
	输  出:
	功能说明:配置4个LED为输出口线

	LED口线分配:
	LED1 : PF6  (输出0点亮)
	LED2 : PF7  (输出0点亮)
	LED3 : PF8  (输出0点亮)
	LED4 : PF9  (输出0点亮)

*/
void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* 第1步:打开GPIOA GPIOC GPIOD GPIOF GPIOG的时钟
	   注意:这个地方可以一次性全打开
	*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC
			| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG,
				ENABLE);

	/* 第2步:配置所有的按键GPIO为浮动输入模式(实际上CPUf复位后就是输入状态) */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	/* PA0 */

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_Init(GPIOC, &GPIO_InitStructure);	/* PC13 */

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_Init(GPIOD, &GPIO_InitStructure);	/* PD3 */

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_13
					  | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_Init(GPIOG, &GPIO_InitStructure);	/* PG7,8,13,14,15 */

	/* 第3步:配置所有的LED指示灯GPIO为推挽输出模式 */
	/* 由于将GPIO设置为输出时,GPIO输出寄存器的值缺省是0,因此会驱动LED点亮
		这是我不希望的,因此在改变GPIO为输出前,先修改输出寄存器的值为1 */
	GPIO_SetBits(GPIOF,  GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOF, &GPIO_InitStructure);
}

/*******************************************************************************
	函数名:InitBoard
	输  入:
	输  出:
	功能说明:初始化硬件设备
*/
static void InitBoard(void)
{
	/*
		这个函数是ST库中的函数,函数实体在
		Libraries\CMSIS\Core\CM3\system_stm32f10x.c

		配置内部Flash接口,初始化PLL,配置系统频率
		系统时钟缺省配置为72MHz,你如果需要更改,则需要去修改相关的头文件中的宏定义
	 */
	SystemInit();

	/* 配置按键GPIO和LED GPIO */
	GPIO_Configuration();

	/* 配置串口 */
	USART_Configuration();

	/* 在 SysTick_Config()前,必须先调用 */
	InitButtonVar();

	/* 配置systic作为1ms中断,这个函数在
	\Libraries\CMSIS\Core\CM3\core_cm3.c */
	SysTick_Config(SystemFrequency / 1000);
}

/*******************************************************************************
	函数名: DispLogo
	输  入:
	输  出:
	功能说明:显示例程Logo (通过串口打印到PC机的超级终端显示)
*/
static void DispLogo(void)
{
	/* 通过串口输出例程名和更新日期 */
	PrintfLogo(EXAMPLE_NAME, EXAMPLE_DATE);
}

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
  * @}
  */

/**
  * @}
  */

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/

⌨️ 快捷键说明

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