OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7190|回复: 22

STM32F407单片机通过FATFS文件系统写SD卡正确率只有98%,但是偶而出错,该如何彻底根治

[复制链接]

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2021-4-8 11:32:28 | 显示全部楼层 |阅读模式
20金钱
我的单片机每隔10分钟自动重启(有重启电路,每次大概运行2分钟,运行完毕,自动关闭电源,下个整点到时,自动重启)。

      每次运行时,先采集三路模拟量数据,然后将采集的模拟量数据写到SD卡,每个模拟量数据写一行,3个模拟量数据写三行。
经过长期运行观察,正确写SD卡的成功率达到98%,但是始终有2%的错误,发现偶而出现如下四种错误现象。

      1、有时候SD卡的文件中会漏写三行。(注:共采集三路模拟量数据,每路模拟量数据写一行,3路模拟量数据写三行)
                即:该次的数据没有被写到SD卡的文件中。
      2、有时候SD卡的文件中会漏写二行。(注:共采集三路模拟量数据,每路模拟量数据写一行,3路模拟量数据写三行)
                即:该次的数据只有一路模拟量被写到SD卡的文件中,另外二路没有被写到SD卡的文件中。
      3、有时候SD卡的文件中会漏写一行。(注:共采集三路模拟量数据,每路模拟量数据写一行,3路模拟量数据写三行)
                即:该次的数据只有二路模拟量被写到SD卡的文件中,另外一路没有被写到SD卡的文件中。   
      4、有时候创建的文件不能写入数据到文件中,该文件是个空文件,拨掉SD卡,插入电脑插口,只要拷贝该空文件到电脑上,就报错。



  1. /*********************************************************************************************************
  2. *        说    明 : 本例程移植FatFS文件系统(版本 R0.09b)
  3. *********************************************************************************************************/
  4. void PRINT_FileFatFS(void)
  5. {
  6.         FRESULT result;
  7.         FATFS fs;
  8.         FIL file;
  9.         DIR DirInf;
  10.         uint32_t bw;
  11.         uint32_t fil_size;
  12.         char FileName[50];
  13.        
  14.        
  15.         if (!GPIO_SD_READY())
  16.         {
  17.                 //printf("插槽中没有插入SD卡\r\n");
  18.                 return ;
  19.         }
  20.        
  21.         /* 挂载文件系统 */
  22.         result = f_mount(FS_SD, &fs);                /* Mount a logical drive */
  23.         if (result != FR_OK)
  24.         {
  25.                 //printf("挂载文件系统失败 (%d)\r\n", result);
  26.                 return ;
  27.         }

  28.         /* 打开根文件夹 */
  29.         result = f_opendir(&DirInf, "/");         /* 如果不带参数,则从当前目录开始 */
  30.         if (result != FR_OK)
  31.         {
  32.                 //printf("打开根目录失败 (%d)\r\n");
  33.                 /* 卸载文件系统 */
  34.                 f_mount(FS_SD, NULL);
  35.                 return ;
  36.         }

  37.        
  38.         /* 打开文件 */       

  39.                         strcpy(FileName ,"TEST.csv");
  40.                         result = f_open(&file, FileName, FA_OPEN_ALWAYS | FA_WRITE);

  41.        
  42.         if (result == FR_OK)
  43.         {
  44.                 fil_size = f_size(&file);
  45.                 result = f_lseek(&file,fil_size);
  46.                 if (result == FR_OK)
  47.                 {               
  48.                         Printf_FATFS_COM_Buffer(enum_COM1_CHANNEL_NO);      //生成第一路模拟量数据
  49.                         result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);        //往SD卡写第一路模拟量数据                               
  50.                        
  51.                         Printf_FATFS_COM_Buffer(enum_COM2_CHANNEL_NO);    //生成第二路模拟量数据
  52.                         result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);  //往SD卡写第二路模拟量数据

  53.                        
  54.                         Printf_FATFS_COM_Buffer(enum_COM3_CHANNEL_NO);   //生成第三路模拟量数据
  55.                         result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw); //往SD卡写第三路模拟量数据
  56.                 }//if (result == FR_OK)
  57.         }//if (result == FR_OK)
  58.        
  59.         /* 关闭文件*/
  60.         f_close(&file);
  61.         /* 卸载文件系统 */
  62.         f_mount(FS_SD, NULL);
  63. }
复制代码



