本篇文章来自极术社区与兆易创新组织的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 );}}}}
#endifxWriteCH376Cmd( 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_Uif ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 ) {CH376WriteVar32( VAR_CURRENT_CLUST, 0 );}
#endifreturn( 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_Uif ( name[0] == DEF_SEPAR_CHAR1 || name[0] == DEF_SEPAR_CHAR2 ) {CH376WriteVar32( VAR_CURRENT_CLUST, 0 );}
#endifreturn( 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

【GD32F427开发板试用】硬件SPI通信驱动CH376芯片,用单片机实现U盘数据下载相关推荐

  1. 【GD32F427开发板试用】5. SPI驱动TFTLCD屏幕

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:hehung 之前发帖 [GD32F427开发板试用]1. 串口实现scanf输入控制L ...

  2. 【GD32F427开发板试用】INA226完成电流电压采集

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:จุ๊บ冰语 前言 本次有幸参与并通过了极术社区组织的[GD32F427开发板试用]活动 ...

  3. 【GD32F427开发板试用】三、USB转CAN功能开发与试用总结

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:chenjie [GD32F427开发板试用]一.环境搭建与freertos移植 [GD ...

  4. 【GD32F427开发板试用】二、USB库移植与双USB CDC-ACM功能开发

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:chenjie [GD32F427开发板试用]一.环境搭建与freertos移植 [GD ...

  5. 【GD32F427开发板试用】+GD32F427开发以来遇到的问题以及解决方案

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:考试结束就睡觉 大纲 开箱问题 环境搭建以及创建第一个project 串口问题 重定向问 ...

  6. GD32F427开发板试用 驱动TM1640显示屏

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:swag 一.硬件介绍 TM1640 是一种LED(发光二极管显示器)驱动控制专用电路, ...

  7. 【GD32F427开发板试用】06-硬件I2C软件I2C驱动0.91OLED

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:Stark_GS I2C 简介及特点 并行总线至 I2C 总线协议的转换及接口: 同一接 ...

  8. 【GD32F427开发板试用】USR-C210 WIFI模块进行以太网通信

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:小蜗牛 一.硬件介绍 USR-C210 硬件上集成了 MAC.基频芯片.射频收发单元,尺 ...

  9. 【GD32F427开发板试用】FreeRTOS移植工程

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:kings669669 前言 为了方便需要FreeRTOS,附上移植完毕的工程,方便大家 ...

最新文章

  1. Android上的MVP:如何组织显示层的内容
  2. Unity TIP4: 带泛型参数的接口注入(interface,generic)
  3. 2.4操作系统之死锁详解(预防、避免、检测、解除)+思维导图
  4. android crop 大图,Android-CropView
  5. USB转串口 FT232/PL2303/CH340 驱动以及使用体会
  6. redhat7.1安装mysql_redhat7.1 安装mysql 5.7.10步骤详解(图文详解)
  7. [转]Python 获取Windows管理员权限
  8. 数据结构实验之栈三:后缀式求值
  9. strcat在某种特定条件下的优化
  10. Linux下使用Nginx端口转发出现502错误的一种解决办法
  11. 软件项目管理 2.2.项目招投标流程
  12. 机器学习之理解支持向量机SVM
  13. 新兴研究将如何更好地应对社会挑战?我们等你来共同探讨!
  14. 趣头条递交招股书 将冲刺移动内容聚合第一股
  15. PPT技巧-宏命令:如何一键删除所有页面动画效果
  16. 2022-2028全球及中国铝硅合金电子封装材料行业研究及十四五规划分析报告
  17. C. The Intriguing Obsession(组合数学)
  18. strcmp函数的两种实现
  19. Java开发者跳槽指南面试篇
  20. netfilter 子系统实现tcp断链

热门文章

  1. 猫生病了,老鼠在干嘛?
  2. js监听只读文本框_急急急~~~~~~js radio 文本框只读/只写
  3. textarea标签自适应宽度和高度
  4. AP RFC介绍:关于sRFC,aRFC,tRFC,qRFC和bgRFC
  5. [工作]公司报销发票抬头信息
  6. Cannot have more than one plugin implementing a REST wrapper
  7. python漏洞检测脚本_一个检测OpenSSL心脏出血漏洞的Python脚本分享
  8. 百年科技发明史:改变人类生活的发明
  9. 3DLC系列之:图像窗口
  10. Harbor安装教程