📄 main.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 + -