STM32L476應用開發之五:數據保存與SD卡操作


便攜式氣體分析儀的特點就是離線運行。盡管是離線運行,但測試數據還是需要的,所以采取方式保存數據就是必須的。在本次項目中我們計划采用SD卡來保存數據。

1、硬件設計

該讀卡器整合 SD 卡規范和 FAT 文件格式規范,只要通過本模塊規定的通訊協議就可以把數據存儲在 SD 卡中的文件中。該讀卡器連接方便采用串口通訊方式,如下圖:

該讀卡器摸塊通訊協議比較簡單,本模塊的通訊協議分為命令發送和命令的應答兩部分,其中命令格式由4個部分組成:命令識別碼(0x55 0xAA),命令號,字節數(參數的個數,占2個字節,先發送低位字節,再發送高位字節),參數(根據命令的不同而不同),校驗和(除命令識別碼和校驗和本身,所有發送數據之和的低 8 位數據)。命令格式如圖:

 

應答分為兩部分:命令的執行情況(編碼將附錄 1),數據。數據根據命令的不同而不同。

根據上述描述,我們設計SD卡的接口電路如下:

 

2、軟件設計

接下來我們根據協議編寫讀寫SD卡的軟件,主要實現狀態檢測、創建文件、打開文件、寫文件、關閉文件、保存文件以及獲取文件信息等。

1)獲取系統的狀態命令

獲取系統的狀態命令是用來獲取模塊當前的狀態。命令編碼是:0x01,命令格式如下:

 

//檢測系統SD卡的狀態

uint8_t GetSDCardStatus(void)

{

  uint8_t CommandText[6]={0x55,0xAA,0x01,0x00,0x00,0x01};

  uint8_t StatusByte=0xaa;

  StatusByte = SendCommand(CommandText,6);

  Delayms(50);

  return StatusByte;

}

2)創建文件命令

創建文件命令提供給主機創建文件的功能。參數為 N 字節 8.3 文件格式的文件名(字符串格式,即文件名以 0 結尾),即 8 字節的基本文件名(模塊不支持漢字編碼,字母不區分大小寫),3 字節擴展名。命令編碼是:0x02,命令格式如下:

 

//創建文件,返回操作狀態

uint8_t CreateFile(uint8_t fileName[8])

{

  uint8_t CommandText[19]={0x55,0xAA,0x02,0x0D,0x00,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x2E,0x74,0x78,0x74,0x00,0x41};

  uint8_t StatusByte;

  StatusByte=0xaa;

  uint16_t i;

  for(i=0;i<8;i++)

  {

    CommandText[i+5]=fileName[i];

  }

  uint8_t checksum=0x00;

  for(i=2;i<18;i++)

  {

    checksum+=CommandText[i];

  }

  CommandText[18]=checksum;

  StatusByte = SendCommand(CommandText,19);

  return StatusByte;

}

(3)打開文件命令

該命令為主機提供打開文件的功能。參數為 N 字節 8.3 文件格式的文件名(字符串格式,即文件名以0 結尾),即 8 字節的基本文件名(模塊不支持漢字編碼,字母不區分大小寫),3 字節擴展名。命令編碼是:0x06命令格式如下,其中個數占 2 字節,低字節先發送:

 

//打開文件

uint8_t OpenFile(uint8_t fileName[8])

{

  uint8_t CommandText[19]={0x55,0xAA,0x06,0x0D,0x00,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x2E,0x74,0x78,0x74,0x00,0x45};//打開文件命令 0x06

  uint8_t StatusByte=0xaa;

  uint16_t i;

  for(i=0;i<8;i++)

  {

    CommandText[i+5]=fileName[i];

  }

  uint8_t checksum=0x00;

  for(i=2;i<18;i++)

  {

    checksum+=CommandText[i];

  }

  CommandText[18]=checksum;

  StatusByte = SendCommand(CommandText,19);

  return StatusByte;

}

4)獲取文件信息命令

本命令為主機提供了讀取當前打開文件的文件指針值和文件大小的功能。命令編碼是:0x09,其命令格式如下:

 

//獲取文件信息命令

void GetFileStatus(uint8_t rxData[])

