OpenEdv-开源电子网

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

连续写sd卡总是会在20多个小时后死机

[复制链接]

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
发表于 2015-9-29 09:48:06 | 显示全部楼层 |阅读模式
5金钱
我在做将485收到的数据以625k大小的txt文件存到sd卡里面,可是总是死机。

#define  __SHOW_SD_PROCEDURE__

FIL File;
FIL* CreateNewFile(void)   //创建新文件
{
char FileName[16];
static int i = 0;
int mount = 0;     //为了检查哪里出错设置的标志位
    int open  = 0;    //同上
int lseek = 0;    //同上
    u8    res_mount  = 1;   //同上
u8    res_open   = 1;       //同上
u8    res_lseek  = 1;         //同上
char  CntBuf[64];

RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;

RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
    RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);

sprintf(FileName, "%02d%02d%02d%02d.txt",
       RTC_DateStruct.RTC_Date,
       RTC_TimeStruct.RTC_Hours,
       RTC_TimeStruct.RTC_Minutes,
       RTC_TimeStruct.RTC_Seconds);

loop: exfuns_init(); //为fatfs相关变量申请内存  
 usmart_dev.init(72);

 my_mem_init(SRAMIN); //初始化内部内存池
 SD_InitializeCards();
while(res_mount!=0)

if(mount > 5) 
{
sprintf(CntBuf, "f_mount = %d", res_mount);
            LCD_ShowString(60, 50, 210, 16, 16, CntBuf); 
goto loop;
}
res_mount = f_mount(fs[0], "0:", 1);
}   //注册工作区
while(res_open!=0)
{
if(open > 5) 
{
sprintf(CntBuf, "f_open = %d", res_open);
            LCD_ShowString(60, 80, 210, 16, 16, CntBuf); 
goto loop;
}
   res_open = f_open(&File, FileName, FA_OPEN_ALWAYS | FA_WRITE);
}
while(res_lseek!=0)
{
if( lseek > 5) 
{
sprintf(CntBuf, "f_lseek = %d", res_lseek);
            LCD_ShowString(60, 110, 210, 16, 16, CntBuf); 
goto loop;
}
   res_lseek = f_lseek(&File, 0);


#ifdef __SHOW_SD_PROCEDURE__
LCD_ShowString(60, 140, 210, 16, 16, FileName);
#endif

LCD_ShowString(60, 170, 210, 16, 16, " CreateNewFile = ");    
LCD_ShowNum(200, 170, ++i, 8, 16);  

return &File;
}

#define  FILE_BLOCK_CNT   100

int main(void) 
 {  
char  CntBuf[64];
int   FileBlockCnt = 0;
int   FileCnt      = 0;
FIL  *SDFile       = NULL;
     u8    res_close  = 1;
//-------------------------------
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
//-------------------------------  
delay_init(168);                                    // 初始化延时函数
uart_init(115200);                                // 初始化串口波特率为115200
LED_Init();                        // 初始化LED 
  LCD_Init();                        // LCD初始化  
RS485_Init(115200);                            // 初始化RS485串口2
    RTC_Set_WakeUp(RTC_WakeUpClock_CK_SPRE_16bits, 0);  // 配置WAKE UP中断,1秒钟中断一次
// //-----------------------------
    while(1)  
{
  
  if(QueueFullWithData)    // QueueFullWithData是在485中断里面设置的缓存区,当存够6400的数以后一次性赋值给QueueFullWithData
  {  
if(FileBlockCnt == 0)
   {
   SDFile = CreateNewFile();
   }
   
f_write(SDFile, QueueFullWithData, QUEUE_SIZE, (UINT*)&bw);
delay_ms(10);
  
LCD_ShowString(60, 200, 210, 16, 16, "Saved File Block = ");    
LCD_ShowNum(200, 200, ++FileBlockCnt, 8, 16);  

QueueFullWithData = NULL; 
  
  
   if(FileBlockCnt == FILE_BLOCK_CNT)   //在同一个文件内写100次,写够625k后关闭该文件,然后创建新文件
   {
while(res_close!=0)
{
res_close = f_close(SDFile);
   sprintf(CntBuf, "f_close = %d", res_close);
                     LCD_ShowString(60, 230, 210, 16, 16, CntBuf); 
}

FileBlockCnt = 0;
   LCD_ShowString(60, 260, 210, 16, 16, "Saved File Cnt = ");    
       LCD_ShowNum(200, 260, ++FileCnt, 8, 16);  
   } 
  }
}
}
 
