完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
之前做毕设买了CH375B模块,一直没好好用过。现在想把这个模块用起来。程序参考的振南的51例程《U盘扇区读写[IO方式]》 和正点原子的例程模板,只要把最底层的扇区读写测试通过,znFAT文件系统就可以用了。程序用的并口通信控制。先说端口配置:8位数据端口用的GPIOC的低8位,写选通WR、读选通RD、片选 CS、命令口和数据口地址选择A0和中断INT用的GPIOB端口。端口定义如下:
#define GPIO_CH375_Data GPIOC //数据端口 #define DATA_MODE_IN GPIO_CH375_Data->CRL=0x44444444; // Floating IN #define DATA_MODE_OUT GPIO_CH375_Data->CRL=0x33333333; // PP_OUT 50MHZ #define GPIO_CH375_CTL GPIOB //CH375控制端口 #define WR PBout(11) #define RD PBout(10) #define CS PBout(9) #define A0 PBout(8) #define INT PBin(12) 端口初始化代码如下: void CH375_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE); // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |GPIO_Pin_11 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; // INT中断 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;// GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |GPIO_Pin_3| GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7 ; //GPIOC数据端口 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); // } //写命令 void CH375_WR_CMD( u8 cmd ) { u16 TempData=0; DATA_MODE_OUT; //设置成数据输出 TempData=GPIO_ReadOutputData(GPIO_CH375_Data); //读取数据口数据,保护高8位 TempData &= 0xFF00; //低8位清0,保留高8位状态 TempData |= (u16)cmd; //写命令 delay_us(10); //延时 CS=0; //打开片选 // delay_us(10); A0=1; //命令模式 // delay_us(10); GPIO_Write(GPIO_CH375_Data, TempData); //向CH375写命令码 //delay_us(10); WR=0; //打开写使能 delay_us(10); // WR=1; //关闭写使能 //delay_us(10); CS=1; //关闭片选 // delay_us(10); A0=1; //恢复A0为高电平 delay_us(200); //延时 } //写数据 void CH375_WR_DAT( u8 dat ) { u16 TempData=0; DATA_MODE_OUT; //数据端口设置成输出,发送数据给CH375 TempData=GPIO_ReadOutputData(GPIO_CH375_Data);//读数据端口数据,保护高8位 TempData &= 0xFF00; //低8位清0 TempData |= (u16)dat; //写数据 delay_us(10); // CS=0; // //delay_us(10); A0=0; // //delay_us(10); GPIO_Write(GPIO_CH375_Data, TempData); // //delay_us(10); WR=0; // delay_us(10); WR=1; // // delay_us(10); CS=1; // //delay_us(10); A0=1; // delay_us(200); // } //读取数据 u8 CH375_RD_DAT( void ) { u8 PortData; DATA_MODE_IN; // delay_us(10); // CS=0; // // delay_us(10); A0=0; // //delay_us(10); RD=0; // // delay_us(10); PortData = (u8)( GPIO_ReadInputData(GPIO_CH375_Data) ); // delay_us(10); RD=1; // //delay_us(10); CS=1; // //delay_us(10); A0=1; // //delay_us(10); return PortData; // } //等待中断 u8 WaitInterrupt( void ) { delay_us(10); INT=1; //IO口作输入先置高 while(INT); //等待中断,低电平有效 delay_us(10); CH375_WR_CMD( CMD_GET_STATUS ); //产生操作完成中断,获取中断状态,收到GET_STATUS命令到INT#引脚撤消中断最大延时3us delay_us(10); return( CH375_RD_DAT( ) ); } 写好读写数据命令函数后就是CH375初始化和磁盘初始化: //CH375芯片初始化,设置CH375为USB主机模式,成功返回0,失败返回1 u8 CH375Init( void ) { u8 i; u8 Read_Data=0; CH375_WR_CMD( CMD_CHECK_EXIST ); //测试工作状态 CH375_WR_DAT( 0x55 ); // 测试数据 Read_Data = CH375_RD_DAT( ); // 返回的数据应是测试数据取反,如发送0x55,返回0xAA if ( Read_Data != 0xaa ) //CH375出错 { for ( i = 100; i != 0; i -- ) { CH375_WR_CMD( CMD_RESET_ALL ); delay_ms(50); //RESET_ALL命令的执行时间最大为40ms CH375_WR_CMD( CMD_CHECK_EXIST ); // 测试工作状态 CH375_WR_DAT( 0x55 ); // 测试数据 Read_Data = CH375_RD_DAT( ); if ( Read_Data == 0xaa ) //读取到的数据是输入数据按位取反 break; } } CH375_WR_CMD( CMD_SET_USB_MODE ); // 设置USB工作模式 delay_us(30);//设置USB工作模式为等待20us CH375_WR_DAT( 6 ); //模式代码,自动检测USB设备连接 for ( i = 0xff; i != 0; i -- ) // 等待操作成功,通常要等待10uS-20uS // { delay_us(20); if ( CH375_RD_DAT( ) == CMD_RET_SUCCESS ) break; //操作成功,退出循环 } if ( i != 0 ) return( 0 ); // 操作成功,返回0 else return( 1 ); // CH375初始化出错,如芯片型号出错或处于串口方式或不支持,返回1 } //磁盘初始化,成功返回0,失败返回1 unsigned char CH375_InitDisk(void) { unsigned char status,i,j=0; //delay_us(100); status=WaitInterrupt(); delay_us(100); if(status==USB_INT_DISCONNECT) return 1; //USB设备断开 while(1) { CH375_WR_CMD(CMD_DISK_INIT); //初始化USB存储器 delay_us(100); status=WaitInterrupt(); //等待中断并获取中断状态 delay_us(100); if(status==USB_INT_SUCCESS) break; } while(1) //以下代码均源自于沁恒的官方优盘初始化函数,借用它可提高对优盘的兼容性 { j++; CH375_WR_CMD(CMD_DISK_SIZE); //获取优盘容量 delay_us(100); status=WaitInterrupt(); //等待中断并获取中断状态 delay_us(100); if(status==USB_INT_SUCCESS) break; else { //Delay(1000); delay_us(100); CH375_WR_CMD(CMD_DISK_R_SENSE); //主机方式:检查USB存储器错误 delay_us(100); status=WaitInterrupt(); //等待中断并获取中断状态 delay_us(100); if(status==USB_INT_SUCCESS) continue; //初始化成功跳出while(1) else return 1; //初始化失败,返回1 } if(j==5) return 1; //初始化失败,返回1 } for(i=0;i!=5;i++) { //delay_us(100); CH375_WR_CMD( CMD_DISK_READY ); //检查USB存储设备的错误 delay_us(100); status=WaitInterrupt(); //等待中断并获取中断状态 delay_us(100); if(status==USB_INT_SUCCESS) return 0; //优盘已经成功初始化,返回0 } return 1; //优盘初始化失败,返回1 } 后面就是main函数了,测试扇区读写功能: #define ADDR 100//6600000//100 //要操作的优盘物理扇区地址 用winhex打开物理磁盘可查看扇区地址数据 u8 flag1=0; u8 Write_pbuf[512]; //发送数据缓冲区 u8 Read_pbuf[2048]; //接收数据缓冲区 u8 status=0xff; //初始化状态标志 //注意:单片机要先上电,再插入优盘 int main(void) { u16 i=0; delay_init(); //延时函数初始化 LED_Init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(9600); //串口初始化波特率9600 printf("串口设置完毕rn"); delay_ms(100); //内部电源上电的复位时间最大为40ms,这里延时防止出现CH375初始化失败 CH375_GPIO_Init(); // CH375_WR_CMD(CMD_GET_IC_VER); // 获取芯片及固件版本 status=CH375_RD_DAT(); // printf("芯片版本为:%#xrn",status); status=CH375Init(); //初始化CH375芯片,成功返回0,失败返回1 printf("CH375芯片初始化值:%#xrn",status); CH375_WR_CMD(CMD_DISK_MAX_LUN); //获取USB存储设备的最大逻辑单元号 status=CH375_RD_DAT(); // 最大逻辑单元号 printf("USB存储设备的最大逻辑单元号为:%#xrn",status); //status=InitDisk(); //初始化优盘,成功返回0,失败返回1 //注意:单片机要先上电,再插入优盘 status=CH375_InitDisk(); //上电后再插入优盘 金士顿8G优盘 东莞16G 3.0优盘测试通过 printf("U盘初始化值:%#xrn",status); status=Get_CH375DiskSize();//打印磁盘容量,单位MByte for(i=0;i<512;i++) Write_pbuf=i;//0x55;// //向数据缓冲区中写入0-255 0-255 共512个字节 printf("向缓冲区中装入完毕rn"); //CH375WriteSector(ADDR,Write_pbuf);//将数据缓冲区中的512个字节数据写入优盘的第ADDR个扇区 CH375_WriteDisk(Write_pbuf,ADDR,4); //连续写多个扇区 printf("写U盘扇区完毕rn"); for(i=0;i<2048;i++) //清空接收数据缓冲区 { Read_pbuf=0; } printf("清空接收缓冲区完毕rn"); //CH375ReadSector(ADDR+1,Read_pbuf);//从优盘的第ADDR个扇区中读取512个字节数据到数据缓冲区 CH375_ReadDisk(Read_pbuf,ADDR,4); //连续读取多个扇区数据 //查看读取到的几个扇区数据,只取一小部分 for(i=0;i<10;i++) { printf("读取到的扇区数据为:i=%d Read_pbuf=%#xrn",i,Read_pbuf); } for(i=520;i<530;i++) { printf("读取到的扇区数据为:i=%d Read_pbuf=%#xrn",i,Read_pbuf); } for(i=1030;i<1040;i++) { printf("读取到的扇区数据为:i=%d Read_pbuf=%#xrn",i,Read_pbuf); } for(i=1600;i<1610;i++) { printf("读取到的扇区数据为:i=%d Read_pbuf=%#xrn",i,Read_pbuf); } printf("读取优盘扇区完毕rn"); for(i=0;i<512;i++) { if(Write_pbuf!=Read_pbuf) //对读取的数据进行匹配 { flag1=1; //匹配失败,flag1=1 break; } } printf("匹配完毕rn"); for(i=0;i<512;i++) //清空发送数据缓冲区 { Write_pbuf=0; //printf("扇区数据为:%#xn",Write_pbuf); } if(flag1) { LED=1; //发光LED灭 printf("优盘扇区读写测试失败rn"); //数据不吻合 } else { LED=0; //发光LED点亮 printf("优盘扇区读写测试成功rn"); //数据吻合 } printf("------------------------------------rn"); while(1){ } } 测试结果如下: 金士顿8G优盘串口内容: 使用winhex打开金士顿8G优盘查看数据和容量如下: 总容量=总扇区数*每扇区字节数=15131636*512=7747397632字节=7388.494140625MByte 之前用程序计算总容量的时候没注意到变量位数,导致计算后的总字节数超过定义的32位变量,输出的结果有误,修改计算过程后计算结果正常了。 到此,用STM32F103RC和CH375模块读写优盘扇区基本实现了,后面就可以用znFAT或FATFS在优盘上读写文件了。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1874 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1658 浏览 1 评论
1143 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
759 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1720 浏览 2 评论
1963浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
788浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
610浏览 3评论
628浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
590浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-11 03:19 , Processed in 0.633296 second(s), Total 41, Slave 36 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号