1. 程式人生 > >STM32F429的外接nandflash當作U盤實現資料記錄功能

STM32F429的外接nandflash當作U盤實現資料記錄功能

目錄

功能需求

實現資料採集記錄的功能。需要每一秒將資料記錄一次,並且實現24小時迴圈記錄的功能。如果電腦插上USB_SLAVE口,就可以直接將採集到的資料拷貝出來。在上位機上進行資料的管理。

主要功能

1.485資料採集

專案主要利用485進行資料採集,每接收到一個完整的一幀資料,就可以解包並進行CRC校驗,只要校驗通過即可認為這一條資料是有效的。可以進行資料記錄。

2.NANDFlash模擬成U盤

這裡需要利用fatfs+ftl將NANDFlash對映成Windows系統可直接識別的FAT32模式,該模式下檔案系統可直接被識別,FTL可以很好的對NANDFlash進行管理,實現壞區標記等功能。最後再通過移植USB,這樣就可以直接被電腦所識別。

3.讀寫Fatfs

由於前面兩個功能網上都有大量的例子,本人就不必贅言。這裡主要敘述開發過程中對Fatfs操作過程中遇到的種種錯誤以及自己思考的解決辦法。

具體實現

其實在操作Fatfs過程中,剛開始一直沒有弄清楚究竟操作的是什麼,其實這裡直接可以將操作的物件當成一個檔案即可。操作過程中,先開啟檔案