下面是SD卡底层移植函数
  1. /**************************************************************************************/
  2. //SD卡SPI驱动程序
  3. /**************************************************************************************/
  4. #include "MMC_SD.h"
  5. #include "BSP_SPI.h"



  6. u8  SD_Type=0;//SD卡的类型



  7. //SD卡初始化的时候,需要低速
  8. void SD_SPI_SpeedLow(void)
  9. {
  10.         //SPI2_SetSpeed(SPI_BaudRatePrescaler_256);//设置到低速模式
  11.         SPI1_SetSpeed(enum_SPI_SPEED_LOW);
  12. }



  13. //SD卡正常工作的时候,可以配置为高速
  14. void SD_SPI_SpeedHigh(void)
  15. {
  16.         //SPI1_SetSpeed(SPI_BaudRatePrescaler_8);//设置到高速模式
  17.         SPI1_SetSpeed(enum_SPI_SPEED_HIGH);
  18. }



  19. //取消选择,释放SPI总线
  20. void SD_DisSelect(void)
  21. {
  22.         GPIO_SetBits(GPIOA,GPIO_Pin_4);
  23.         SPI_WriteByte(0xff);//提供额外的8个时钟
  24. }



  25. //选择sd卡,并且等待卡准备OK
  26. //返回值:0,成功;1,失败;
  27. u8 SD_Select(void)
  28. {
  29.         GPIO_ResetBits(GPIOA,GPIO_Pin_4);
  30.         if(SD_WaitReady()==0)return 0;//等待成功
  31.         SD_DisSelect();
  32.         return 1;//等待失败
  33. }



  34. //等待卡准备好
  35. //返回值:0,准备好了;其他,错误代码
  36. u8 SD_WaitReady(void)
  37. {
  38.         u32 t=0;
  39.         do
  40.         {
  41.                 if (SPI_ReadByte()==0XFF)return 0;//OK
  42.                 t++;
  43.         }while(t<0XFFF);//等待
  44.         return 1;
  45. }



  46. //等待SD卡回应
  47. //Response:要得到的回应值
  48. //返回值:0,成功得到了该回应值
  49. //    其他,得到回应值失败
  50. u8 SD_GetResponse(u8 Response)
  51. {
  52.         u16 Count=0xFFFF;//等待次数
  53.         while ((SPI_ReadByte()!=Response) && Count) Count--;//等待得到准确的回应(等待得到读取数据令牌0xfe)
  54.         if (Count==0)
  55.                 return MSD_RESPONSE_FAILURE;        //得到回应失败
  56.         else
  57.                 return MSD_RESPONSE_NO_ERROR;        //正确回应
  58. }



  59. //从sd卡读取一个数据包的内容
  60. //buf:数据缓存区
  61. //len:要读取的数据长度.
  62. //返回值:0,成功;其他,失败;
  63. u8 SD_RecvData(u8*buf,u16 len)
  64. {
  65.         if (SD_GetResponse(0xFE)) return 1;//等待SD卡发回数据起始令牌0xFE
  66.         while(len--)//开始接收数据
  67.         {
  68.                 *buf=SPI_ReadByte();
  69.                 buf++;
  70.         }
  71.         //下面是2个伪CRC(dummy CRC)
  72.         SPI_WriteByte(0xFF);
  73.         SPI_WriteByte(0xFF);
  74.         return 0;//读取成功
  75. }



  76. //向sd卡写入一个数据包的内容 512字节
  77. //buf:数据缓存区
  78. //cmd:指令
  79. //返回值:0,成功;其他,失败;
  80. u8 SD_SendBlock(u8*buf,u8 cmd)
  81. {
  82.         u16 t;
  83.         if(SD_WaitReady())return 1;//等待准备失效
  84.         SPI_WriteByte(cmd);
  85.         if(cmd!=0XFD)//不是结束指令
  86.         {
  87.                 for(t=0; t<512; t++)SPI_WriteByte(buf[t]); //提高速度,减少函数传参时间
  88.                 SPI_WriteByte(0xFF);//忽略crc
  89.                 SPI_WriteByte(0xFF);
  90.                 t=SPI_ReadByte();//接收响应
  91.                 if((t&0x1F)!=0x05)return 2;//响应错误
  92.         }
  93.         return 0;//写入成功
  94. }



  95. //向SD卡发送一个命令
  96. //输入: u8 cmd   命令
  97. //      u32 arg  命令参数
  98. //      u8 crc   crc校验值
  99. //返回值:SD卡返回的响应
  100. u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
  101. {
  102.         u8 r1;
  103.         u8 Retry=0;
  104.        
  105.         SD_DisSelect();//取消上次片选
  106.         if(SD_Select())return 0XFF;//片选失效
  107.         //发送
  108.         SPI_WriteByte(cmd | 0x40);//分别写入命令
  109.         SPI_WriteByte(arg >> 24);
  110.         SPI_WriteByte(arg >> 16);
  111.         SPI_WriteByte(arg >> 8);
  112.         SPI_WriteByte(arg);
  113.         SPI_WriteByte(crc);
  114.         if(cmd==CMD12)SPI_WriteByte(0xff);//Skip a stuff byte when stop reading
  115.         //等待响应,或超时退出

  116.         Retry=0X1F;
  117.         do
  118.         {
  119.                 r1=SPI_ReadByte();
  120.         }
  121.         while((r1&0X80) && Retry--);
  122.         //返回状态值
  123.         return r1;
  124. }



  125. //获取SD卡的CID信息,包括制造商信息
  126. //输入: u8 *cid_data(存放CID的内存,至少16Byte)
  127. //返回值:0:NO_ERR
  128. //                 1:错误
  129. u8 SD_GetCID(u8 *cid_data)
  130. {
  131.         u8 r1;
  132.         //发CMD10命令,读CID
  133.         r1=SD_SendCmd(CMD10,0,0x01);
  134.         if(r1==0x00)
  135.         {
  136.                 r1=SD_RecvData(cid_data,16);//接收16个字节的数据
  137.         }
  138.         SD_DisSelect();//取消片选
  139.         if(r1)return 1;
  140.         else return 0;
  141. }



  142. //获取SD卡的CSD信息,包括容量和速度信息
  143. //输入:u8 *cid_data(存放CID的内存,至少16Byte)
  144. //返回值:0:NO_ERR
  145. //                 1:错误
  146. u8 SD_GetCSD(u8 *csd_data)
  147. {
  148.         u8 r1;
  149.         r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD
  150.         if(r1==0)
  151.         {
  152.                 r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
  153.         }
  154.         SD_DisSelect();//取消片选
  155.         if(r1)return 1;
  156.         else return 0;
  157. }



  158. //获取SD卡的总扇区数(扇区数)
  159. //返回值:0: 取容量出错
  160. //       其他:SD卡的容量(扇区数/512字节)
  161. //每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
  162. u32 SD_GetSectorCount(void)
  163. {
  164.         u8 csd[16];
  165.         u32 Capacity;
  166.         u8 n;
  167.         u16 csize;
  168.         //取CSD信息,如果期间出错,返回0
  169.         if(SD_GetCSD(csd)!=0) return 0;
  170.         //如果为SDHC卡,按照下面方式计算
  171.         if((csd[0]&0xC0)==0x40)         //V2.00的卡
  172.         {
  173.                 csize = csd[9] + ((u16)csd[8] << 8) + 1;
  174.                 Capacity = (u32)csize << 10;//得到扇区数
  175.         }
  176.         else //V1.XX的卡
  177.         {
  178.                 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
  179.                 csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
  180.                 Capacity= (u32)csize << (n - 9);//得到扇区数
  181.         }
  182.         return Capacity;
  183. }



  184. //初始化SD卡
  185. u8 SD_Initialize(void)
  186. {
  187.         u8 r1;      // 存放SD卡的返回值
  188.         u16 retry;  // 用来进行超时计数
  189.         u8 buf[4];
  190.         u16 i;
  191.        

  192.         SPI1_Configuration();
  193.         SD_SPI_SpeedLow();        //设置到低速模式               

  194.         for(i=0; i<15; i++)SPI_WriteByte(0XFF); //发送最少74个脉冲
  195.         retry=2000;
  196.         do
  197.         {
  198.                 r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
  199.         }
  200.         while((r1!=0X01) && retry--);
  201.         SD_Type=0;//默认无卡
  202.         if(r1==0X01)
  203.         {
  204.                 if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
  205.                 {
  206.                         for(i=0; i<4; i++)buf[i] = SPI_ReadWriteByte(0XFF);        //Get trailing return value of R7 resp
  207.                         if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
  208.                         {
  209.                                 retry=0XFFFE;
  210.                                 do
  211.                                 {
  212.                                         SD_SendCmd(CMD55,0,0X01);        //发送CMD55
  213.                                         r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
  214.                                 }
  215.                                 while(r1&&retry--);
  216.                                 if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
  217.                                 {
  218.                                         for(i=0; i<4; i++)buf[i] = SPI_ReadWriteByte(0XFF); //得到OCR值
  219.                                         if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCS
  220.                                         else SD_Type=SD_TYPE_V2;
  221.                                 }
  222.                         }
  223.                 }
  224.                 else //SD V1.x/ MMC        V3
  225.                 {
  226.                         SD_SendCmd(CMD55,0,0X01);                //发送CMD55
  227.                         r1=SD_SendCmd(CMD41,0,0X01);        //发送CMD41
  228.                         if(r1<=1)
  229.                         {
  230.                                 SD_Type=SD_TYPE_V1;
  231.                                 retry=0XFFFE;
  232.                                 do //等待退出IDLE模式
  233.                                 {
  234.                                         SD_SendCmd(CMD55,0,0X01);        //发送CMD55
  235.                                         r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
  236.                                 }
  237.                                 while(r1&&retry--);
  238.                         }
  239.                         else
  240.                         {
  241.                                 SD_Type=SD_TYPE_MMC;//MMC V3
  242.                                 retry=0XFFFE;
  243.                                 do //等待退出IDLE模式
  244.                                 {
  245.                                         r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
  246.                                 }
  247.                                 while(r1&&retry--);
  248.                         }
  249.                         if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
  250.                 }
  251.         }
  252.         SD_DisSelect();//取消片选
  253.         SD_SPI_SpeedHigh();//SPI配置为高速模式
  254.        
  255.         if (SD_Type)
  256.                 return 0;
  257.         else if(r1)
  258.                 return r1;
  259.         return (0xaa);//其他错误
  260. }



  261. //读SD卡
  262. //buf:数据缓存区
  263. //sector:扇区
  264. //cnt:扇区数
  265. //返回值:0,ok;其他,失败.
  266. u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
  267. {
  268.         u8 r1;
  269.         if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
  270.         if(cnt==1)
  271.         {
  272.                 r1=SD_SendCmd(CMD17,sector,0X01);//读命令
  273.                 if(r1==0)//指令发送成功
  274.                 {
  275.                         r1=SD_RecvData(buf,512);//接收512个字节
  276.                 }
  277.         }
  278.         else
  279.         {
  280.                 r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
  281.                 do
  282.                 {
  283.                         r1=SD_RecvData(buf,512);//接收512个字节
  284.                         buf+=512;
  285.                 }
  286.                 while(--cnt && r1==0);
  287.                 SD_SendCmd(CMD12,0,0X01);        //发送停止命令
  288.         }
  289.         SD_DisSelect();//取消片选
  290.         return r1;//
  291. }



  292. //写SD卡
  293. //buf:数据缓存区
  294. //sector:起始扇区
  295. //cnt:扇区数
  296. //返回值:0,ok;其他,失败.
  297. u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
  298. {
  299.         u8 r1;
  300.         if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址
  301.         if(cnt==1)
  302.         {
  303.                 r1=SD_SendCmd(CMD24,sector,0X01);//读命令
  304.                 if(r1==0)//指令发送成功
  305.                 {
  306.                         r1=SD_SendBlock(buf,0xFE);//写512个字节
  307.                 }
  308.         }
  309.         else
  310.         {
  311.                 if(SD_Type!=SD_TYPE_MMC)
  312.                 {
  313.                         SD_SendCmd(CMD55,0,0X01);
  314.                         SD_SendCmd(CMD23,cnt,0X01);//发送指令
  315.                 }
  316.                 r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令
  317.                 if(r1==0)
  318.                 {
  319.                         do
  320.                         {
  321.                                 r1=SD_SendBlock(buf,0xFC);//接收512个字节
  322.                                 buf+=512;
  323.                         }
  324.                         while(--cnt && r1==0);
  325.                         r1=SD_SendBlock(0,0xFD);//接收512个字节
  326.                 }
  327.         }
  328.         SD_DisSelect();//取消片选
  329.        
  330.         return r1;//
  331. }