在网上搜了以后说是SD时钟太快了,就把SD时钟改成了1Mhz,原来的是48Mhz,是将SDIO_TRANSFER_CLK_DIV改成0x30,可是还是会出错
if(SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V1_1||SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V2_0)
{
clkdiv=SDIO_TRANSFER_CLK_DIV+2; //V1.1/V2.0卡,设置最高48/4=12Mhz
}else clkdiv=SDIO_TRANSFER_CLK_DIV; //SDHC等其他卡,设置最高48/2=24Mhz
SDIO_Clock_Set(clkdiv); //设置时钟频率,SDIO时钟计算公式:SDIO_CK时钟=SDIOCLK/[clkdiv+2];其中,SDIOCLK固定为48Mhz 
//errorstatus=SD_SetDeviceMode(SD_DMA_MODE); //设置为DMA模式
errorstatus=SD_SetDeviceMode(SD_POLLING_MODE);//设置为查询模式
能帮忙看一下是什么问题造成的吗?

最佳答案

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

测试了三天,一直没有出现问题,在485.c里面添加了一段程序 [mw_shl_code=c,true]f(USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET) { USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR其实就是清除标志 USART_ReceiveData(USART2); //读DR }[/mw_shl_code] 可是如果溢出的话是进不到if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-9-29 09:48:07 | 显示全部楼层
测试了三天,一直没有出现问题,在485.c里面添加了一段程序
[mw_shl_code=c,true]f(USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET) { USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR其实就是清除标志 USART_ReceiveData(USART2); //读DR }[/mw_shl_code]


可是如果溢出的话是进不到if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)   ,等于加上上面的这段程序是进不去的 ,可是现在好了,也不知道是为什么
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2015-9-29 21:55:58 | 显示全部楼层
局部数组有点大.
试试不处理485数据,直接程序生成一个固定的字符串,模拟485收到的数据,往SD卡写入,持续20小时,看看有无问题.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

55

主题

243

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1596
金钱
1596
注册时间
2012-12-30
在线时间
240 小时
发表于 2015-9-30 11:19:34 | 显示全部楼层
换张好点的卡试试 看看时间是不是都在20多小时就死机 还有在原来已经死机过的卡上把原来的文件用覆盖方式继续测试20小时 如果卡死时间提前  那么就用好点的卡
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-9-30 21:11:17 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
试过直接存写好的数据(但没有模拟成485的数据)是没有问题的,正在测试的是把f_mout只在系统启动的时候运行一次,现在存的超过24个小时了,再看看能不能继续存
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-9-30 21:12:44 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
原子哥,局部数组64也大吗?我后来把定义的标志位的变量都放到了函数外面成全局变量
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-9-30 21:32:38 | 显示全部楼层
回复【3楼】wgh1990:
---------------------------------
让我换几张卡试一试,测试一下
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-10-1 11:33:23 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
原子哥,今天看sd看发现,把f_mount提出来以后,只有第一个文件建立成功了,是不是没建立一个新的文件,都要注册工作区?
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2015-10-4 10:32:34 | 显示全部楼层
回复【7楼】kekehuhu:
---------------------------------
不用的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-10-4 11:55:47 | 显示全部楼层
回复【8楼】正点原子:
---------------------------------
原子哥,我把f_mount提出来了以后,sd卡存了318个文件后程序又死了,是在存完第318个文件后,进入CreatNewFile这出问题了。能看一下会有什么影响到程序会让程序跑偏了吗?一个文件的存储时间大约7分钟

#define  __SHOW_SD_PROCEDURE__
static int i = 0;

FIL File;
FIL* CreateNewFile(void)
{
char  FileName[16];
char  CntBuf[64];
u8    res_open   = 1;
    u8    res_lseek  = 1;
int   open  = 0;
    int   lseek = 0;

    RTC_TimeTypeDef RTC_TimeStruct;   //__align(8) 8字节对其
RTC_DateTypeDef RTC_DateStruct;

RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
    RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);

sprintf(FileName, "%02d%02d%02d%02d.txt",
        RTC_DateStruct.RTC_Date,
        RTC_TimeStruct.RTC_Hours,
        RTC_TimeStruct.RTC_Minutes,
        RTC_TimeStruct.RTC_Seconds);

while(res_open!=0)
{
res_open = f_open(&File, FileName, FA_OPEN_ALWAYS | FA_WRITE);
if(++open > 2) 
{
sprintf(CntBuf, "f_open = %d", res_open);
            LCD_ShowString(60, 80, 210, 16, 16, CntBuf); 
}
}
while(res_lseek!=0)
{
res_lseek = f_lseek(&File, 0);
if(++lseek > 2) 
{
sprintf(CntBuf, "f_lseek = %d", res_lseek);
            LCD_ShowString(60, 110, 210, 16, 16, CntBuf); 
}


#ifdef __SHOW_SD_PROCEDURE__
LCD_ShowString(60, 140, 210, 16, 16, FileName);
#endif

LCD_ShowString(60, 170, 210, 16, 16, " CreateNewFile = ");    
LCD_ShowNum(200, 170, ++i, 8, 16);  

return &File;
}

#define  FILE_BLOCK_CNT   100
int   FileBlockCnt = 0;
int   FileCnt      = 0;
u8    res_close    = 1;
int   close        = 0;

int main(void) 
 {  
 char  CntBuf[64];
 FIL  *SDFile       = NULL;

//-------------------------------
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
//-------------------------------  
delay_init(168);                                    // 初始化延时函数
uart_init(115200);                                 // 初始化串口波特率为115200
LED_Init();                         // 初始化LED 
  LCD_Init();                         // LCD初始化  
RS485_Init(115200);                             // 初始化RS485串口2
    RTC_Set_WakeUp(RTC_WakeUpClock_CK_SPRE_16bits, 0);  // 配置WAKE UP中断,1秒钟中断一次
exfuns_init();  //为fatfs相关变量申请内存  
    usmart_dev.init(72);

my_mem_init(SRAMIN); //初始化内部内存池
SD_InitializeCards();
    f_mount(fs[0], "0:", 1);    //注册工作区 
// //-----------------------------
    while(1)  
{  
   if(QueueFullWithData)
   {  
 if(FileBlockCnt == 0)
    {
    SDFile = CreateNewFile();
    }
 f_write(SDFile, QueueFullWithData, QUEUE_SIZE, (UINT*)&bw);
 delay_ms(10);
   
 LCD_ShowString(60, 200, 210, 16, 16, "Saved File Block = ");    
 LCD_ShowNum(200, 200, ++FileBlockCnt, 8, 16);  

 QueueFullWithData = NULL; 
   
   
     if(FileBlockCnt == FILE_BLOCK_CNT)
     {
while(res_close!= 0)
{
res_close = f_close(SDFile);
if(++close > 2)
{
sprintf(CntBuf, "f_close = %d", res_close);
LCD_ShowString(60, 230, 210, 16, 16, CntBuf); 
}
}
res_close = 1;  close = 0;

FileBlockCnt = 0;
    LCD_ShowString(60, 260, 210, 16, 16, "Saved File Cnt = ");    
        LCD_ShowNum(200, 260, ++FileCnt, 8, 16);  
    } 
   }
}
}
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2015-10-5 16:48:10 | 显示全部楼层
回复【9楼】kekehuhu:
---------------------------------
这个,只能慢慢调了。你直接快速创建测试下吧。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-10-6 11:49:03 | 显示全部楼层
[mw_shl_code=c,true]FIL File;[/mw_shl_code] [mw_shl_code=c,true]FIL* CreateNewFile(void) { __align(8) RTC_TimeTypeDef RTC_TimeStruct; //__align(8) 8字节对其 __align(8) RTC_DateTypeDef RTC_DateStruct; RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct); RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct); LCD_ShowNum(200, 320, ++m, 8, 16); sprintf(FileName, "%02d%02d%02d%02d.txt", RTC_DateStruct.RTC_Date, RTC_TimeStruct.RTC_Hours, RTC_TimeStruct.RTC_Minutes, RTC_TimeStruct.RTC_Seconds); LCD_ShowNum(200, 350, ++n, 8, 16); while(res_open!=0) { res_open = f_open(&File, FileName, FA_OPEN_ALWAYS | FA_WRITE); if(++open > 2) { sprintf(CntBuf, "f_open = %d", res_open); LCD_ShowString(60, 80, 210, 16, 16, CntBuf); } } res_open = 1; open = 0; while(res_lseek!=0) { res_lseek = f_lseek(&File, 0); if(++lseek > 2) { sprintf(CntBuf, "f_lseek = %d", res_lseek); LCD_ShowString(60, 110, 210, 16, 16, CntBuf); } } res_lseek = 1; lseek = 0; #ifdef __SHOW_SD_PROCEDURE__ LCD_ShowString(60, 140, 210, 16, 16, FileName); #endif LCD_ShowString(60, 170, 210, 16, 16, " CreateNewFile = "); LCD_ShowNum(200, 170, ++i, 8, 16); return &File; }[/mw_shl_code]
[mw_shl_code=c,true]经过设标志位,发现是上面的程序出现问题了。[/mw_shl_code] [mw_shl_code=c,true] [mw_shl_code=c,true] while(res_open!=0) { res_open = f_open(&File, FileName, FA_OPEN_ALWAYS | FA_WRITE); if(++open > 2) { sprintf(CntBuf, "f_open = %d", res_open); LCD_ShowString(60, 80, 210, 16, 16, CntBuf); } } res_open = 1; open = 0;[/mw_shl_code] 这块死了,可是我设置的如果打开文件查过两次,就显示"f_open = %d",但是没有显示,这是怎么回事?

[/mw_shl_code]
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-10-6 13:07:10 | 显示全部楼层
经过快速创建文件,测试发现是485中断出问题了,我使用的是USART2,可是结果在USART.C中进入了USART1,
下面是485.c里的程序,用来接收数据的
[mw_shl_code=c,true]#if EN_USART2_RX //如果使能了接收,.h一直为1 //u8 RS485_RX_BUF[5000]; //中间传递缓冲区 //u32 RS485_RX_CNT; //中间传递计数值 u32 QueueIdx = 0; // 当前使用队列下标 CQueue CommQueue[2]; // 串口数据接收队列 CQueue *QueueFullWithData = NULL; // 已写满数据的队列 void USART2_IRQHandler(void) { CQueue *CurQueue = CommQueue + QueueIdx; while(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据 程序死在这句了 { // 读取接收到的数据USART2->DR u8 Data = USART_ReceiveData(USART2); // 将接收到的数据写入当前队列中 QueuePushBack(CurQueue, Data); // 如果队列写满,则下次使用另一个队列 if(QueueFull(CurQueue)) { QueueFullWithData = CurQueue; QueueIdx = ++QueueIdx % 2; CurQueue = CommQueue + QueueIdx; InitQueue(CurQueue); } } } #endif [/mw_shl_code]
下面是usart.c的程序
[mw_shl_code=c,true]void USART1_IRQHandler(void) //串口1中断服务程序 { u8 Res; #ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了. OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) 程序死在这句了 { Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据 if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d { if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(Res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 } } } } #ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了. OSIntExit(); #endif } #endif [/mw_shl_code]
能看一下是USART有什么问题吗?
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2015-10-6 15:45:07 | 显示全部楼层
回复【12楼】kekehuhu:
---------------------------------
应该是你串口1也产生了 接收数据中断,也就是收到了数据了。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

20

主题

89

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2015-7-6
在线时间
61 小时
 楼主| 发表于 2015-10-6 17:09:40 | 显示全部楼层
每次都是死在了while(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据这句话了,这是怎么回事
回复

使用道具 举报

15

主题

78

帖子

0

精华

初级会员

Rank: 2

积分
180
金钱
180
注册时间
2012-11-21
在线时间
9 小时
发表于 2015-10-6 19:40:46 | 显示全部楼层
回复【14楼】kekehuhu:
---------------------------------
中断服务程序进去了,但是对应的中断标志位没变化,是中断哪里有问题吗,原子哥?
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-25 09:33

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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