void ProcessBuffer485(u8* bInbuff)
{
    //memset(databuffer, 0, sizeof(databuffer));
    switch(bInbuff[0])
    {
        case DATPKG: //如果滿足07
資料 bInbuff++; memcpy((u8 *)&statePkg, bInbuff, sizeof(STAT_PKG)); //如果兩個時間一致,就跳出執行,將這一幀資料丟棄 if(statePkg.timesec==lastsec) { return; } lastsec=statePkg.timesec; //時間 year = statePkg.YMDHM >> 20; month = (statePkg.YMDHM >> 16
) &0x0F; day = (statePkg.YMDHM >>11) & 0x1F; hour = (statePkg.YMDHM >> 6) & 0x1F; minute = statePkg.YMDHM & 0x3F; if(reload==0) { z=0; lastfilelen=0; firststate=0; reload=1; } //如果檔案剛開始,寫完一條資料 if((z==0)&&(lastfilelen==0)&&(firststate==0)) { firststate=1; p = sprintf( databuffer, "id\t YMDHM\t lamps\t engSpeed\t engOilPress\t engWaterTemp\t trainSpeed\t RunKM\t bat24_V\t bat24_A\t engWorkTime\t Soft_Version\n"); p += sprintf( databuffer+p, "%6d\t %4d-%2d-%2d %2d:%2d:%2d\t %10d\t %5d\t %5d\t %5d\t %5d\t %10d\t %5d\t %5d\t %6d\t %34d\n", z,year,month,day,hour,minute, statePkg.timesec,statePkg.lamps,statePkg.engSpeed, statePkg.engOilPress, statePkg.engWaterTemp, statePkg.trainSpeed, statePkg.RunKM, statePkg.bat24_V, statePkg.bat24_A, statePkg.engWorkTime,statePkg.Soft_Version); z++; //讓計數加一 break; //此時返回databuffer的資料一共是256位元組 } //第1條資料 //if((z==1)&&(lastfilelen==0)) //{ // p += sprintf( databuffer + p, "%6d\t %4d-%2d-%2d %2d:%2d:%2d\t %10d\t %5d\t %5d\t %5d\t %5d\t %10d\t %5d\t %5d\t %6d\t %24d\n", z,year,month,day,hour,minute,statePkg.timesec, statePkg.lamps,statePkg.engSpeed, statePkg.engOilPress, statePkg.engWaterTemp, statePkg.trainSpeed, statePkg.RunKM, statePkg.bat24_V, statePkg.bat24_A, statePkg.engWorkTime,statePkg.Soft_Version); // return; // } //在位元組裡又增加128位元組 p += sprintf( databuffer + p, "%6d\t %4d-%2d-%2d %2d:%2d:%2d\t %10d\t %5d\t %5d\t %5d\t %5d\t %10d\t %5d\t %5d\t %6d\t %24d\n", z,year,month,day,hour,minute,statePkg.timesec, statePkg.lamps,statePkg.engSpeed, statePkg.engOilPress, statePkg.engWaterTemp, statePkg.trainSpeed, statePkg.RunKM, statePkg.bat24_V, statePkg.bat24_A, statePkg.engWorkTime,statePkg.Soft_Version); if(z==1) { z++; //此時還差一條到達512位元組 break; }else if(z==2){ //在這一條資料之後滿足512位元組了 p=0; } if(lastfilelen>0) { //表示已經有資料儲存了 if(z==0) { z = lastfilelen+1; } } if(z>2) { if((z-2)%4!=0) { z++; break; }else{ p=0; } } if(z>=180002) { reload=0; } /* if(z>=180002) { reload=0; } */ NAND_FlashFatfsDemo("2:/1.xls",databuffer,512); z++; memset(databuffer, 0, sizeof(databuffer));//陣列每次使用完,都要進行清空操作 break; default: break; } }

讀寫操作

/*
********************************************************************************************************
函式名稱:NAND_FlashFatfsDemo
函式功能: 測試 nand flash 讀寫功能,帶 fatfs 檔案管理系統操作
引數:    無
返回值:  無
********************************************************************************************************
*/

void NAND_FlashFatfsDemo(const TCHAR* path,const void* buff,int len)
{
        uint8_t res;
        //開啟之前改變檔案許可權
        //如果是隻讀模式,那麼開啟檔案的標識是不會生效的,也就是不能開啟檔案
        //res = f_chmod(path,AM_ARC,AM_ARC|AM_RDO);
        res = f_open(myfile, path, FA_OPEN_ALWAYS | FA_WRITE); //開啟檔案,已經滿足512位元組了
        f_sync(myfile);
      //    delay_ms(10);  //延時10ms
        if(FR_OK!=res)
        {
            //如果檔案沒有開啟成功,直接退出
            return;
        }

        //資料第一次被建立
        offset=((z-1)/4)*512;
        res = f_lseek(myfile,offset);
        //delay_ms(20);
        //開始寫資料
        res=f_write(myfile,buff,512,&bw);
        //f_sync(myfile);
        //delay_ms(20);
        if(FR_OK!=res||bw==0)
        {
            z--;
            z--;
            z--;
            z--;
            f_close(myfile);
            return;
        }

        //關閉資料檔案
        f_close(myfile);




        delay_ms(50);
        //開始寫計數檔案

        res = f_open(ftemp, "2:/number.txt", FA_CREATE_ALWAYS | FA_WRITE | FA_READ); //開啟檔案
        f_sync(ftemp);
    //  delay_ms(10);
        if(EOF==f_printf(ftemp,"%6d",z))
        {
        //  delay_ms(10);
            f_close(ftemp);
            //測試,如果寫入失敗的情況
            //res = f_open(ftemp, "2:/err.txt", FA_CREATE_ALWAYS | FA_WRITE | FA_READ); //開啟檔案
            //  delay_ms(10);
            //  f_close(ftemp);
                return;
        }
    //f_putc(z,myfile);
        f_close(ftemp);
        delay_ms(10);

} 

主要的思路是先將資料收集到512位元組,然後一次性向檔案裡面寫。當寫完後,則開始寫編號,這裡的編號用來表示下一次重新開始的檔案偏移位置。如果通過讀取檔案大小來操作檔案的指標,就沒有辦法實現迴圈複寫的功能了。所以只能思考採用兩個檔案來實現,一個專門寫資料,另外一個專門計數。當上電時,則可以計數檔案的數值。只用操作檔案指標偏移到相應的位置,即可修改檔案了。

遇到的問題

在操作過程中,剛開始寫的資料不對,有點時候讀出資料都是亂碼。這裡一般都是檔案的偏移地址算的不對。在寫完一條資料後,如果想讓資料接著寫,不覆蓋之前的資料,首先就是檔案的開啟方式採用 FA_OPEN_ALWAYS,其次就是要將檔案指標f_lseek移到該條資料結尾。不可移動太多了,如果移動太多,很可能會出現已經刪除了的資料。這樣就不對了。
第二個問題就是插上USB,windows系統會提示驅動有問題,是否修復U盤,很有可能是檔案寫完資料後,還沒來得及關閉資料,當沒有呼叫f_close或者f_sync時,資料是沒有的。所以有的時候會發現明明f_write寫了資料,但是有的時候卻沒有資料的情況。還可能出現FAT表損壞的情況。其實這個問題很常見,有的時候一斷電,資料檔案正在寫或者還沒來得及關閉,都有可能發生。
第三個問題就是斷電資料儲存的問題。本人在網上找了大量的資料,沒有發現合適的HAL庫版本的掉電中斷的文章,這裡來進行一下簡單的操作

void MyPVD_Init(void)
{


    PWR_PVDTypeDef pvd;

        __HAL_RCC_PWR_CLK_ENABLE();//使能電源時鐘PWR


    pvd.PVDLevel=PWR_CR_PLS_LEV7;
    pvd.Mode=PWR_PVD_MODE_IT_RISING;
//  HAL_PWR_DeInit();
    HAL_PWR_ConfigPVD(&pvd);
    HAL_PWR_EnablePVD();
    //LED1=!LED1;

    //__HAL_PWR_PVD_EXTI_ENABLE_IT();
     HAL_NVIC_SetPriority(PVD_IRQn,0x00,0x02); //搶佔優先順序1,子優先順序2
   HAL_NVIC_EnableIRQ(PVD_IRQn);

}

//產生中斷!
void PVD_IRQHandler()
{
    //LED1=0;
    HAL_PWR_PVD_IRQHandler();
}

//產生中斷後的回掉函式
void HAL_PWR_PVDCallback(void)
{

    LED1=0;

}

經過以上的配置,可以進入到中斷裡。這裡用LED燈可以看到發光一下。但是僅靠這個中斷想要實現資料的儲存還是不夠的,需要斷電後電壓維持一段時間,這段時間內足夠操作nandflash。