复制代码


下面是SPI硬件中断配置
  1. void SPI1_Configuration(void)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         SPI_InitTypeDef SPI_InitStructure;

  5.        
  6.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

  8.         GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
  9.         GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
  10.         GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
  11.        
  12.         //Configure SPI1 Pins: SCK, MISO and MOSI
  13.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  14.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       
  15.         GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
  16.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  17.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.           GPIO_Init(GPIOA, &GPIO_InitStructure);
  19.        
  20.         //Configure NSS Pin
  21.         //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  22.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  23.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       
  24.         GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
  25.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                //CS/NSS
  26.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  27.           GPIO_Init(GPIOA, &GPIO_InitStructure);
  28.         GPIO_SetBits(GPIOA, GPIO_Pin_4);//不选中(关闭片选)--->低电平选通SD卡

  29.         SPI_I2S_DeInit(SPI1);
  30.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);        //复位SPI1
  31.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1
  32.        
  33.         SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;        //双线双向全双工
  34.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //主器件
  35.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;        //8位数据长度
  36.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                   //这里要注意,一定要配置为上升沿数据有效,因为SD卡为上升沿数据有效
  37.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                //这里要注意,一定要配置为SPI_CPHA_2Edge(数据捕获于第2个时钟沿),参见SD卡协议要求
  38.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                        //NSS信号由外部管脚管理
  39.         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//SPI速度为低速
  40.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //数据传输的第一个字节为MSB
  41.         SPI_InitStructure.SPI_CRCPolynomial = 7;                        //CRC的多项式
  42.         SPI_Init(SPI1,&SPI_InitStructure);
  43.         SPI_Cmd(SPI1,DISABLE);
  44.         SPI_Cmd(SPI1,ENABLE);
  45.        
  46.        
  47. }



  48. //SPI 速度设置函数
  49. //SpeedSet:
  50. //SPI_BaudRatePrescaler_2   2分频   (SPI 36M[url=home.php?mod=space&uid=19210]@sys[/url] 72M)
  51. //SPI_BaudRatePrescaler_8   8分频   (SPI 9M@sys 72M)
  52. //SPI_BaudRatePrescaler_16  16分频  (SPI 4.5M@sys 72M)
  53. //SPI_BaudRatePrescaler_256 256分频 (SPI 281.25K@sys 72M)
  54. void SPI1_SetSpeed(uint8_t SpeedSet)
  55. {
  56.        
  57.     SPI_InitTypeDef SPI_InitStructure;

  58.        
  59.         SPI_I2S_DeInit(SPI1);
  60.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);        //复位SPI1
  61.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1
  62.         SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;        //双线双向全双工
  63.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //主器件
  64.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;        //8位数据长度
  65.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                   //这里要注意,一定要配置为上升沿数据有效,因为SD卡为上升沿数据有效
  66.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                //这里要注意,一定要配置为SPI_CPHA_2Edge(数据捕获于第2个时钟沿),参见SD卡协议要求
  67.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                        //NSS信号由外部管脚管理

  68.         switch (SpeedSet)
  69.         {
  70.                 case enum_SPI_SPEED_LOW:                       
  71.                         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//设置到低速模式
  72.                         break;
  73.                 case enum_SPI_SPEED_HIGH:
  74.                         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;        //设置到高速模式
  75.                         break;       
  76.                 default:
  77.                         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//设置到低速模式
  78.                         break;                       
  79.         }

  80.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //数据传输的第一个字节为MSB               
  81.         SPI_InitStructure.SPI_CRCPolynomial = 7;                        //CRC的多项式
  82.         SPI_Init(SPI1,&SPI_InitStructure);
  83.         SPI_Cmd(SPI1 , DISABLE);
  84.         SPI_Cmd(SPI1 , ENABLE);
  85. }



  86. void SPI_WriteByte(uint8_t _ucByte)
  87. {
  88.         while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE )==RESET);        //等待数据发送寄存器清空
  89.         SPI_I2S_SendData(SPI1 , _ucByte);                                                                //通过SPI发送出去一个字节数据
  90.         while(SPI_I2S_GetFlagStatus(SPI1 , SPI_I2S_FLAG_RXNE )==RESET);        //等待接收到一个数据(接收到一个数据就相当于发送一个数据完毕)
  91.         SPI_I2S_ReceiveData(SPI1);                                                                                //返回接收到的数据
  92. }



  93. uint8_t SPI_ReadByte(void)
  94. {
  95.         uint8_t ch;
  96.        
  97.        
  98.         while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE )==RESET);
  99.         SPI_I2S_SendData(SPI1 , 0xFF);
  100.         while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE )==RESET);
  101.         ch = SPI_I2S_ReceiveData(SPI1);
  102.         return (ch);
  103. }



  104. uint8_t SPI_ReadWriteByte(uint8_t _ucByte)
  105. {  
  106.         uint8_t ch;
  107.        
  108.        
  109.         while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);                // 等待发送缓冲区空
  110.         SPI_I2S_SendData(SPI1, _ucByte);
  111.         while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);                // 等待数据接收完毕
  112.         ch = SPI_I2S_ReceiveData(SPI1);
  113.         return (ch);
  114. }
复制代码


最佳答案

查看完整内容[请看2#楼]

解决方法:[/backcolor] 对程序进行如下改造:[/backcolor] 1、第一步:[/backcolor] 挂载文件系统[/backcolor] 2、第二步:[/backcolor] 打开根目录[/backcolor] 3、第三步:[/backcolor] 打开文件[/backcolor] 4、第四步[/backcolor] 移动文件指针到文件尾[/backcolor] 5、第五步:[/backcolor] 写第一行数据,延时一段时间[/ ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-8 11:32:29 | 显示全部楼层
解决方法:    对程序进行如下改造:
     1、第一步:
          挂载文件系统
      2、第二步:
           打开根目录
      3、第三步:
           打开文件
      4、第四步
           移动文件指针到文件尾
     5、第五步:
             写第一行数据,延时一段时间
     6、第六步:
             写第二行数据,延时一段时间
     7、第七步:
             写第三行数据



   经过上述处理,没有再出现之前的情况,搞不懂,为什么打开文件写完第一行332字节之后,必须要延时一点时间才能写第二行332个字节呢?



void PRINT_TemperatureFatFS(uint8_t mode)
{
        char FileName[50];
      
      
        /* 挂载文件系统 */
        result = f_mount(FS_SD, &fs);                /* Mount a logical drive */
        if (result != FR_OK)
        {
                //printf("挂载文件系统失败 (%d)\r\n", result);

                I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE1-1]++;        //记录FATFS 挂载文件系统失败次数到I2C芯片中存储
                AT24C512_Write_configuration_PARAMETERS();
                return ;
        }

        /* 打开根文件夹 */
        result = f_opendir(&DirInf, "/");         /* 如果不带参数,则从当前目录开始 */
        if (result != FR_OK)
        {
                //printf("打开根目录失败 (%d)\r\n");
                /* 卸载文件系统 */
                I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE2-1]++;        //记录FATFS 打开根文件夹失败次数到I2C芯片中存储
                AT24C512_Write_configuration_PARAMETERS();
                /* 卸载文件系统 */
                f_mount(FS_SD, NULL);               
                return ;
        }

      
        /* 打开文件 */      
        sprintf(FileName ,"B082-%02X%02X%02X%02X%02X%02X.csv"                ,MAC_ADDRESS_Buffer[0] , MAC_ADDRESS_Buffer[1] , MAC_ADDRESS_Buffer[2] , MAC_ADDRESS_Buffer[3] , MAC_ADDRESS_Buffer[4] , MAC_ADDRESS_Buffer[5]);
        result = f_open(&file, FileName, FA_OPEN_ALWAYS | FA_WRITE);

      
      
        if (result != FR_OK)
        {
                I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE3-1]++;        //记录FATFS 打开文件失败次数到I2C芯片中存储
                AT24C512_Write_configuration_PARAMETERS();
                /* 卸载文件系统 */
                f_mount(FS_SD, NULL);
                return ;
        }
      
        fil_size = f_size(&file);
        result = f_lseek(&file,fil_size);
        if (result != FR_OK)
        {
                I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE4-1]++;        //记录FATFS 移动文件指针到文件尾失败次数到I2C芯片中存储
                AT24C512_Write_configuration_PARAMETERS();
                /* 关闭文件*/
                f_close(&file);
                /* 卸载文件系统 */
                f_mount(FS_SD, NULL);
                return ;
        }
      


        result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);
        if (result != FR_OK)
        {
                I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE5-1]++;        //记录FATFS 写第一行数据时出错次数到I2C芯片中存储
                AT24C512_Write_configuration_PARAMETERS();
                /* 关闭文件*/
                f_close(&file);
                /* 卸载文件系统 */
                f_mount(FS_SD, NULL);
                return ;
        }
      
        WatchDog_Delay(50000);   //必须要增加延时

        result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);
        if (result != FR_OK)
        {
                I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE6-1]++;        //记录FATFS 写第二行数据时出错次数到I2C芯片中存储
                AT24C512_Write_configuration_PARAMETERS();
                /* 关闭文件*/
                f_close(&file);
                /* 卸载文件系统 */
                f_mount(FS_SD, NULL);
                return ;
        }
      