{

  uint8_t CommandText[6]={0x55,0xAA,0x09,0x00,0x00,0x09};//獲取文件信息命令0x09

  uint16_t i;

  for(i=0;i<6;i++)

  {

    //等待傳送結束

    while(USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET)

    {

    }

    // 寫一個字節到對應的串口傳送數據寄存器

    USART_SendData(UART4, CommandText[i]);

  }

 

  Delayms(20);

 

  for(i=0;i<9;i++)

  {

    // 等待字節被對應的串口完全接收

    //while(USART_GetFlagStatus(UART4, USART_FLAG_RXNE) == RESET)

    //{

    //}

    // 獲取接收到的字節

    rxData[i] = USART_ReceiveData(UART4);

  }

}

5)寫文件命令

該命令為主機提供向已打開文件中寫入數據的功能。每寫一個數據文件指針自動加1,當數據寫完,文件指針指向最后一個數據地址加1的位置。命令編碼是:0x05,命令格式如下,其中個數占2字節,低字節先發送,起始地址占4字節,低字節先發送:

 

//寫文件,返回寫操作的狀態

uint8_t WriteToFile(uint8_t * address,uint8_t data[],uint16_t datalength)

{

  uint16_t count=datalength+10+19;

  uint8_t CommandText[70];

  uint8_t StatusByte=0xaa;

  uint16_t i;

  CommandText[0]=0x55;

  CommandText[1]=0xAA;

  CommandText[2]=0x05;

  CommandText[3]=datalength+4+19;

  CommandText[4]=0x00;

  CommandText[5]=0xFF;

  CommandText[6]=0xFF;

  CommandText[7]=0xFF;

  CommandText[8]=0xFF;

 

  for(i=0;i<datalength;i++)

  {

    CommandText[i+9]=data[i];

  }

 

  CommandText[datalength+9]=(saveDate[0]/10)+0x30;

  CommandText[datalength+10]=(saveDate[0]%10)+0x30;

  CommandText[datalength+11]=0x2D;

  CommandText[datalength+12]=(saveDate[1]/10)+0x30;

  CommandText[datalength+13]=(saveDate[1]%10)+0x30;

  CommandText[datalength+14]=0x2D;

  CommandText[datalength+15]=(saveDate[2]/10)+0x30;

  CommandText[datalength+16]=(saveDate[2]%10)+0x30;

  CommandText[datalength+17]=0x20;

  CommandText[datalength+18]=(saveDate[3]/10)+0x30;

  CommandText[datalength+19]=(saveDate[3]%10)+0x30;

  CommandText[datalength+20]=0x3A;

  CommandText[datalength+21]=(saveDate[4]/10)+0x30;

  CommandText[datalength+22]=(saveDate[4]%10)+0x30;

  CommandText[datalength+23]=0x3A;

  CommandText[datalength+24]=(saveDate[5]/10)+0x30;

  CommandText[datalength+25]=(saveDate[5]%10)+0x30;

  CommandText[datalength+26]=0x0D;

  CommandText[datalength+27]=0x0A;

 

  uint8_t checksum=0x00;

  for(i=2;i<count-1;i++)

  {

    checksum+=CommandText[i];

  }

  CommandText[count-1]=checksum;

  StatusByte = SendCommand(CommandText,count);

  return StatusByte;

}

6)保存文件命令

該命令為主機提供保存當前打開文件的功能,為了防止頻繁寫 SD 卡,每次送入模塊的數據先是保存在模塊的 512 字節的扇區緩沖中,所以為了防止數據丟失,完成所有數據的傳輸后,要發送保存文件命令來保存文件。命令編碼是:0x04,命令格式如下:

 

//保存文件,返回操作執行狀態

uint8_t SaveFile(void)

{

  uint8_t CommandText[6]={0x55,0xAA,0x04,0x00,0x00,0x04};//保存文件命令 0x04

  uint8_t StatusByte=0xaa;

  StatusByte = SendCommand(CommandText,6);

  return StatusByte;

}

7)關閉文件命令

該命令為主機提供關閉當前打開的文件的功能。在創建文件、創建文件夾、打開文件之前要求關閉當前打開的文件,才可以執行這些命令,否則返回失敗。命令編碼是:0x08,命令格式如下:

 

//關閉文件,返回操作執行狀態

uint8_t CloseFile(void)

{

  uint8_t CommandText[19]={0x55,0xAA,0x08,0x00,0x00,0x08};//關閉文件命令 0x08

  uint8_t StatusByte=0xaa;

  StatusByte = SendCommand(CommandText,6);

  return StatusByte;

}

3、測試結果

編寫完程序,我們測試以我們想要的格式寫一些數據下去文件被保存為文本文件,以時間為文件名,數據格式與預期一致。至此SD卡讀寫完成。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM