/* name: IO口模拟SPI.c writer: xiaowu date: 2010/11/3 **************************************** ** Copyright (C) 深圳蓝色飞舞科技 2008-2010 ** ** Web: http://www.lanwind.com ** **************************************** ** USB Host File Module @PB375A ** ** 51 mcu ** ** 深圳蓝色飞舞科技有限公司 ** ** 联系方式:0755-29739852 ** 技术email:xiaowuyeah@163.com ** discription: | | | | | 51MCU | | PB375A | | P13|---> |CS | | P12|---> |SCK | | P10|---> |SDI | | P11|<--- |SDO | |________ | |____________| 51单片机的 的P13,P12,P10,P11分别和PB375A的CS SCK SDI SDO连接 该例程使用了51的IO来模拟SPI 软件流程: 初始化IO口 检测U盘是否存在 新建文件 写入数据 关闭文件 ========================================================================================================== 移植说明: 对于不同的单片机的IO,你需要改动的函数有: sbit PB375A_CS = P1^3; sbit PB375A_SCK = P1^2; sbit PB375A_SDI = P1^0; sbit PB375A_SDO = P1^1; 需要将这4个定义改为对应的单片机的IO口操作 ========================================================================================================== ********************************************* */ #include #include #define PB375_VER 0x28 /* 当前模块版本 */ /* ********************************************************************************************************************* */ /* 返回的操作状态码 */ #define ERR_DISK_DISCON 0x82 /* 检测到USB设备连接事件,磁盘已经断开,或者磁盘尚未连接 */ /* 最终状态码 */ #define ERR_SUCCESS 0x00 /* 操作成功 */ /* 外部命令码 */ #define CMD_FileOpen 0x64 /* 打开文件 */ #define CMD_FileCreate 0x65 /* 新建文件并打开,如果文件已经存在则先删除后再新建 */ #define CMD_FileErase 0x66 /* 删除文件并关闭 */ #define CMD_FileClose 0x67 /* 关闭当前文件 */ #define CMD_DiskReady 0x71 /* 查询磁盘是否准备好 */ #define CMD_ByteLocate 0x7A /* 以字节为单位移动当前文件指针 */ #define CMD_ByteRead 0x7B /* 以字节为单位从当前文件读取数据块 */ #define CMD_ByteWrite 0x7C /* 以字节为单位向当前文件写入数据块 */ sbit PB375A_CS = P1^3; sbit PB375A_SCK = P1^2; sbit PB375A_SDI = P1^0; sbit PB375A_SDO = P1^1; #define PB375_CS_SET PB375A_CS = 1 #define PB375_CS_CLR PB375A_CS = 0 #define PB375_SCK_SET PB375A_SCK = 1 #define PB375_SCK_CLR PB375A_SCK = 0 #define PB375_SDI_SET PB375A_SDI = 1 #define PB375_SDI_CLR PB375A_SDI = 0 #define PB375_SDO PB375A_SDO //发送接收数组缓冲区 #define MAXBUFLEN 128 //发送缓冲区 unsigned char sendBuff[MAXBUFLEN]; //接收缓冲区 unsigned char recBuff[MAXBUFLEN]; void SPI_MasterTransmit(char cData); unsigned char SPI_Read(void); //初始化IO口 CS输出 void initPort() { PB375_CS_SET; PB375_SCK_SET; PB375_SDI_SET; PB375_RST_SET; PB375_RST_CLR; //RESET } void delayUs1(void) { unsigned char tempi; for(tempi = 1;tempi != 0;tempi--) ; } /* 发送一个字节数据给PB375A模块 */ void mSpiSend( unsigned char c ) { unsigned char i; for ( i = 8; i != 0; i -- ) { // 8个位 PB375_SCK_CLR; if ( c & 0x80 ) PB375_SDI_SET; // 向模块的SDI输入引脚输出数据 else PB375_SDI_CLR; c <<= 1; delayUs1(); PB375_SCK_SET; // SPI时钟上升沿 delayUs1(); } } /* 接收一个字节数据 */ unsigned char mSpiRec( void ) { unsigned char i, d; d = 0; PB375_SCK_CLR; for ( i = 8; i != 0; i -- ) { // 8个位 delayUs1(); d <<= 1; PB375_SCK_SET; // SPI时钟上升沿 if ( PB375_SDO ) d++; // 如果模块的SDO输出引脚为高电平则输入位1 PB375_SDO delayUs1(); PB375_SCK_CLR; } return( d ); } /* 以毫秒为单位延时,适用于24MHz时钟 */ void mDelaymS( unsigned char delay ) { unsigned char i, j, c; for ( i = delay; i != 0; i -- ) { for ( j = 200; j != 0; j -- ) c += 1; /* 在24MHz时钟下延时500uS */ } } /* 执行命令 name:ExecCommand discription: 操作流程 CS置低 发送命令 发送参数长度 发送参数内容 CS置高 CS置低 读返回状态 若状态为成功 则读返回参数 CS置高 若状态为忙 则CS置高 返回继续读状态 若状态为错误 则CS置高 返回状态 */ unsigned char ExecCommand( unsigned char cmd, unsigned char len ) { unsigned char i, j, status; PB375_CS_CLR; // SPI片选CS为低 mSpiSend( cmd ); // 写入命令码 mSpiSend( len ); // 写入后续参数的长度 if ( len ) // 有参数 { for ( i = 0; i != len; i ++ ) mSpiSend( sendBuff[ i ] ); // 依次写入参数数据 } PB375_CS_SET; // SPI片选 CS为高 while ( 1 ) // 处理数据传输,直到操作完成才退出 { PB375_CS_CLR; // SPI片选 CS为低 status = mSpiRec(); // 读返回状态 if ( status == 0xFF ) { // 模块操作尚未完成,也就是INT#没有中断产生 PB375_CS_SET; // SPI片选 CS为高 mDelaymS( 1 ); continue; // 继续等待模块完成操作 } if ( status == ERR_SUCCESS ) // 操作成功 { i = mSpiRec(); if ( i ) { // 返回参数非空 j = 0; do { recBuff[ j ] = mSpiRec(); // 接收结果数据并保存到参数结构中 j ++; } while ( -- i ); } PB375_CS_SET; // SPI片选 CS为高 break; // 操作成功返回 } else // 操作失败 { PB375_CS_SET; // SPI片选 CS为高 if ( status == ERR_DISK_DISCON ) mDelaymS( 100 ); // U盘刚刚连接或者断开,应该延时几十毫秒再操作 break; // 操作失败 } } return( status ); } /* 主程序 流程: 初始化端口 初始化SPI 延时50ms 检测U盘是否存在 根据操作码进行操作(如新建文件) 新建文件 写入数据 关闭文件 完成 */ void main( ) { unsigned char i,j; unsigned char oprCode; // 操作码 initPort(); SPI_MasterInit(); mDelaymS( 50 ); // 延时50毫秒,PB375模块上电后需要50毫秒左右的复位时间 for ( i = 0; i < 5; i ++ ) { // 查询磁盘是否准备好 mDelaymS( 100 ); if ( ExecCommand( CMD_DiskReady, 0 ) == ERR_SUCCESS ) break; } oprCode = 4; // 1----删除BLUEFIVE.TXT文件 // 2----从BLUEFIVE.TXT的最后追加数据 // 3----读取BLUEFIVE.TXT内容 // 4----新建BLUEFIVE.TXT文件并写入数据 switch(oprCode) { case 1: //删除文件 sendBuff[0] = 92; // \BLUEFIVE.TXT sendBuff[1] = 0x42; sendBuff[2] = 0x4C; sendBuff[3] = 0x55; sendBuff[4] = 0x45; sendBuff[5] = 0x46; sendBuff[6] = 0x49; sendBuff[7] = 0x56; sendBuff[8] = 0x45; sendBuff[9] = 0x2E; sendBuff[10] = 0x54; sendBuff[11] = 0x58; sendBuff[12] = 0x54; if ( ExecCommand( CMD_FileErase, 13 ) == ERR_SUCCESS ) //删除文件 { //操作成功 } else { //操作失败 } break; case 2: //写入数据到文件,从文件的最后追加数据 sendBuff[0] = 92; // \BLUEFIVE.TXT sendBuff[1] = 0x42; sendBuff[2] = 0x4C; sendBuff[3] = 0x55; sendBuff[4] = 0x45; sendBuff[5] = 0x46; sendBuff[6] = 0x49; sendBuff[7] = 0x56; sendBuff[8] = 0x45; sendBuff[9] = 0x2E; sendBuff[10] = 0x54; sendBuff[11] = 0x58; sendBuff[12] = 0x54; if ( ExecCommand( CMD_FileOpen, 13 ) == ERR_SUCCESS ) //打开文件 { //加一个字节定位 sendBuff[0] = 0xFF; sendBuff[1] = 0XFF; sendBuff[2] = 0XFF; sendBuff[3] = 0XFF; if ( ExecCommand( CMD_ByteLocate, 4 ) == ERR_SUCCESS ) { sendBuff[0] = 10; //写入文件字节大小 for(j = 1; j <10;j++) sendBuff[j] = 0x35; if ( ExecCommand( CMD_ByteWrite, 11 ) == ERR_SUCCESS ) ExecCommand( CMD_FileClose, 1 ); } } else { //操作失败 } break; case 3: //读取文件 sendBuff[0] = 92; // \BLUEFIVE.TXT sendBuff[1] = 0x42; sendBuff[2] = 0x4C; sendBuff[3] = 0x55; sendBuff[4] = 0x45; sendBuff[5] = 0x46; sendBuff[6] = 0x49; sendBuff[7] = 0x56; sendBuff[8] = 0x45; sendBuff[9] = 0x2E; sendBuff[10] = 0x54; sendBuff[11] = 0x58; sendBuff[12] = 0x54; if ( ExecCommand( CMD_FileOpen, 13 ) == ERR_SUCCESS ) //打开文件 { sendBuff[0] = 11; //读取的字节数量 if (ExecCommand( CMD_ByteRead, 1 ) == ERR_SUCCESS ) ExecCommand( CMD_FileClose, 0 ); //读取数据保持在recBuf[] } else //操作失败 { } break; case 4://创建文件 sendBuff[0] = 92; // \BLUEFIVE.TXT sendBuff[1] = 0x42; sendBuff[2] = 0x4C; sendBuff[3] = 0x55; sendBuff[4] = 0x45; sendBuff[5] = 0x46; sendBuff[6] = 0x49; sendBuff[7] = 0x56; sendBuff[8] = 0x45; sendBuff[9] = 0x2E; sendBuff[10] = 0x54; sendBuff[11] = 0x58; sendBuff[12] = 0x54; if ( ExecCommand( CMD_FileCreate, 13 ) == ERR_SUCCESS ) //新建文件 { sendBuff[0] = 19; //写入文件字节大小 for(j = 1; j <19;j++) sendBuff[j] = 0x55; ExecCommand( CMD_ByteWrite, 20 ); //写入19个字节的0x55到文件中 ExecCommand( CMD_FileClose, 0 ); //操作成功 关闭文件 } else { //操作失败 } break; default :break; } while ( 1 ) { /* 主循环 */ } }