WatchDog_Delay(50000);   //必须要增加延时

        result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);
        if (result != FR_OK)
        {
                I2C_SUN_BATTERY_Buffer[I2C_SUN_SPARE1-1]++;        //记录FATFS 写第三行数据时出错次数到I2C芯片中存储
                AT24C512_Write_SUN_BATTERY_PARAMETERS();
                /* 关闭文件*/
                f_close(&file);
                /* 卸载文件系统 */
                f_mount(FS_SD, NULL);
                return ;
        }

      
        /* 关闭文件*/
        f_close(&file);
        /* 卸载文件系统 */
        f_mount(FS_SD, NULL);
      
}



回复

使用道具 举报

12

主题

3344

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8465
金钱
8465
注册时间
2020-5-11
在线时间
3904 小时
发表于 2021-4-8 13:16:44 | 显示全部楼层
result = f_write 这里监测一下result看看,再看看文件字节数是否能对上,会不会写入的数据中有0导致读出时有遗漏。
专治疑难杂症
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-8 15:24:16 | 显示全部楼层
本帖最后由 霸王猫 于 2021-4-8 15:26 编辑

我怀疑是由于单片机堆栈空间分配不足造成的,原因是FATFS文件系统太占用空间啦.

                             不应该把    FATFS fs;   FIL file;   定义成局部变量,而应该定义成全局变量。


    1、我的单片机工程项目堆栈分配了800个WORD,参见下图。


   2、FATFS的FIL结构体太占用空间啦!我有2个写SD卡的函数,每个函数都在内部定义了局部变量 FIL file;

                        
   3、FATFS的FATFS结构体太占用空间啦!我有2个写SD卡的函数,每个函数都在内部定义了局部变量 FATFS fs;

   4、函数1

   5、函数2


  6、MAX_SS分配了512字节



回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-8 15:29:00 | 显示全部楼层
本帖最后由 霸王猫 于 2021-4-8 15:30 编辑

我怀疑是由于单片机堆栈空间分配不足造成的,原因是FATFS文件系统太占用空间啦.

                             不应该把    FATFS fs;   FIL file;   定义成局部变量,而应该定义成全局变量。


    1、我的单片机工程项目堆栈分配了800个WORD,参见下图。
STACK.png

   2、FATFS的FIL结构体太占用空间啦!我有2个写SD卡的函数,每个函数都在内部定义了局部变量 FIL file;
FIL.png
                        
   3、FATFS的FATFS结构体太占用空间啦!我有2个写SD卡的函数,每个函数都在内部定义了局部变量 FATFS fs;
FATFS.png
   4、函数1
函数1.png
   5、函数2
函数2.png

  6、MAX_SS分配了512字节
MAX_SS.png
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-8 15:56:52 | 显示全部楼层
我把    FATFS fs;   FIL file;  该定义成全局变量   观察一个星期试试,同时我把SD卡读写的每个环节都进行监视,如果某个环节出现错误,我会把错误次数记录到I2C芯片中,一个星期后,我通过读I2C芯片的读数就可以知道是否彻底根治了没有。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2021-4-9 02:06:10 | 显示全部楼层
不间隔休眠,会不会出错,感觉出错可能是因为你的10分钟重启导致的
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-9 08:49:57 | 显示全部楼层
正点原子 发表于 2021-4-9 02:06
不间隔休眠,会不会出错,感觉出错可能是因为你的10分钟重启导致的

版主,你理解错啦!不是不间隔休眠,是单片机和外围设备全断电,只是板子上外挂的一块RTC实时时钟有电,当倒计时时间到时,RTC实时时钟触发低电平,让单片机重新上电。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2021-4-10 01:56:40 | 显示全部楼层
霸王猫 发表于 2021-4-9 08:49
版主,你理解错啦!不是不间隔休眠,是单片机和外围设备全断电,只是板子上外挂的一块RTC实时时钟有电, ...

我是说你断电的时候,可能文件存储没处理好。
导致数据丢失,你不断电看看还丢失不?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-10 10:19:04 | 显示全部楼层
正点原子 发表于 2021-4-10 01:56
我是说你断电的时候,可能文件存储没处理好。
导致数据丢失,你不断电看看还丢失不?

   我写完文件后,还要将数据发送到服务器(如果服务器无应答,还要等待30秒),然后再等待25秒(目的是等待GPS信号稳定,GPS信号稳定后,用GPS的的年月日时分秒来校准RTC时钟芯片的时间),最后单片机才断电。
        所以不存在【我是说你断电的时候,可能文件存储没处理好。导致数据丢失】
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-12 14:03:30 | 显示全部楼层
本帖最后由 霸王猫 于 2021-4-12 14:39 编辑

经过3天的运行,发现不是堆栈的原因。

    我对写SD卡的所有文件系统操作相关部分都添加追踪记录方面的代码,只有发现操作失败(result != FR_OK)一次就记录一次到I2C芯片(AT24C02)中。

            我对文件系统以下操作部分添加了追踪代码,发现这部分代码错误一次,就记录一次到I2C芯片(AT24C02)中。

  1.   1、         /* 挂载文件系统 */
  2.         result = f_mount(FS_SD, &fs);                /* Mount a logical drive */

  3.     2、        /* 打开根文件夹 */
  4.         result = f_opendir(&DirInf, "/");         /* 如果不带参数,则从当前目录开始 */

  5.     3、   /* 打开文件 */        
  6.             result = f_open(&file, FileName, FA_OPEN_ALWAYS | FA_WRITE);

  7.     4、/*移动文件指针*/
  8.                      fil_size = f_size(&file);
  9.         result = f_lseek(&file,fil_size);

  10.     5、/*写数据到文件*/
  11.          result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);
复制代码

结果连续运行3天(每小时写6次,1天写144次,3天写432次),结果发现如下规律,总共错误11次,错误都发生在FATFS文件系统【5./*写数据到文件(/】这一步,其它4种情况从来都没有出过错。



          也就是说, 1、 /* 挂载文件系统 */
                            2、/* 打开根文件夹 */
                        3、 /* 打开文件 */
                       4、/*移动文件指针*/
                从来都不会发生错误
                      错误只出现在  5、/*写数据到文件*/


           我就搞不懂了,我每次只写332个字节,没有超出FATFS的缺省长度(512)呀?怎么会单单错在5、/*写数据到文件*/ 这一步呢?


    以下是SD卡文件中缺失的数据(注:单片机每次向SD卡文件中写三行数据)
2021.04.08   21:50  SD卡文件中缺失 第二行数据
                                 SD卡文件中缺失 第三行数据


   2021.04.09   00:20  SD卡文件中缺失 第三行数据
   2021.04.09   03:00 SD卡文件中缺失 第三行数据
   2021.04.09   06:40 SD卡文件中缺失 第三行数据


   2021.04.09   08:00 SD卡文件中缺失 第一行数据
   2021.04.09   08:00 SD卡文件中缺失 第二行数据
   2021.04.09   08:00 SD卡文件中缺失 第三行数据


2021.04.09   10:30 SD卡文件中缺失 第三行数据

2021.04.12   10:30 SD卡文件中缺失 第二行数据
2021.04.12   10:30 SD卡文件中缺失 第三行数据

回复

使用道具 举报

2

主题

255

帖子

0

精华

高级会员

Rank: 4

积分
823
金钱
823
注册时间
2013-6-5
在线时间
142 小时
发表于 2021-4-13 17:44:11 | 显示全部楼层
本帖最后由 zhxzhx 于 2021-4-13 17:48 编辑

你写完的文件关闭了吗?不关闭数据还在缓冲区里。
最好挂载的系统也注销了
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-13 19:05:37 | 显示全部楼层
zhxzhx 发表于 2021-4-13 17:44
你写完的文件关闭了吗?不关闭数据还在缓冲区里。
最好挂载的系统也注销了

我写完文件关闭了,同时还注销了挂载的系统。

  1.       /* 关闭文件*/
  2.         f_close(&file);
  3.         /* 卸载文件系统 */
  4.         f_mount(FS_SD, NULL);
复制代码
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2021-4-13 20:55:44 | 显示全部楼层
本帖最后由 nashui_sx 于 2021-4-13 20:58 编辑
霸王猫 发表于 2021-4-13 19:05
我写完文件关闭了,同时还注销了挂载的系统。

假如你板子上有外部flash  写到flash的文件系统试试,排除下sd的问题   写flash的txt也有问题那就是你代码问题了,没问题那就是sd卡硬件及电路问题了
还有就是写sd卡的数据处理成字符串的代码会不会有bug,把写sd卡的三行数据用个固定的字符串数组试试

回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2021-4-14 01:46:22 | 显示全部楼层
霸王猫 发表于 2021-4-12 14:03
经过3天的运行,发现不是堆栈的原因。

    我对写SD卡的所有文件系统操作相关部分都添加追踪记录方面的 ...

建议一次写512字节,或者其整数倍。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-15 09:57:47 | 显示全部楼层
nashui_sx 发表于 2021-4-13 20:55
假如你板子上有外部flash  写到flash的文件系统试试,排除下sd的问题   写flash的txt也有问题那就是你代 ...

