本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:周文杰
SPI通信作为单片机多种基础数据传输模式中的一种,驱动外部芯片CH376实现数据导出到U盘功能在实际工程项目中是很方便的。本文提供了GD32F427驱动CH376实现数据从U盘导出的完整硬件原理图和软件程序。
硬件连接方面
软件程序方面
SPI0的GPIO引脚初始化
void gpio_config(void)
{
/* configure SPI0 GPIO */
gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
/* set SPI1_NSS as GPIO*/
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
gpio_init(GPIOB, GPIO_MODE_IPU , GPIO_OSPEED_50MHZ, GPIO_PIN_0);//PB0配置成上拉输入
}
SPI0的配置初始化
void spi_config(void)
{
spi_parameter_struct spi_init_struct;
/* configure SPI1 parameter */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_32;
spi_init_struct.endian = SPI_ENDIAN_MSB;;
spi_init(SPI0, &spi_init_struct);
}
SPI0的数据发送函数
uint8_t spi0_send_byte(uint8_t spi_byte)
{
uint8_t ByteSend,ByteRecv;
ByteSend=spi_byte;
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
spi_i2s_data_transmit(SPI0,ByteSend);
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
ByteRecv=spi_i2s_data_receive(SPI0);
return ByteRecv;
}
CH376芯片的驱动程序文件为bsp_ch376.c何bsp_ch376.h。便于工程移植使用。
bsp_ch376.c
#ifndef BSP_CH376_H
#define BSP_CH376_H
#include "bsp_ch376.h"
#include "gd32f30x_rcu.h"
#include "gd32f30x_gpio.h"
#include "systick.h"
#include "gd32f30x.h"
#include "uart3dma.h"//调试用
#include "bsp_spi.h"
#define FLASH_CS_0() {gpio_bit_write(GPIOA, GPIO_PIN_4,RESET);delay_1ms(10);}
#define FLASH_CS_1() {gpio_bit_write(GPIOA, GPIO_PIN_4,SET);delay_1ms(10);}
#define CH376_INTPORT GPIOB //定义IO接口
#define CH376_INT GPIO_PIN_0 //定义IO接口【此处是预留引脚,程序中未使用】
uint8_t retval = 0; //返回值
uint32_t u32retcount = 0; //写入字节数
uint32_t u32count = 0; //循环变量
char retString[120]="";
char buf[512]="";
void xWriteCH376Cmd(uint8_t mCmd){
FLASH_CS_1(); /* 防止之前未通过xEndCH376Cmd禁止SPI片选 */
delay_1us(20);
/* 对于双向I/O引脚模拟SPI接口,那么必须确保已经设置SPI_SCS,SPI_SCK,SPI_SDI为输出
* 方向,SPI_SDO为输入方向 */
FLASH_CS_0(); /* SPI片选有效 */
spi0_send_byte( mCmd ); /* 发出命令码 */
delay_1us(1800); /* 延时1.5mS确保读写周期大于1.5mS,或者用上面一行的状态查询代替 */
}
void xWriteCH376Data(uint8_t mData){
spi0_send_byte( mData );
delay_1us(700); /* 确保读写周期大于0.6mS */
}
uint8_t xReadCH376Data(void){
uint8_t i;
delay_1us(20);
i = spi0_send_byte(0xFF);
return(i);
}
void xEndCH376Cmd(void){ //结束命令
FLASH_CS_1(); //SPI片选无效,结束CH376命令
}
/*******************************************************************************
* 描 述 : 查询CH376中断(INT#低电平).
* 返 回 : 0:无中断. 1:有中断.
******************************************************************************
uint8_t Query376Interrupt(void){
uint8_t i;
i = gpio_input_bit_get(CH376_INTPORT,CH376_INT);
return( i == 0);
}
*/
/*******************************************************************************
* 描 述 : 初始化CH376.
* 返 回 : FALSE:无中断. TRUE:有中断.
*******************************************************************************/
uint8_t mInitCH376Host(void){
uint8_t u8ret;
delay_1ms(600);
FLASH_CS_1();
xWriteCH376Cmd( CMD11_CHECK_EXIST ); /* 测试单片机与CH376之间的通讯接口 */
xWriteCH376Data( 0x55 );
u8ret = xReadCH376Data( );
// printf("res =%02x \n",(unsigned short)res);
xEndCH376Cmd( );
if ( u8ret != 0xAA ) return( ERR_USB_UNKNOWN ); /* 通讯接口不正常,可能原因有:接口连接异常,其它设备影响(片选不唯一),串口波特率,一直在复位,晶振不工作 */
xWriteCH376Cmd( CMD11_SET_USB_MODE ); /* 设备USB工作模式 */
xWriteCH376Data( 0x06 ); //06H=已启用的主机方式并且自动产生SOF包
delay_1ms(1);
u8ret = xReadCH376Data( );
// printf("res =%02x \n",(unsigned short)res);
xEndCH376Cmd( );
if ( u8ret == CMD_RET_SUCCESS ){ //RES=51 命令操作成功
UART3_Transmit_DMA(UART3,"#########################################################ok", 200);
return( USB_INT_SUCCESS ); //USB事务或者传输操作成功
}else{
UART3_Transmit_DMA(UART3,"not ok", 20);
return( ERR_USB_UNKNOWN );/* 设置模式错误 */
}
}
/*******************************************************************************
* 描 述 : 查询CH376中断(INT#低电平).
* 返 回 : 0:无中断. 1:有中断.
*******************************************************************************/
uint8_t Query376Interrupt(void){
uint8_t i;
char strings[200]="";
i = gpio_input_bit_get(CH376_INTPORT, GPIO_PIN_0);
//i=~i;
//sprintf(strings, "%x\n", i);
//UART3_Transmit_DMA(UART3,(uint8_t *)strings, 10);
return ( i == 0x00 );
}
/*******************************************************************************
* 函 数 名 : CH376GetIntStatus
* 描 述 : 获取中断状态并取消中断请求.
* 输 入 : 无.
* 返 回 : UINT8 s:
* 中断状态.
*******************************************************************************/
uint8_t CH376GetIntStatus( void )
{
uint8_t s;
xWriteCH376Cmd( CMD01_GET_STATUS );
s = xReadCH376Data( );
xEndCH376Cmd( );
return( s );
}
uint8_t Wait376Interrupt( void )
{
/* 是否定义了超时时间 */
uint32_t i;
uint8_t ret=0;
for ( i = 0; i < 50000; i ++ ) /* 计数防止超时,默认的超时时间,与单片机主频有关 */
{
ret = Query376Interrupt() ;
if (ret)
{
return( CH376GetIntStatus()); /* 检测到中断 */
}
/* 在等待CH376中断的过程中,可以做些需要及时处理的其它事情 */
}
return( ERR_USB_UNKNOWN ); /* 不应该发生的情况 */
}
uint8_t CH376SendCmdWaitInt( uint8_t mCmd )
{
xWriteCH376Cmd( mCmd );
xEndCH376Cmd( );
return( Wait376Interrupt( ) );
}
/*******************************************************************************
* 函 数 名 : CH376SendCmdDatWaitInt
* 描 述 : 发出命令码和一字节数据后,等待中断.
* 输 入 : 无.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376SendCmdDatWaitInt( uint8_t mCmd, uint8_t mDat )
{
xWriteCH376Cmd( mCmd );
xWriteCH376Data( mDat );
xEndCH376Cmd( );
return( Wait376Interrupt( ) );
}
/*******************************************************************************
* 函 数 名 : CH376ReadVar8
* 描 述 : 读CH376芯片内部的8位变量.
* 输 入 : 无.
* 返 回 : 8位变量.
*******************************************************************************/
uint8_t CH376ReadVar8( uint8_t var )
{
uint8_t c0;
xWriteCH376Cmd( CMD11_READ_VAR8 ); /* 读取指定的8位文件系统变量 */
xWriteCH376Data( var );
c0 = xReadCH376Data( );
xEndCH376Cmd( );
return( c0 );
}
#define VAR_DISK_STATUS 0x2B /* 主机文件模式下的磁盘及文件状态 */
/*******************************************************************************
* 函 数 名 : CH376GetDiskStatus
* 描 述 : 获取磁盘和文件系统的工作状态.
* 输 入 : 无.
* 返 回 : 状态.
*******************************************************************************/
uint8_t CH376GetDiskStatus( void )
{
return( CH376ReadVar8( VAR_DISK_STATUS ) );
}
/*******************************************************************************
* 函 数 名 : CH376FileClose
* 描 述 : 关闭当前已经打开的文件或者目录(文件夹)
* 输 入 : PUINT8 UpdateSz:
* 是否更新文件长度.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376FileClose( uint8_t UpdateSz )
{
return( CH376SendCmdDatWaitInt( CMD1H_FILE_CLOSE, UpdateSz ) );
}
/*******************************************************************************
* 函 数 名 : CH376DiskMount
* 描 述 : 初始化磁盘并测试磁盘是否就绪.
* 输 入 : 无.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376DiskMount( void )
{
return( CH376SendCmdWaitInt( 0x31 ) ); /* 初始化磁盘并测试磁盘是否就绪 */
}
/*******************************************************************************
* 函 数 名 : CH376WriteReqBlock
* 描 述 : 向内部指定缓冲区写入请求的数据块,返回长度.
* 输 入 : PUINT8 buf:
* 指向发送缓冲区.
* 返 回 : UINT8 s:后续数据长度.
*******************************************************************************/
uint8_t CH376WriteReqBlock( uint8_t * buf ){
uint8_t s, l;
xWriteCH376Cmd( CMD01_WR_REQ_DATA ); /* 向内部指定缓冲区写入请求的数据块 */
s = l = xReadCH376Data( ); /* 后续数据长度 */
if ( l )
{
do
{
xWriteCH376Data( *buf );
buf ++;
} while ( -- l );
}
xEndCH376Cmd( );
return( s );
}
/*******************************************************************************
* 函 数 名 : CH376ByteLocate
* 描 述 : 以字节为单位移动当前文件指针
* 输 入 : UINT32 offset:
* 指针偏移地址.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376ByteLocate( uint32_t offset )
{
xWriteCH376Cmd( CMD4H_BYTE_LOCATE );
xWriteCH376Data( (uint8_t)offset );
xWriteCH376Data( (uint8_t)((uint16_t)offset>>8) );
xWriteCH376Data( (uint8_t)(offset>>16) );
xWriteCH376Data( (uint8_t)(offset>>24) );
xEndCH376Cmd( );
return( Wait376Interrupt( ) );
}
/*******************************************************************************
* 函 数 名 : CH376ByteWrite
* 描 述 : 以字节为单位向当前位置写入数据块.
* 输 入 : PUINT8 buf:
* 指向外部缓冲区.
* UINT16 ReqCount:
* 请求写入的字节数.
* PUINT16 RealCount:
* 实际写入的字节数.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376ByteWrite( uint8_t * buf, uint16_t ReqCount, uint16_t * RealCount )
{
uint8_t s;
xWriteCH376Cmd( CMD2H_BYTE_WRITE );
xWriteCH376Data( (uint8_t)ReqCount );
xWriteCH376Data( (uint8_t)(ReqCount>>8) );
xEndCH376Cmd( );
if ( RealCount )
{
*RealCount = 0;
}
while ( 1 )
{
s = Wait376Interrupt( );
if ( s == USB_INT_DISK_WRITE )
{
s = CH376WriteReqBlock( buf ); /* 向内部指定缓冲区写入请求的数据块,返回长度 */
xWriteCH376Cmd( CMD0H_BYTE_WR_GO );
xEndCH376Cmd( );
buf += s;
if ( RealCount ) *RealCount += s;
}
else
{
return( s ); /* 错误 */
}
}
}
/*******************************************************************************
* 函 数 名 : CH376Read32bitDat
* 描 述 : 从CH376芯片读取32位的数据并结束命令.
* 输 入 : 无.
* 返 回 : 32位数据.
*******************************************************************************/
uint32_t CH376Read32bitDat( void )
{
uint8_t c0, c1, c2, c3;
c0 = xReadCH376Data( );
c1 = xReadCH376Data( );
c2 = xReadCH376Data( );
c3 = xReadCH376Data( );
xEndCH376Cmd( );
return( c0 | (uint16_t)c1 << 8 | (uint32_t)c2 << 16 | (uint32_t)c3 << 24 );
}
/*******************************************************************************
* 函 数 名 : CH376ReadVar8
* 描 述 : 读CH376芯片内部的32位变量.
* 输 入 : UINT8 var:
* 变量地址.
* 返 回 : 32位变量.
*******************************************************************************/
uint32_t CH376ReadVar32( uint8_t var )
{
xWriteCH376Cmd( CMD14_READ_VAR32 );
xWriteCH376Data( var );
return( CH376Read32bitDat( ) ); /* 从CH376芯片读取32位的数据并结束命令 */
}
/*******************************************************************************
* 函 数 名 : CH376WriteVar32
* 描 述 : 写CH376芯片内部的32位变量.
* 输 入 : UINT8 var:
* 变量地址.
* UINT32 dat:
* 数据.
* 返 回 : 无.
*******************************************************************************/
void CH376WriteVar32( uint8_t var, uint32_t dat )
{
xWriteCH376Cmd( CMD50_WRITE_VAR32 );
xWriteCH376Data( var );
xWriteCH376Data( (uint8_t)dat );
xWriteCH376Data( (uint8_t)( (uint16_t)dat >> 8 ) );
xWriteCH376Data( (uint8_t)( dat >> 16 ) );
xWriteCH376Data( (uint8_t)( dat >> 24 ) );
xEndCH376Cmd( );
}
/*******************************************************************************
* 函 数 名 : CH376SetFileName
* 描 述 : 设置将要操作的文件的文件名 .
* 输 入 : PUINT8 name:
* 指向文件名缓冲区.
* 返 回 : 无.
*******************************************************************************/
void CH376SetFileName( uint8_t * name )
{
uint8_t c;
#ifndef DEF_IC_V43_U /* 默认支持低版本 */
uint8_t s;
xWriteCH376Cmd( CMD01_GET_IC_VER ); /* 获取芯片版本 */
if ( xReadCH376Data( ) < 0x43 )
{
if ( CH376ReadVar8( VAR_DISK_STATUS ) < DEF_DISK_READY )
{
xWriteCH376Cmd( CMD10_SET_FILE_NAME );
xWriteCH376Data( 0 );
s = CH376SendCmdWaitInt( CMD0H_FILE_OPEN );
if ( s == USB_INT_SUCCESS )
{
s = CH376ReadVar8( 0xCF );
if ( s )
{
CH376WriteVar32( 0x4C, CH376ReadVar32( 0x4C ) + ( (uint16_t)s << 8 ) );
CH376WriteVar32( 0x50, CH376ReadVar32( 0x50 ) + ( (uint16_t)s << 8 ) );
CH376WriteVar32( 0x70, 0 );
}
}
}
}
#endif
xWriteCH376Cmd( CMD10_SET_FILE_NAME );
c = *name;
xWriteCH376Data( c );
while ( c )
{
name ++;
c = *name;
if ( c == DEF_SEPAR_CHAR1 || c == DEF_SEPAR_CHAR2 )
{
c = 0; /* 强行将文件名截止 */
}
xWriteCH376Data( c );
}
xEndCH376Cmd( );
}
/*******************************************************************************
* 函 数 名 : CH376FileOpen
* 描 述 : 在根目录或者当前目录下打开文件或者目录(文件夹).
* 输 入 : 无.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376FileOpen( uint8_t * name )
{
CH376SetFileName( name ); /* 设置将要操作的文件的文件名 */
#ifndef DEF_IC_V43_U
if ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 )
{
CH376WriteVar32( VAR_CURRENT_CLUST, 0 );
}
#endif
return( CH376SendCmdWaitInt( CMD0H_FILE_OPEN ) );
}
/*******************************************************************************
* 函 数 名 : CH376FileCreate
* 描 述 : 在根目录或者当前目录下新建文件,如果文件已经存在那么先删除.
* 输 入 : 无.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376FileCreate( uint8_t * name )
{
if ( name )
{
CH376SetFileName( name ); /* 设置将要操作的文件的文件名 */
}
return( CH376SendCmdWaitInt( CMD0H_FILE_CREATE ) );
}
/*******************************************************************************
* 函 数 名 : CH376DirCreate
* 描 述 : 在根目录下新建目录(文件夹)并打开,如果目录已经存在那么直接打开.
* 输 入 : 无.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376DirCreate( uint8_t * name )
{
CH376SetFileName( name ); /* 设置将要操作的文件的文件名 */
#ifndef DEF_IC_V43_U
if ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 )
{
CH376WriteVar32( VAR_CURRENT_CLUST, 0 );
}
#endif
return( CH376SendCmdWaitInt( CMD0H_DIR_CREATE ) );
}
/*******************************************************************************
* 函 数 名 : CH376SeparatePath
* 描 述 : 从路径中分离出最后一级文件名或者目录(文件夹)名
* 输 入 : PUINT8 path:
* 指向路径缓冲区.
* 返 回 : 返回最后一级文件名或者目录名的字节偏移.
*******************************************************************************/
uint8_t CH376SeparatePath( uint8_t * path )
{
uint8_t * 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 );
}
/*******************************************************************************
* 函 数 名 : CH376FileOpenDir
* 描 述 : 打开多级目录下的文件或者目录的上级目录,支持多级目录路径,
* 支持路径分隔符,路径长度不超过255个字符
* 输 入 : PUINT8 path:
* 指向路径缓冲区.
* UINT8 StopName:
* 指向最后一级文件名或者目录名
* 返 回 : 返回最后一级文件名或者目录名的字节偏移.
*******************************************************************************/
uint8_t CH376FileOpenDir( uint8_t * PathName, uint8_t StopName )
{
uint8_t 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为成功打开目录(文件夹),其它为操作出错 */
}
}
}
/*******************************************************************************
* 函 数 名 : CH376FileOpenPath
* 描 述 : 打开多级目录下的文件或者目录(文件夹),支持多级目录路径,
* 支持路径分隔符,路径长度不超过255个字符
* 输 入 : PUINT8 path:
* 指向路径缓冲区.
* 返 回 : 返回最后一级文件名或者目录名的字节偏移.
*******************************************************************************/
uint8_t CH376FileOpenPath( uint8_t * PathName )
{
return( CH376FileOpenDir( PathName, 0xFF ) );
}
/*******************************************************************************
* 函 数 名 : CH376FileCreatePath
* 描 述 : 新建多级目录下的目录(文件夹)并打开,支持多级目录路径,支持路
* 径分隔符,路径长度不超过255个字符.
* 输 入 : PUINT8 path:
* 指向路径缓冲区.
* 返 回 : 中断状态.
*******************************************************************************/
uint8_t CH376FileCreatePath( uint8_t * PathName )
{
uint8_t s;
uint8_t Name;
Name = CH376SeparatePath( PathName ); /* 从路径中分离出最后一级文件名,返回最后一级文件名的偏移 */
if ( Name ) /* 是多级目录 */
{
s = CH376FileOpenDir( PathName, Name ); /* 打开多级目录下的最后一级目录,即打开新建文件的上级目录 */
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 ); /* 操作出错 */
}
}
}
return( CH376FileCreate( &PathName[Name] ) ); /* 在根目录或者当前目录下新建文件 */
}
/*******************************************************************************
* 函 数 名 : CH376DiskConnect
* 描 述 : 检查U盘是否连接,不支持SD卡.
* 输 入 : 无.
* 返 回 : U盘是否连接状态.
*******************************************************************************/
uint8_t CH376DiskConnect( void )
{
uint8_t ret = 0;
char strings[20]="";
if ( Query376Interrupt())
{
ret = CH376GetIntStatus();
}
return( CH376SendCmdWaitInt( CMD0H_DISK_CONNECT ) ); /* 检查磁盘是否连接 */
}
/*******************************************************************************
* 函 数 名 : CH376_INIT
* 描 述 : CH376初始化. U盘操作之前第一步
* 输 入 : 无.
* 返 回 : 0 代表U盘已经准备好
*******************************************************************************/
uint8_t CH376_INIT( void )
{
uint8_t retval = 0;
uint32_t u32count = 0;
retval = mInitCH376Host();
retval = CH376DiskConnect(); //读出U盘的状态
if(retval == USB_INT_SUCCESS){ //检查U盘是否连接//等待U盘插入
delay_1ms(1); //每次操作后必要的延时
}else{
delay_1ms(1); //每次操作后必要的延时
return -1;
}
for ( u32count = 0; u32count < 10000; u32count ++ ){
delay_1ms( 10 );
retval = CH376DiskMount( ); //初始化磁盘并测试磁盘是否就绪.
if ( retval == USB_INT_SUCCESS ) //准备好
{
return 0;
}else if ( retval == ERR_DISK_DISCON )// 检测到断开,重新检测并计时
{
break;
}
if ( CH376GetDiskStatus() >= DEF_DISK_MOUNTED && u32count >= 5 ) // 有的U盘总是返回未准备好,不过可以忽略,只要其建立连接MOUNTED且尝试5*50mS
{
//UART3_Transmit_DMA(UART3,(uint8_t *)"STATUSOK", 10);
break;
}
}
delay_1ms(1); //每次操作后必要的延时
}
/*******************************************************************************
* 函 数 名 : CH376_INIT
* 描 述 : CH376初始化. U盘操作之前第一步
* 输 入 : filename 类型 uint8_t *
* 返 回 : USB_INT_SUCCESS 代表U盘已经准备好
*******************************************************************************/
uint8_t CH376_OPEN( uint8_t * filename )
{
uint32_t u32retcount = 0;
u32retcount=CH376FileOpenPath( filename ); /* 打开已存在的文件 */
if(u32retcount==ERR_MISS_FILE ){
u32retcount=CH376FileCreatePath(filename ); /* 文件不存在则创建 */
}
u32retcount = CH376ByteLocate( 0xFFFFFFFF ); /* 移动文件指针 0xFFFFFFFF 到最后 */
if ( u32retcount != USB_INT_SUCCESS )
{
return( u32retcount );
}
}
#endif /* BSP_CH376_H */
bsp_ch376.h
#ifndef BSP_CH376_H
#define BSP_CH376_H
//#include "sys.h"
#include "gd32f30x.h"
#include "bsp_spi.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#ifndef NULL
#define NULL 0
#endif
//#define SPI2PORT GPIOB //
//#define SPI2_MOSI GPIO_PIN_15 //
//#define SPI2_MISO GPIO_PIN_14 //
//#define SPI2_SCK GPIO_PIN_13 //
//#define SPI2_NSS GPIO_PIN_12 //
#define CH376_INTPORT GPIOB //定义IO接口
#define CH376_INT GPIO_PIN_0 //定义IO接口【此处是预留引脚,程序中未使用】
/* 硬件特性 */
#define CH376_DAT_BLOCK_LEN 0x40 /* USB单个数据包, 数据块的最大长度, 默认缓冲区的长度 */
extern uint8_t retval ; //返回值
extern uint32_t u32retcount; //写入字节数
extern uint32_t u32count; //循环变量
extern char retString[120];
extern char buf[512];
/* ********************************************************************************************************************* */
/* 命令代码 */
/* 部分命令兼容CH375芯片, 但是输入数据或者输出数据的可能局部不同) */
/* 一个命令操作顺序包含:
一个命令码(对于串口方式,命令码之前还需要两个同步码),
若干个输入数据(可以是0个),
产生中断通知 或者 若干个输出数据(可以是0个), 二选一, 有中断通知则一定没有输出数据, 有输出数据则一定不产生中断
仅CMD01_WR_REQ_DATA命令例外, 顺序包含: 一个命令码, 一个输出数据, 若干个输入数据
命令码起名规则: CMDxy_NAME
其中的x和y都是数字, x说明最少输入数据个数(字节数), y说明最少输出数据个数(字节数), y如果是H则说明产生中断通知,
有些命令能够实现0到多个字节的数据块读写, 数据块本身的字节数未包含在上述x或y之内 */
/* 本文件默认会同时提供与CH375芯片命令码兼容的命令码格式(即去掉x和y之后), 如果不需要, 那么可以定义_NO_CH375_COMPATIBLE_禁止 */
/* ********************************************************************************************************************* */
/* 主要命令(手册一), 常用 */
#define CMD01_GET_IC_VER 0x01 /* 获取芯片及固件版本 */
/* 输出: 版本号( 位7为0, 位6为1, 位5~位0为版本号 ) */
/* CH376返回版本号的值为041H即版本号为01H */
#define CMD21_SET_BAUDRATE 0x02 /* 串口方式: 设置串口通讯波特率(上电或者复位后的默认波特率为9600bps,由D4/D5/D6引脚选择) */
/* 输入: 波特率分频系数, 波特率分频常数 */
/* 输出: 操作状态( CMD_RET_SUCCESS或CMD_RET_ABORT, 其它值说明操作未完成 ) */
#define CMD00_ENTER_SLEEP 0x03 /* 进入睡眠状态 */
#define CMD00_RESET_ALL 0x05 /* 执行硬件复位 */
#define CMD11_CHECK_EXIST 0x06 /* 测试通讯接口和工作状态 */
/* 输入: 任意数据 */
/* 输出: 输入数据的按位取反 */
#define CMD20_CHK_SUSPEND 0x0B /* 设备方式: 设置检查USB总线挂起状态的方式 */
/* 输入: 数据10H, 检查方式 */
/* 00H=不检查USB挂起, 04H=以50mS为间隔检查USB挂起, 05H=以10mS为间隔检查USB挂起 */
#define CMD20_SET_SDO_INT 0x0B /* SPI接口方式: 设置SPI的SDO引脚的中断方式 */
/* 输入: 数据16H, 中断方式 */
/* 10H=禁止SDO引脚用于中断输出,在SCS片选无效时三态输出禁止, 90H=SDO引脚在SCS片选无效时兼做中断请求输出 */
#define CMD14_GET_FILE_SIZE 0x0C /* 主机文件模式: 获取当前文件长度 */
/* 输入: 数据68H */
/* 输出: 当前文件长度(总长度32位,低字节在前) */
#define CMD50_SET_FILE_SIZE 0x0D /* 主机文件模式: 设置当前文件长度 */
/* 输入: 数据68H, 当前文件长度(总长度32位,低字节在前) */
#define CMD11_SET_USB_MODE 0x15 /* 设置USB工作模式 */
//00H=未启用的设备方式, 01H=已启用的设备方式并且使用外部固件模式(串口不支持),
//02H=已启用的设备方式并且使用内置固件模式 03H=SD卡主机模式/未启用的主机模式,用于管理和存取SD卡中的文件
//04H=未启用的主机方式, 05H=已启用的主机方式, 06H=已启用的主机方式并且自动产生SOF包, 07H=已启用的主机方式并且复位USB总线 */
//输出: 操作状态( CMD_RET_SUCCESS或CMD_RET_ABORT, 其它值说明操作未完成 )
#define CMD01_GET_STATUS 0x22 /* 获取中断状态并取消中断请求 */
/* 输出: 中断状态 */
#define CMD00_UNLOCK_USB 0x23 /* 设备方式: 释放当前USB缓冲区 */
#define CMD01_RD_USB_DATA0 0x27 /* 从当前USB中断的端点缓冲区或者主机端点的接收缓冲区读取数据块 */
/* 输出: 长度, 数据流 */
#define CMD01_RD_USB_DATA 0x28 /* 设备方式: 从当前USB中断的端点缓冲区读取数据块, 并释放缓冲区, 相当于 CMD01_RD_USB_DATA0 + CMD00_UNLOCK_USB */
/* 输出: 长度, 数据流 */
#define CMD10_WR_USB_DATA7 0x2B /* 设备方式: 向USB端点2的发送缓冲区写入数据块 */
/* 输入: 长度, 数据流 */
#define CMD10_WR_HOST_DATA 0x2C /* 向USB主机端点的发送缓冲区写入数据块 */
/* 输入: 长度, 数据流 */
#define CMD01_WR_REQ_DATA 0x2D /* 向内部指定缓冲区写入请求的数据块 */
/* 输出: 长度 */
/* 输入: 数据流 */
#define CMD20_WR_OFS_DATA 0x2E /* 向内部缓冲区指定偏移地址写入数据块 */
/* 输入: 偏移, 长度, 数据流 */
#define CMD10_SET_FILE_NAME 0x2F /* 主机文件模式: 设置将要操作的文件的文件名 */
/* 输入: 以0结束的字符串(含结束符0在内长度不超过14个字符) */
/* ********************************************************************************************************************* */
/* 主要命令(手册一), 常用, 以下命令总是在操作结束时产生中断通知, 并且总是没有输出数据 */
#define CMD0H_DISK_CONNECT 0x30 /* 主机文件模式/不支持SD卡: 检查磁盘是否连接 */
/* 输出中断 */
#define CMD0H_DISK_MOUNT 0x31 /* 主机文件模式: 初始化磁盘并测试磁盘是否就绪 */
/* 输出中断 */
#define CMD0H_FILE_OPEN 0x32 /* 主机文件模式: 打开文件或者目录(文件夹),或者枚举文件和目录(文件夹) */
/* 输出中断 */
#define CMD0H_FILE_ENUM_GO 0x33 /* 主机文件模式: 继续枚举文件和目录(文件夹) */
/* 输出中断 */
#define CMD0H_FILE_CREATE 0x34 /* 主机文件模式: 新建文件,如果文件已经存在那么先删除 */
/* 输出中断 */
#define CMD0H_FILE_ERASE 0x35 /* 主机文件模式: 删除文件,如果已经打开则直接删除,否则对于文件会先打开再删除,子目录必须先打开 */
/* 输出中断 */
#define CMD1H_FILE_CLOSE 0x36 /* 主机文件模式: 关闭当前已经打开的文件或者目录(文件夹) */
/* 输入: 是否允许更新文件长度 */
/* 00H=禁止更新长度, 01H=允许更新长度 */
/* 输出中断 */
#define CMD1H_DIR_INFO_READ 0x37 /* 主机文件模式: 读取文件的目录信息 */
/* 输入: 指定需要读取的目录信息结构在扇区内的索引号 */
/* 索引号范围为00H~0FH, 索引号0FFH则为当前已经打开的文件 */
/* 输出中断 */
#define CMD0H_DIR_INFO_SAVE 0x38 /* 主机文件模式: 保存文件的目录信息 */
/* 输出中断 */
#define CMD4H_BYTE_LOCATE 0x39 /* 主机文件模式: 以字节为单位移动当前文件指针 */
/* 输入: 偏移字节数(总长度32位,低字节在前) */
/* 输出中断 */
#define CMD2H_BYTE_READ 0x3A /* 主机文件模式: 以字节为单位从当前位置读取数据块 */
/* 输入: 请求读取的字节数(总长度16位,低字节在前) */
/* 输出中断 */
#define CMD0H_BYTE_RD_GO 0x3B /* 主机文件模式: 继续字节读 */
/* 输出中断 */
#define CMD2H_BYTE_WRITE 0x3C /* 主机文件模式: 以字节为单位向当前位置写入数据块 */
/* 输入: 请求写入的字节数(总长度16位,低字节在前) */
/* 输出中断 */
#define CMD0H_BYTE_WR_GO 0x3D /* 主机文件模式: 继续字节写 */
/* 输出中断 */
#define CMD0H_DISK_CAPACITY 0x3E /* 主机文件模式: 查询磁盘物理容量 */
/* 输出中断 */
#define CMD0H_DISK_QUERY 0x3F /* 主机文件模式: 查询磁盘空间信息 */
/* 输出中断 */
#define CMD0H_DIR_CREATE 0x40 /* 主机文件模式: 新建目录(文件夹)并打开,如果目录已经存在那么直接打开 */
/* 输出中断 */
#define CMD4H_SEC_LOCATE 0x4A /* 主机文件模式: 以扇区为单位移动当前文件指针 */
/* 输入: 偏移扇区数(总长度32位,低字节在前) */
/* 输出中断 */
#define CMD1H_SEC_READ 0x4B /* 主机文件模式/不支持SD卡: 以扇区为单位从当前位置读取数据块 */
/* 输入: 请求读取的扇区数 */
/* 输出中断 */
#define CMD1H_SEC_WRITE 0x4C /* 主机文件模式/不支持SD卡: 以扇区为单位在当前位置写入数据块 */
/* 输入: 请求写入的扇区数 */
/* 输出中断 */
#define CMD0H_DISK_BOC_CMD 0x50 /* 主机方式/不支持SD卡: 对USB存储器执行BulkOnly传输协议的命令 */
/* 输出中断 */
#define CMD5H_DISK_READ 0x54 /* 主机方式/不支持SD卡: 从USB存储器读物理扇区 */
/* 输入: LBA物理扇区地址(总长度32位, 低字节在前), 扇区数(01H~FFH) */
/* 输出中断 */
#define CMD0H_DISK_RD_GO 0x55 /* 主机方式/不支持SD卡: 继续执行USB存储器的物理扇区读操作 */
/* 输出中断 */
#define CMD5H_DISK_WRITE 0x56 /* 主机方式/不支持SD卡: 向USB存储器写物理扇区 */
/* 输入: LBA物理扇区地址(总长度32位, 低字节在前), 扇区数(01H~FFH) */
/* 输出中断 */
#define CMD0H_DISK_WR_GO 0x57 /* 主机方式/不支持SD卡: 继续执行USB存储器的物理扇区写操作 */
/* 输出中断 */
/* ********************************************************************************************************************* */
/* 辅助命令(手册二), 不太常用或者是为了与CH375和CH372兼容 */
#define CMD10_SET_USB_SPEED 0x04 /* 设置USB总线速度, 在每次CMD11_SET_USB_MODE设置USB工作模式时会自动恢复到12Mbps全速 */
/* 输入: 总线速度代码 */
/* 00H=12Mbps全速FullSpeed(默认值), 01H=1.5Mbps(仅修改频率), 02H=1.5Mbps低速LowSpeed */
#define CMD11_GET_DEV_RATE 0x0A /* 主机方式: 获取当前连接的USB设备的数据速率类型 */
/* 输入: 数据07H */
/* 输出: 数据速率类型 */
/* 位4为1则是1.5Mbps低速USB设备, 否则是12Mbps全速USB设备 */
#define CMD11_GET_TOGGLE 0x0A /* 获取OUT事务的同步状态 */
/* 输入: 数据1AH */
/* 输出: 同步状态 */
/* 位4为1则OUT事务同步, 否则OUT事务不同步 */
#define CMD11_READ_VAR8 0x0A /* 读取指定的8位文件系统变量 */
/* 输入: 变量地址 */
/* 输出: 数据 */
/*#define CMD11_GET_MAX_LUN = CMD11_READ_VAR8( VAR_UDISK_LUN )*/ /* 主机方式: 获取USB存储器最大和当前逻辑单元号 */
#define CMD20_SET_RETRY 0x0B /* 主机方式: 设置USB事务操作的重试次数 */
/* 输入: 数据25H, 重试次数 */
/* 位7为0则收到NAK时不重试, 位7为1位6为0则收到NAK时无限重试, 位7为1位6为1则收到NAK时最多重试3秒, 位5~位0为超时后的重试次数 */
#define CMD20_WRITE_VAR8 0x0B /* 设置指定的8位文件系统变量 */
/* 输入: 变量地址, 数据 */
/*#define CMD20_SET_DISK_LUN = CMD20_WRITE_VAR8( VAR_UDISK_LUN )*/ /* 主机方式: 设置USB存储器的当前逻辑单元号 */
#define CMD14_READ_VAR32 0x0C /* 读取指定的32位文件系统变量 */
/* 输入: 变量地址 */
/* 输出: 数据(总长度32位,低字节在前) */
#define CMD50_WRITE_VAR32 0x0D /* 设置指定的32位文件系统变量 */
/* 输入: 变量地址, 数据(总长度32位,低字节在前) */
#define CMD01_DELAY_100US 0x0F /* 延时100uS(串口不支持) */
/* 输出: 延时期间输出0,延时结束输出非0 */
#define CMD40_SET_USB_ID 0x12 /* 设备方式: 设置USB厂商VID和产品PID */
/* 输入: 厂商ID低字节, 厂商ID高字节, 产品ID低字节, 产品ID高字节 */
#define CMD10_SET_USB_ADDR 0x13 /* 设置USB地址 */
/* 输入: 地址值 */
#define CMD01_TEST_CONNECT 0x16 /* 主机方式/不支持SD卡: 检查USB设备连接状态 */
/* 输出: 状态( USB_INT_CONNECT或USB_INT_DISCONNECT或USB_INT_USB_READY, 其它值说明操作未完成 ) */
#define CMD00_ABORT_NAK 0x17 /* 主机方式: 放弃当前NAK的重试 */
#define CMD10_SET_ENDP2 0x18 /* 设备方式(串口不支持): 设置USB端点0的接收器 */
/* 输入: 工作方式 */
/* 位7为1则位6为同步触发位, 否则同步触发位不变 */
/* 位3~位0为事务响应方式: 0000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */
#define CMD10_SET_ENDP3 0x19 /* 设备方式(串口不支持): 设置USB端点0的发送器 */
/* 输入: 工作方式 */
/* 位7为1则位6为同步触发位, 否则同步触发位不变 */
/* 位3~位0为事务响应方式: 0000~1000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */
#define CMD10_SET_ENDP4 0x1A /* 设备方式(串口不支持): 设置USB端点1的接收器 */
/* 输入: 工作方式 */
/* 位7为1则位6为同步触发位, 否则同步触发位不变 */
/* 位3~位0为事务响应方式: 0000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */
#define CMD10_SET_ENDP5 0x1B /* 设备方式(串口不支持): 设置USB端点1的发送器 */
/* 输入: 工作方式 */
/* 位7为1则位6为同步触发位, 否则同步触发位不变 */
/* 位3~位0为事务响应方式: 0000~1000-就绪ACK, 1110-正忙NAK, 1111-错误STALL */
#define CMD10_SET_ENDP6 0x1C /* 设置USB端点2/主机端点的接收器 */
/* 输入: 工作方式 */
/* 位7为1则位6为同步触发位, 否则同步触发位不变 */
/* 位3~位0为事务响应方式: 0000-就绪ACK, 1101-就绪但不返回ACK, 1110-正忙NAK, 1111-错误STALL */
#define CMD10_SET_ENDP7 0x1D /* 设置USB端点2/主机端点的发送器 */
/* 输入: 工作方式 */
/* 位7为1则位6为同步触发位, 否则同步触发位不变 */
/* 位3~位0为事务响应方式: 0000-就绪ACK, 1101-就绪但无须应答, 1110-正忙NAK, 1111-错误STALL */
#define CMD00_DIRTY_BUFFER 0x25 /* 主机文件模式: 清除内部的磁盘和文件缓冲区 */
#define CMD10_WR_USB_DATA3 0x29 /* 设备方式(串口不支持): 向USB端点0的发送缓冲区写入数据块 */
/* 输入: 长度, 数据流 */
#define CMD10_WR_USB_DATA5 0x2A /* 设备方式(串口不支持): 向USB端点1的发送缓冲区写入数据块 */
/* 输入: 长度, 数据流 */
/* ********************************************************************************************************************* */
/* 辅助命令(手册二), 不太常用或者是为了与CH375和CH372兼容, 以下命令总是在操作结束时产生中断通知, 并且总是没有输出数据 */
#define CMD1H_CLR_STALL 0x41 /* 主机方式: 控制传输-清除端点错误 */
/* 输入: 端点号 */
/* 输出中断 */
#define CMD1H_SET_ADDRESS 0x45 /* 主机方式: 控制传输-设置USB地址 */
/* 输入: 地址值 */
/* 输出中断 */
#define CMD1H_GET_DESCR 0x46 /* 主机方式: 控制传输-获取描述符 */
/* 输入: 描述符类型 */
/* 输出中断 */
#define CMD1H_SET_CONFIG 0x49 /* 主机方式: 控制传输-设置USB配置 */
/* 输入: 配置值 */
/* 输出中断 */
#define CMD0H_AUTO_SETUP 0x4D /* 主机方式/不支持SD卡: 自动配置USB设备 */
/* 输出中断 */
#define CMD2H_ISSUE_TKN_X 0x4E /* 主机方式: 发出同步令牌, 执行事务, 该命令可代替 CMD10_SET_ENDP6/CMD10_SET_ENDP7 + CMD1H_ISSUE_TOKEN */
/* 输入: 同步标志, 事务属性 */
/* 同步标志的位7为主机端点IN的同步触发位, 位6为主机端点OUT的同步触发位, 位5~位0必须为0 */
/* 事务属性的低4位是令牌, 高4位是端点号 */
/* 输出中断 */
#define CMD1H_ISSUE_TOKEN 0x4F /* 主机方式: 发出令牌, 执行事务, 建议用CMD2H_ISSUE_TKN_X命令 */
/* 输入: 事务属性 */
/* 低4位是令牌, 高4位是端点号 */
/* 输出中断 */
#define CMD0H_DISK_INIT 0x51 /* 主机方式/不支持SD卡: 初始化USB存储器 */
/* 输出中断 */
#define CMD0H_DISK_RESET 0x52 /* 主机方式/不支持SD卡: 控制传输-复位USB存储器 */
/* 输出中断 */
#define CMD0H_DISK_SIZE 0x53 /* 主机方式/不支持SD卡: 获取USB存储器的容量 */
/* 输出中断 */
#define CMD0H_DISK_INQUIRY 0x58 /* 主机方式/不支持SD卡: 查询USB存储器特性 */
/* 输出中断 */
#define CMD0H_DISK_READY 0x59 /* 主机方式/不支持SD卡: 检查USB存储器就绪 */
/* 输出中断 */
#define CMD0H_DISK_R_SENSE 0x5A /* 主机方式/不支持SD卡: 检查USB存储器错误 */
/* 输出中断 */
#define CMD0H_RD_DISK_SEC 0x5B /* 主机文件模式: 从磁盘读取一个扇区的数据到内部缓冲区 */
/* 输出中断 */
#define CMD0H_WR_DISK_SEC 0x5C /* 主机文件模式: 将内部缓冲区的一个扇区的数据写入磁盘 */
/* 输出中断 */
#define CMD0H_DISK_MAX_LUN 0x5D /* 主机方式: 控制传输-获取USB存储器最大逻辑单元号 */
/* 输出中断 */
#define USB_INT_SUCCESS 0x14 /* USB事务或者传输操作成功 */
#define USB_INT_CONNECT 0x15 /* 检测到USB设备连接事件, 可能是新连接或者断开后重新连接 */
#define USB_INT_DISCONNECT 0x16 /* 检测到USB设备断开事件 */
#define USB_INT_BUF_OVER 0x17 /* USB传输的数据有误或者数据太多缓冲区溢出 */
#define USB_INT_USB_READY 0x18 /* USB设备已经被初始化(已经分配USB地址) */
#define USB_INT_DISK_READ 0x1D /* USB存储器请求数据读出 */
#define USB_INT_DISK_WRITE 0x1E /* USB存储器请求数据写入 */
#define USB_INT_DISK_ERR 0x1F /* USB存储器操作失败 */
/* 附加的USB操作状态定义 */
#define ERR_USB_UNKNOWN 0xFA /* 未知错误,不应该发生的情况,需检查硬件或者程序错误 */
#define CMD_RET_SUCCESS 0x51 /* 命令操作成功 */
#define CMD_RET_ABORT 0x5F /* 命令操作失败 */
//void SPI2_Init(void);
//uint8_t SPI2_SendByte(uint8_t Byte);
void xWriteCH376Cmd(uint8_t mCmd);
void xWriteCH376Data(uint8_t mData);
uint8_t xReadCH376Data(void);
void xEndCH376Cmd(void);
void spi0_init(void);
uint8_t mInitCH376Host(void);
uint8_t CH376DiskMount( void );
uint8_t CH376FileClose( uint8_t UpdateSz );
uint8_t CH376GetDiskStatus( void );
uint8_t CH376FileCreatePath( uint8_t * PathName );
uint8_t CH376ByteWrite( uint8_t * buf, uint16_t ReqCount, uint16_t * RealCount );
uint8_t CH376ByteLocate( uint32_t offset );
uint8_t CH376FileOpenPath( uint8_t * PathName );
#endif /* BSP_CH376_H */
main.c函数中调用实现数据导出到U盘的1234.txt文件
retval = mInitCH376Host();
retval = CH376DiskConnect(); //读出U盘的状态
if(retval == USB_INT_SUCCESS)
{ //检查U盘是否连接//等待U盘插入
UART3_Transmit_DMA(UART3,(uint8_t *)"U OK", 10);//------------------------------------------调试用
}
else
{
UART3_Transmit_DMA(UART3,(uint8_t *)"没检测到U盘", 20);//------------------------------------调试用
}
for ( u32count = 0; u32count < 10000; u32count ++ )
{
delay_1ms( 10 );
retval = CH376DiskMount( ); //初始化磁盘并测试磁盘是否就绪.
if ( retval == USB_INT_SUCCESS ) //准备好
{
//UART3_Transmit_DMA(UART3,(uint8_t *)"INTOK", 10);//----------------------------------调试用
break;
}
else if ( retval == ERR_DISK_DISCON )// 检测到断开,重新检测并计时
{
break;
}
if ( CH376GetDiskStatus( ) >= DEF_DISK_MOUNTED && u32count >= 5 ) // 有的U盘总是返回未准备好,不过可以忽略,只要其建立连接MOUNTED且尝试5*50mS
{
//UART3_Transmit_DMA(UART3,(uint8_t *)"STATUSOK", 10);//--------------------------------调试用
break;
}
}
delay_1ms(1); //每次操作后必要的延时
u32retcount=CH376FileOpenPath( "/1234.TXT" );
if(u32retcount==ERR_MISS_FILE ){
u32retcount=CH376FileCreatePath( "/1234.TXT" );
}
UART3_Transmit_DMA(UART3,(uint8_t *)"===\n", 20);//---------------------------------------------调试用
u32retcount = CH376ByteLocate( 0xFFFFFFFF );
if ( u32retcount != USB_INT_SUCCESS )
{
return( u32retcount );
}
delay_1ms(200); //每次操作后必要的延时
u32retcount = sprintf( (char *)buf , "时间 状态 \n");
u32retcount=CH376ByteWrite((uint8_t *) buf, u32retcount, NULL ); // 以字节为单位向当前位置写入数据块
for(u32count=0;u32count<10;u32count++)
{
memset((void *)buf, 255, 0);
u32retcount = sprintf( (char *)buf , " %d %d %d %d %d %d %d %d %s\n", u32count,retval,retval,retval,retval,retval,retval,retval,"a");
u32retcount=CH376ByteWrite((uint8_t *) buf, u32retcount, NULL ); // 以字节为单位向当前位置写入数据块
u32retcount=CH376ByteWrite((uint8_t *) buf, 0, NULL ); // 以字节为单位向当前位置写入数据块
UART3_Transmit_DMA(UART3,(uint8_t *)buf, 60);//------------------------------------单条数据下载成功
}
delay_1ms(200); //每次操作后必要的延时
retval=CH376FileClose(1); // 关闭文件,对于字节读写建议自动更新文件长度
while ( CH376DiskConnect() == USB_INT_SUCCESS ) delay_1ms(500); // 等待U盘拔出
delay_1ms(200); //每次操作后必要的延时
UART3_Transmit_DMA(UART3,(uint8_t *)"DONE!", 10);//------------------------------------下载结束
参考资料
- GD32F427xx_Datasheet_Rev1.2.pdf
- GD32F4xx_User_Manual_Rev2.7_CN.pdf
- GD32F4xx_gujiankushiyongzhinan_V1.0.pdf
- GD32F4xx_Firmware_Library_V3.0.2.zip
- GD32F4xx_Demo_Suites_V2.6.1.rar
- GD32F4xx_AddOn_V3.0.0.rar