实验九MicroSD卡操作实验
程序流程:时钟初始化-->SSI初始化-->液晶初始化-->UART初始化--> 接收UART命令help,cat,ls等-->处理命令(nStatus = CmdLineProcess(g_cCmdBuf);)-->判断nStatus是否为0,如果为0正常运行程序输出结果并重新接收命令,否则的话输出相应的错误提示并重新接收命令。
总的来说,我们在串口调试软件发送窗口输入一个命令后点击发送到单片机,单片机开始处理命令,并把结果通过端口发送到软件的接收数据窗口。
程序注释(按住ctrl点击这里到实验十):
uint32_t g_ui32SysClock;
#define PATH_BUF_SIZE 80 //定义缓冲区大小,用来保存路径
#define CMD_BUF_SIZE 64 //定义命令行的缓冲区大小
static char g_cCwdBuf[PATH_BUF_SIZE] = "/"; //这个缓冲区保存当前工作目录的完整路径static char g_cTmpBuf[PATH_BUF_SIZE]; //一个临时数据缓冲区操作文件路径时使用,或从SD卡读取数据
static char g_cCmdBuf[CMD_BUF_SIZE]; //一个缓冲区用来保存命令行
static FATFS g_sFatFs;
static DIR g_sDirObject;
static FILINFO g_sFileInfo;
static FIL g_sFileObject;
typedef struct
{
FRESULT fresult;
char *pcResultStr;
}
tFresultString;
#define FRESULT_ENTRY(f) { (f), (#f) }
/
/用于查错误代码并打印
tFresultString g_sFresultStrings[] =
{
FRESULT_ENTRY(FR_OK),
FRESULT_ENTRY(FR_DISK_ERR),
FRESULT_ENTRY(FR_INT_ERR),
FRESULT_ENTRY(FR_NOT_READY),
FRESULT_ENTRY(FR_NO_FILE),
FRESULT_ENTRY(FR_NO_PATH),
FRESULT_ENTRY(FR_INVALID_NAME),
FRESULT_ENTRY(FR_DENIED),
FRESULT_ENTRY(FR_EXIST),
FRESULT_ENTRY(FR_INVALID_OBJECT),
FRESULT_ENTRY(FR_WRITE_PROTECTED),
FRESULT_ENTRY(FR_INVALID_DRIVE),
FRESULT_ENTRY(FR_NOT_ENABLED),
FRESULT_ENTRY(FR_NO_FILESYSTEM),
FRESULT_ENTRY(FR_MKFS_ABORTED),
FRESULT_ENTRY(FR_TIMEOUT),
FRESULT_ENTRY(FR_LOCKED),
FRESULT_ENTRY(FR_NOT_ENOUGH_CORE),
FRESULT_ENTRY(FR_TOO_MANY_OPEN_FILES),
FRESULT_ENTRY(FR_INVALID_PARAMETER)
};
#define NUM_FRESULT_CODES (sizeof(g_sFresultStrings) / sizeof(tFresultString)) tContext g_sContext;
//返回一个错误代码的字符串
const char *
StringFromFresult(FRESULT fresult)
{
unsigned int uIdx;
//进入一个循环从错误代码表中搜索匹配错误代码
for(uIdx = 0; uIdx < NUM_FRESULT_CODES; uIdx++)
{
//如果到匹配项,则返回错误代码的字符串名称
if(g_sFresultStrings[uIdx].fresult == fresult)
{
return(g_sFresultStrings[uIdx].pcResultStr);
}
}
//如果没有到匹配的代码,则返回“UNKNOW ERROR CODE”
return("UNKNOWN ERROR CODE");
}
void
SysTickHandler(void)
{
disk_timerproc();
}
//这个函数实现了“ls”命令。用来打开当前目录,并打印所到的每项内容,显示文件属性,时间,日期,文件大小,以及文件名
int
Cmd_ls(int argc, char *argv[])
{
unsigned long ulTotalSize;
unsigned long ulFileCount;
unsigned long ulDirCount;
FRESULT fresult;
FATFS *pFatFs;
//打开当前目录进行访问
单片机printf函数
fresult = f_opendir(&g_sDirObject, g_cCwdBuf);
//检查错误,如果有错误就返回错误
if(fresult != FR_OK)
{
return(fresult);
}
ulTotalSize = 0;
ulFileCount = 0;
ulDirCount = 0;
UARTprintf("\n");
//列举所有目录条目,并打印
for(;;)
{
fresult = f_readdir(&g_sDirObject, &g_sFileInfo);
if(fresult != FR_OK)
{
return(fresult);
}
if(!g_sFileInfo.fname[0])
{
break;
}
if(g_sFileInfo.fattrib & AM_DIR)
{
ulDirCount++;
}
else
{
ulFileCount++;
ulTotalSize += g_sFileInfo.fsize;
}
UARTprintf("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9u %s\n",
(g_sFileInfo.fattrib & AM_DIR) ? 'D' : '-',
(g_sFileInfo.fattrib & AM_RDO) ? 'R' : '-',
(g_sFileInfo.fattrib & AM_HID) ? 'H' : '-',
(g_sFileInfo.fattrib & AM_SYS) ? 'S' : '-',
(g_sFileInfo.fattrib & AM_ARC) ? 'A' : '-',
(g_sFileInfo.fdate >> 9) + 1980,
(g_sFileInfo.fdate >> 5) & 15,
g_sFileInfo.fdate & 31,
(g_sFileInfo.ftime >> 11),
(g_sFileInfo.ftime >> 5) & 63,
g_sFileInfo.fsize,
g_sFileInfo.fname);
}
UARTprintf("\n%4u File(s),%10u bytes total\n%4u Dir(s)",
ulFileCount, ulTotalSize, ulDirCount);
fresult = f_getfree("/", &ulTotalSize, &pFatFs);
if(fresult != FR_OK)
{
return(fresult);
}
UARTprintf(", %10uK bytes free\n", ulTotalSize * pFatFs->csize / 2);
return(0);
}
//这个函数实现了“cd”命令。它接受一个参数来指定当前的工作目录。路径分隔符必须使用正斜杠“/”。一旦新指定目录,它试图打开目录,确定它的存在。如果成功打开新路径,那么当前工作目录改变到新的路径
int
Cmd_cd(int argc, char *argv[])
{
unsigned int uIdx;
FRESULT fresult;
//当前工作路径复制到一个临时缓冲区
strcpy(g_cTmpBuf, g_cCwdBuf);
if(argv[1][0] == '/')
{
//确保新路径并不比命令行缓冲区大
if(strlen(argv[1]) + 1 > sizeof(g_cCwdBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
else
{
strncpy(g_cTmpBuf, argv[1], sizeof(g_cTmpBuf));
}
}
else if(!strcmp(argv[1], ".."))
{
uIdx = strlen(g_cTmpBuf) - 1;
//备份路径名,直到结束的分隔符(/)到,或者直到我们提高路径的开始while((g_cTmpBuf[uIdx] != '/') && (uIdx > 1))
{
uIdx--;
}
g_cTmpBuf[uIdx] = 0;
}
//否则,这只是一个正常的当前目录的路径名,需要附加到当前路径else
{
if(strlen(g_cTmpBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cCwdBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
//新路径是对的,所以添加分隔符,然后添加新的目录路径
else
{
if(strcmp(g_cTmpBuf, "/"))
{
strcat(g_cTmpBuf, "/");
}
strcat(g_cTmpBuf, argv[1]);
}
}
fresult = f_opendir(&g_sDirObject, g_cTmpBuf);
//如果它不能被打开,那么有错误,返回错误
if(fresult != FR_OK)
{
UARTprintf("cd: %s\n", g_cTmpBuf);
return(fresult);
}
//否则,它是一个有效的新路径,所以将它复制到CWD
else
{
strncpy(g_cCwdBuf, g_cTmpBuf, sizeof(g_cCwdBuf));
}
return(0);
}