我现在固定写三行同样的字符串,字符串长度为512,字符串为512个“1”,再运行3天观察。

   
   下面是我改造后的程序,只有有FATFS文件系统返回值的地方都进行了监控,只要发生错误,就将错误次数记录到I2C中保存,便于查看到底是在哪里出错啦。


  1. void PRINT_TemperatureFatFS(uint8_t mode)
  2. {
  3.         char FileName[50];
  4.        
  5.        
  6.         /* 挂载文件系统 */
  7.         result = f_mount(FS_SD, &fs);                /* Mount a logical drive */
  8.         if (result != FR_OK)
  9.         {
  10.                 //printf("挂载文件系统失败 (%d)\r\n", result);

  11.                 I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE1-1]++;        //记录FATFS 挂载文件系统失败次数到I2C芯片中存储
  12.                 AT24C512_Write_configuration_PARAMETERS();
  13.                 return ;
  14.         }

  15.         /* 打开根文件夹 */
  16.         result = f_opendir(&DirInf, "/");         /* 如果不带参数,则从当前目录开始 */
  17.         if (result != FR_OK)
  18.         {
  19.                 //printf("打开根目录失败 (%d)\r\n");
  20.                 /* 卸载文件系统 */
  21.                 I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE2-1]++;        //记录FATFS 打开根文件夹失败次数到I2C芯片中存储
  22.                 AT24C512_Write_configuration_PARAMETERS();
  23.                 /* 卸载文件系统 */
  24.                 f_mount(FS_SD, NULL);               
  25.                 return ;
  26.         }

  27.        
  28.         /* 打开文件 */       
  29.         sprintf(FileName ,"B082-%02X%02X%02X%02X%02X%02X.csv"                ,MAC_ADDRESS_Buffer[0] , MAC_ADDRESS_Buffer[1] , MAC_ADDRESS_Buffer[2] , MAC_ADDRESS_Buffer[3] , MAC_ADDRESS_Buffer[4] , MAC_ADDRESS_Buffer[5]);
  30.         result = f_open(&file, FileName, FA_OPEN_ALWAYS | FA_WRITE);

  31.        
  32.        
  33.         if (result != FR_OK)
  34.         {
  35.                 I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE3-1]++;        //记录FATFS 打开文件失败次数到I2C芯片中存储
  36.                 AT24C512_Write_configuration_PARAMETERS();
  37.                 /* 卸载文件系统 */
  38.                 f_mount(FS_SD, NULL);
  39.                 return ;
  40.         }
  41.        
  42.         fil_size = f_size(&file);
  43.         result = f_lseek(&file,fil_size);
  44.         if (result != FR_OK)
  45.         {
  46.                 I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE4-1]++;        //记录FATFS 移动文件指针到文件尾失败次数到I2C芯片中存储
  47.                 AT24C512_Write_configuration_PARAMETERS();
  48.                 /* 关闭文件*/
  49.                 f_close(&file);
  50.                 /* 卸载文件系统 */
  51.                 f_mount(FS_SD, NULL);
  52.                 return ;
  53.         }
  54.        


  55.         result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);
  56.         if (result != FR_OK)
  57.         {
  58.                 I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE5-1]++;        //记录FATFS 写第一行数据时出错次数到I2C芯片中存储
  59.                 AT24C512_Write_configuration_PARAMETERS();
  60.                 /* 关闭文件*/
  61.                 f_close(&file);
  62.                 /* 卸载文件系统 */
  63.                 f_mount(FS_SD, NULL);
  64.                 return ;
  65.         }
  66.        
  67.         WatchDog_Delay(50000);

  68.         result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);
  69.         if (result != FR_OK)
  70.         {
  71.                 I2C_PARAMETERS_Buffer[I2C_PARAMETERS_SPARE6-1]++;        //记录FATFS 写第二行数据时出错次数到I2C芯片中存储
  72.                 AT24C512_Write_configuration_PARAMETERS();
  73.                 /* 关闭文件*/
  74.                 f_close(&file);
  75.                 /* 卸载文件系统 */
  76.                 f_mount(FS_SD, NULL);
  77.                 return ;
  78.         }
  79.        
  80.         result = f_write(&file, FATFS_COM_Buffer , strlen(FATFS_COM_Buffer), &bw);
  81.         if (result != FR_OK)
  82.         {
  83.                 I2C_SUN_BATTERY_Buffer[I2C_SUN_SPARE1-1]++;        //记录FATFS 写第三行数据时出错次数到I2C芯片中存储
  84.                 AT24C512_Write_SUN_BATTERY_PARAMETERS();
  85.                 /* 关闭文件*/
  86.                 f_close(&file);
  87.                 /* 卸载文件系统 */
  88.                 f_mount(FS_SD, NULL);
  89.                 return ;
  90.         }

  91.        
  92.         /* 关闭文件*/
  93.         f_close(&file);
  94.         /* 卸载文件系统 */
  95.         f_mount(FS_SD, NULL);
  96.        
  97. }
复制代码
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-20 08:54:04 | 显示全部楼层
霸王猫 发表于 2021-4-15 09:57
我现在固定写三行同样的字符串,字符串长度为512,字符串为512个“1”,再运行3天观察。

   

还是会出现错误。

回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-4-20 08:59:13 | 显示全部楼层
继续对程序进行如下改造:
     1、第一步:
          挂载文件系统
      2、第二步:
           打开根目录
      3、第三步:
           打开文件
      4、第四步
           移动文件指针到文件尾
     5、第五步:
             写第一行数据,延时一段时间
     6、第六步:
             写第二行数据,延时一段时间
     7、第七步:
             写第三行数据

    继续连续运行观察3天


  




回复

使用道具 举报

0

主题

7

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
271
金钱
271
注册时间
2019-6-27
在线时间
56 小时
发表于 2021-4-20 13:38:42 | 显示全部楼层
关注一下跟进一下
回复

使用道具 举报

30

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
608
金钱
608
注册时间
2020-4-17
在线时间
111 小时
发表于 2021-4-20 14:15:37 | 显示全部楼层
三天三天又三天呀
回复

使用道具 举报

18

主题

41

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
420
金钱
420
注册时间
2016-9-2
在线时间
78 小时
发表于 2021-5-6 23:45:43 | 显示全部楼层
一个月过去啦,怎么样了楼主
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-5-10 17:24:37 | 显示全部楼层
熊大 发表于 2021-5-6 23:45
一个月过去啦,怎么样了楼主

我做了如下改进:

    1、写完第一行后,延时一段时间   WatchDog_Delay(50000);
    2、写完第二行后,延时一段时间   WatchDog_Delay(50000);
    3、写第三行

   又连续运行3天,没有发现任何错误。

      难道是写完第一行数据时,立即写第二行数据,文件系统反应不过来吗?
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-5-10 17:25:29 | 显示全部楼层
解决方法:    对程序进行如下改造:
     1、第一步:
          挂载文件系统
      2、第二步:
           打开根目录
      3、第三步:
           打开文件
      4、第四步
           移动文件指针到文件尾
     5、第五步:
             写第一行数据,延时一段时间
     6、第六步:
             写第二行数据,延时一段时间
     7、第七步:
             写第三行数据



   经过上述处理,连续3天没有再出现之前的情况,搞不懂,为什么打开文件写完第一行332字节之后,必须要延时一点时间才能写第二行332个字节呢?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 21:08

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表