<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
九、添加新的命令fwrite
1、继续调试程序
在昨天调试的基础上,为了解决问题,今天进行了单步调试,发现读多块指令发出后,会受到一个返回值00,然后就都是0xFF字节。
在路上骑自行车的时候,突然想到,diskread()函数是调用SD_ReadMultiBlock,但是在读的块数为1的时候,可以去调用SD读单块的函数啊,于是在读多块的函数里,加了这句 if ( BlockNum == 1 ) return SD_ReadBlock ( BlockIndex, ReadBuf );。
调试结果出来,还是错误,读单块函数也读到一个00,说明不是函数的问题。
绞尽脑汁,在阅读move_window()函数源代码的时候,突然想到:其它时候调用move_window()的时候,只有读扇区的操作。而由f_write()函数调用的时候,由于文件系统结构体里的扇区为“脏的”,故先进行了写入操作,这个00可能是表示SD卡正在忙的意思,拒绝了刚才读块的指令。这里解决方法有两个:一个是写函数的后续处理,多发几个0xFF给它,让它忙完;再一个就是读块的命令持续发,直到它正确响应这个命令为止。
在修改的时候发现了:
void SD_WaitInBusy( void ){
u8 TmpByte; 可能是它没有初始化带来的问题,改为TmpByte =0。
while ( TmpByte==0x0 )TmpByte = SPI_GetByte( );
SPI_PutByte( 0xFF );
}
重新编译、下载程序,写文件马上成功了,所以变量正确初始化问题对程序是一个很重要的问题,以后一定要记住这个教训。因为这个时候编译不会有问题,实际执行可能就会出现千奇百怪的问题。
2、跟踪执行f_write()的执行流程
在命令窗口输入fwrite aaa.txt。由于目录下已经存在该文件,所以会更新。
先以写和总是创建的模式打开文件,先执行res = follow_path(&dj, path),找到了该文件,会更新目录信息结构体的一些关键信息:当前扇区sect=0x7B8,这是根目录的首扇区,目录索引index=3,aaa.txt是第三个目录项。Dir指向文件系统缓冲扇区的目录项。所指向的文件系统缓冲了目录扇区。Fs.winsect等于绝对扇区号。
接下来:
cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | (dir+DIR_FstClusLO); /*获得文件所占用的簇号 */
ST_WORD(dir+DIR_FstClusHI, 0); /* 修改目录项的信息 */
ST_WORD(dir+DIR_FstClusLO, 0); /因为dir指向
ST_DWORD(dir+DIR_FileSize, 0); /* 文件大小设为0 */
dj.fs->wflag = 1; 当前缓冲对象为根目录扇区,已经修改。缓冲扇区更改的时候,这个修改过的扇区将写回磁盘。
ps = dj.fs->winsect; /* 以下是删除原文件所占的簇链 */
if (cl) {
res = remove_chain(dj.fs, cl); 删除簇链的时候,缓冲扇区变化,此时缓冲的实际上是FAT表的首扇区。
dj.fs->last_clust = cl - 1; /* 文件系统的最后使用簇链更新,这个最新释放的簇可以用于下次分配。 }
res = move_window(dj.fs, ps);这句话实际上又更新了FAT表,簇链的更新有效了。而文件系统缓冲扇区重新回到所在目录的扇区。
fp->dir_sect = dj.fs->winsect; /* 文件目录所在扇区号*/
fp->dir_ptr = dj.dir; 目录项在缓冲扇区内的地址。
fp->flag = mode; /* File access mode */
fp->org_clust =
fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
fp->fptr = 0; fp->csect = 255; /* 在簇内的相对扇区号 */
fp->dsect = 0; 文件数据缓冲区对应的簇号。
以上为更新的文件信息结构体。
3、继续跟踪执行f_write()的执行流程
CharWrite = Uart_GetChar();
if ( CharWrite == 0x1B ) break;
Uart_PutChar(CharWrite);
for ( i="0" ; i<512 ; i++ ) WriteFileBuf = CharWrite; 将读入的字符写入缓冲区,写满一个扇区。
res=f_write(&WriteFileInf,(void *)WriteFileBuf,512,&ByteWrite); //要进去看一看,在第二次这样做的时候,更新的信息如下:
文件的大小和指针都是512,文件相对扇区为1.
sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
sect += fp->csect; 这样可以计算出当前绝对扇区号。
cc = btw / SS(fp->fs); 要写一个扇区
if (cc) {
if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK) 这句话将当前缓冲区的内容写入当前扇区。
当写的内容超过8个扇区后,要重新分配新的簇,其过程如下:
if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */
clst = create_chain(fp->fs, fp->curr_clust);跟踪进去看一看。
fp->curr_clust = clst; /* Update current cluster */
fp->csect = 0; 执行后分配到19号簇,当前簇指向它,相对扇区号清零,因为在新的簇开始写数据。
刚刚这个文件写了9个扇区的数据,超过了一个簇,再读一读看看,的确是刚刚写入的数据。可以说,写文件命令成功完成。
4、改变模式,以写和创建新文件的模式写文件
文章评论(0条评论)
登录后参与讨论