在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

用U盤記錄系統LOG信息的簡單步驟和方法

Geehy極海半導體 ? 來源:Geehy極海半導體 ? 2024-07-31 10:22 ? 次閱讀

# 01 前言

MCU 組成的系統在實際應用中,經常需要記錄系統 LOG 信息,可以是系統不同任務執行情況的 LOG 信息,也可以是內核寄存器等便于維護調試的信息,或者是傳感器的信息等。

上述的這些 LOG 信息,如果在能聯網的系統中,那么直接傳輸回服務器即可,但如果是離線的系統,那么就需要一個存儲設備來記錄這些 LOG 信息。一般有以下幾種方式:

- 記錄到 Nor Flash 等板載存儲器

- 記錄到可移動的存儲器,比如 U 盤等存儲設備

本文提供后一種方式,即數據記錄到 U 盤,這種方式方便進行現場維護,但實際應用中,可以結合 Nor Flash 加 U 盤的方式,避免讀寫 U 盤頻率過快導致損壞。以下內容利用 APM32F407xx 的 OTG Host 和 Fatfs 文件系統,加上 RTC 功能來實現數據記錄,包括以下功能。

- 按日期自動創建文件夾存放 `LOG.xls` 文件

- 按 1 秒的記錄頻率往 `LOG.xls` 文件寫入帶時間戳的數據

- 在 U 盤存儲空間使用超過 90%時,刪除日期最早的文件夾及 LOG 文件

# 02 外設和組件配置

下面簡單介紹一下所用到的外設和組件的配置。

## OTG Host

OTG Host 的配置比較簡單,配置為普通 FS 速度和 MSC Class 類即可。

void USB_HostInitalize(void)

{

/* USB host and class init */

USBH_Init(&gUsbHostFS, USBH_SPEED_FS, &USBH_MSC_CLASS, USB_HostUserHandler);

}

U 盤在枚舉完成后,需要獲取 `LUN` 的信息,以便后續對特定 `LUN` 進行命令和數據讀寫等操作。

101ee3c0-4e57-11ef-b8af-92fbcf53809c.jpg

有關 MSC Class 的處理在 `usbh_msc.c/h` 文件中的 `USBH_MSC_CLASS` 結構體句柄,其包含以下處理函數:

- `USBH_MSC_ClassInitHandler`:Class 初始化函數。

- `USBH_MSC_ClassDeInitHandler`:Class 解初始化函數。

- `USBH_MSC_ClassReqHandler`:Class 特定請求處理函數,用于處理 `MASS_STORAGE_RESET`、`GET_MAX_LUN` 等特定請求。

- `USBH_MSC_CoreHandler`:Class 內核處理函數,包括 BOT 命令、SCSI 命令的處理。

- `USBH_MSC_SOFHandler`:SOF 事件處理函數。

/* MSC class handler */

USBH_CLASS_T USBH_MSC_CLASS =

{

"Class MSC",

USBH_CLASS_MSC,

NULL,

USBH_MSC_ClassInitHandler,

USBH_MSC_ClassDeInitHandler,

USBH_MSC_ClassReqHandler,

USBH_MSC_CoreHandler,

USBH_MSC_SOFHandler,

};

下面的 `USBH_MSC_Handler` 狀態機由 `USBH_MSC_CoreHandler` 函數調用,包含常見的 BOT 命令、SCSI 命令的處理。

/* USB host MSC state handler function */

USBH_MscStateHandler_T USBH_MSC_Handler[] =

{

USBH_MSC_InitHandler,

USBH_MSC_IdleHandler,

USBH_MSC_InquiryHandler,

USBH_MSC_TestUnitReadyHandler,

USBH_MSC_RequestSenseHandler,

USBH_MSC_ReadCapacityHandler,

USBH_MSC_ErrorUnrecoveredHandler,

USBH_MSC_ReadHandler,

USBH_MSC_WriteHandler,

USBH_MSC_RWRequestSenseHandler,

};

BOT SCSI 命令處理。

10462660-4e57-11ef-b8af-92fbcf53809c.jpg

OTG Host 部分還需要了解以下 API 函數,因為后續需要應用到 FatFs 文件系統中。

- `USBH_MSC_ReadDevInfo()`:用于獲取所枚舉成功的 `MSC` 設備信息,比如 `LUN` 邏輯單元是否準備完畢、多媒體設備是否存在、扇區數、block 數等。

- `USBH_MSC_DevStatus()`:獲取 `LUN` 是否準備就緒的狀態。

- `USBH_MSC_ReadDevWP()`:獲取 `LUN` 寫保護狀態。

- `USBH_MSC_DevRead()`:讀取 `LUN` 數據。

- `USBH_MSC_DevWrite()`:往 `LUN` 寫入數據。

USBH_STA_T USBH_MSC_ReadDevInfo(USBH_INFO_T* usbInfo, uint8_t lun, USBH_MSC_STORAGE_INFO_T* device);

uint8_t USBH_MSC_DevStatus(USBH_INFO_T* usbInfo, uint8_t lun);

uint8_t USBH_MSC_ReadDevWP(USBH_INFO_T* usbInfo, uint8_t lun);

USBH_STA_T USBH_MSC_DevRead(USBH_INFO_T* usbInfo, uint8_t lun, uint32_t address,

uint8_t* buffer, uint16_t cnt);

USBH_STA_T USBH_MSC_DevWrite(USBH_INFO_T* usbInfo, uint8_t lun, uint32_t address,

uint8_t* buffer, uint16_t cnt);

## RTC

APM32F4xx 的 RTC 是一個獨立的 BCD 定時計數器,提供完整的日歷時鐘功能。不像 F1 系列的 RTC 只是個計數器,需要自行設定元年,然后換算日期和時間。RTC 的配置比較簡單,配置時鐘源為 LSE,24 小時制即可,然后利用 RTC 的備份寄存器來判斷是否需要配置日歷和時間。

void RTC_CalendarConfig(void)

{

RTC_DateTypeDef Date_Structure;

RTC_TimeTypeDef Time_Structure;

/* Configure the Date */

Date_Structure.Year = 0x23;

Date_Structure.Month = RTC_MONTH_NOVEMBER;

Date_Structure.Date = 0x22;

Date_Structure.WeekDay = RTC_WEEKDAY_MONDAY;

if(DAL_RTC_SetDate(&hrtc,&Date_Structure,RTC_FORMAT_BCD) != DAL_OK)

{

DAL_ErrorHandler();

}

/* Configure the Time */

Time_Structure.Hours = 0x00;

Time_Structure.Minutes = 0x00;

Time_Structure.Seconds = 0x00;

Time_Structure.TimeFormat = RTC_HOURFORMAT12_AM;

Time_Structure.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;

Time_Structure.StoreOperation = RTC_STOREOPERATION_RESET;

if(DAL_RTC_SetTime(&hrtc,&Time_Structure,RTC_FORMAT_BCD) != DAL_OK)

{

DAL_ErrorHandler();

}

DAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0, RTC_BKP_VALUE);

}

## TMR

APM32F4xx 系列的 RTC 沒有秒中斷,這里我們實現一秒記錄一次數據到 U 盤,則開啟一個定時為 1 秒的定時器中斷來實現。

void DAL_TMR3_Config(void)

{

htmr3.Instance = TMR3;

htmr3.Init.Period = 10000 - 1;

htmr3.Init.Prescaler = 8400 - 1;

htmr3.Init.ClockDivision = 0;

htmr3.Init.CounterMode = TMR_COUNTERMODE_UP;

htmr3.Init.AutoReloadPreload = TMR_AUTORELOAD_PRELOAD_DISABLE;

if(DAL_TMR_Base_Init(&htmr3) != DAL_OK)

{

DAL_ErrorHandler();

}

}

## FatFs

使用 FatFs 文件系統前,要重新實現 `diskio.c` 及配置 `ffconf.h` 文件。

其中在 `diskio.c` 文件中,要利用 OTG Host 章節最后提到的 `MSC Class` 的 API ,重新實現以下函數。

`DSTATUS disk_status()`

`DSTATUS disk_initialize()`

`DRESULT disk_read()`

`DRESULT disk_write()

`DRESULT disk_ioctl()`

另外,簡單介紹下后面應用代碼中用到的幾個 API,詳細的使用方法,大家可以參考 FatFs 官方文檔。

### f_opendir

該 API 用于打開一個已存在的目錄文件夾。

FRESULT f_opendir (

DIR* dp, /* [OUT] Pointer to the directory object structure */

const TCHAR* path /* [IN] Directory name */

);

### f_readdir

該 API 用于讀取目錄項,后續用于篩選所有的有效目錄。

FRESULT f_readdir (

DIR* dp, /* [IN] Directory object */

FILINFO* fno /* [OUT] File information structure */

);

### f_mkdir

該 API 用于創建一個新的目錄文件夾。

FRESULT f_mkdir (

const TCHAR* path /* [IN] Directory name */

);

### f_open

該 API 用于打開一個文件。要注意的是參數 `mode flags` 需要使用 `FA_OPEN_ALWAYS`,避免文件內容被覆蓋。

FRESULT f_open (

FIL* fp, /* [OUT] Pointer to the file object structure */

const TCHAR* path, /* [IN] File name */

BYTE mode /* [IN] Mode flags */

);

### f_unlink

該 API 用于刪除文件或子目錄。

FRESULT f_unlink (

const TCHAR* path /* [IN] Object name */

);

### f_close

該 API 用于關閉一個文件。

FRESULT f_close (

FIL* fp /* [IN] Pointer to the file object */

);

### f_lseek

該 API 用于移動被打開的文件對象的文件讀或寫指針,后面應用時,需要用來將寫指針移動到文件末,以添加新的 LOG 信息。

FRESULT f_lseek (

FIL* fp, /* [IN] File object */

FSIZE_t ofs /* [IN] Offset of file read/write pointer to be set */

);

### f_printf

該 API 用于將格式化的字符串寫入文件。使用該 API,我們可以方便的將各種數據類型,轉換為字符串,再寫入文件中。

int f_printf (

FIL* fp, /* [IN] File object */

const TCHAR* fmt, /* [IN] Format stirng */

...

);

### f_getfree

該 API 用于獲取 volume 中的剩余空間。使用該 API,我們可以知道 U 盤剩余空間是多少,從而對老舊的 LOG 數據進行處理。

FRESULT f_getfree (

const TCHAR* path, /* [IN] Logical drive number */

DWORD* nclst, /* [OUT] Number of free clusters */

FATFS** fatfs /* [OUT] Corresponding filesystem object */

);

# 03 實現數據記錄

## 定義參數結構體

定義 `rtcInfo` 和 `diskInfo` 來記錄應用過程中的信息。

/* 記錄 RTC 時間信息 */

typedef struct

{

uint16_t year;

uint8_t month;

uint8_t day;

uint8_t hour;

uint8_t minute;

uint8_t second;

} RTC_TIME_INFO_T;

/* 記錄 U 盤和文件系統信息 */

typedef struct

{

char dirPath[512];

uint16_t dirNum;

uint32_t totSect;

uint32_t freSect;

double usedPercent;

} DISK_INFO_T;

RTC_TIME_INFO_T rtcInfo;

DISK_INFO_T diskInfo;

## 獲取時間參數

在 TMR3 回調函數中獲取 RTC 當前時間,并使能數據更新標志。

void RTC_Application(void)

{

char strBuf[50];

RTC_GetCalendar(&rtcInfo.year, &rtcInfo.month, &rtcInfo.day, &rtcInfo.hour, &rtcInfo.minute, &rtcInfo.second);

/* Display time */

sprintf(strBuf, "20%02d-%02d-%02d %02d:%02d:%02d", rtcInfo.year, rtcInfo.month, rtcInfo.day, rtcInfo.hour, rtcInfo.minute, rtcInfo.second);

DAL_LOGI(tag, "%s", strBuf);

}

void DAL_TMR_PeriodElapsedCallback(TMR_HandleTypeDef *htmr)

{

if(htmr->Instance == TMR3)

{

RTC_Application();

dataUpdate = 1;

}

}

## 記錄數據

### 提供日期和時間給 FatFs

FatFs 系統的文件和目錄的日期、時間信息由 `get_fattime` 函數提供。該函數為 `__weak` 定義,我們在應用文件中重新實現即可,這里要注意 APM32F4xx 的 RTC 日歷的起始年份和 FatFs 的不一致,做好偏移即可。

DWORD get_fattime(void)

{

return (DWORD)(rtcInfo.year + 20) << 25 |

(DWORD)rtcInfo.month << 21 |

(DWORD)rtcInfo.day << 16 |

(DWORD)rtcInfo.hour << 11 |

(DWORD)rtcInfo.minute << 5 |

(DWORD)rtcInfo.second >> 1;

}

### 創建和寫數據到 Excel 文件

下面這個函數中,首先創建一個目錄,然后創建或打開一個 `.xls` 文件,接著打開文件并用 `f_lseek` 函數移動寫指針到文件末,最后用 ` f_printf ` 函數寫入格式化后的字符串數據。

void FATFS_WriteXlsFile(FIL* file, const TCHAR *path, char *dir, char *fileName, char* logInfo, char* timeStamp)

{

FRESULT status;

char filePath[32];

char fileDir[20];

/* Write file */

sprintf(fileDir, "%s", dir);

status = f_mkdir(fileDir);

if (status == FR_OK)

{

DAL_LOGI(tag, ">>> Create direction success");

}

/* Open or create file */

sprintf(filePath, "%s%s%c%s.xls", path, fileDir, '/', fileName);

status = f_open(file, filePath, FA_OPEN_ALWAYS | FA_WRITE);

if (status == FR_OK)

{

DAL_LOGI(tag, ">>> Open or create %s %s file success", fileDir, fileName);

/* Move the file pointer to the end */

f_lseek(file, f_size(file));

f_printf(file, "%s + %s + %s ", fileName, logInfo, timeStamp);

}

else

{

DAL_LOGE(tag, ">>> Open or create file fail, status is %d", status);

}

/* Close file */

f_close(file);

}

### 獲取 U 盤剩余空間信息

Volume 的剩余空間,從之前 FatFs 章節中知道,可以用 `f_getfree` 函數來獲取 U 盤剩余空間信息,并轉換為使用率。

void MSC_Application(void)

{

...

res = f_getfree(USBHPath, &freClust, &fs);

diskInfo.totSect = (fs->n_fatent - 2) * fs->csize;

diskInfo.totSect /= 2;

diskInfo.freSect = freClust * fs->csize;

diskInfo.freSect /= 2;

diskInfo.usedPercent = (1.0 - (double)diskInfo.freSect / diskInfo.totSect) * 100.0;

...

}

### 刪除舊文件夾

以下代碼,使用 `FATFS_ViewRootDir()` 函數獲取目錄文件夾信息,并按日期進行排序輸出。最后由 `sscanf()` 來找到第一個目錄,然后刪除目錄和文件。

void MSC_Application(void)

{

...

/* Get dir information */

DAL_LOGI(tag, "------> Get dir information");

FATFS_ViewRootDir(&USBHFatFS, USBHPath, diskInfo.dirPath, &diskInfo.dirNum);

DAL_LOGI(tag, ">>> dir path :%s", diskInfo.dirPath);

DAL_LOGI(tag, ">>> dir number :%d", diskInfo.dirNum);

/* Used percent > 90% and dir number > 1 */

if((diskInfo.usedPercent - DISK_SPACE_MAX_PERCENT) > EPS && (diskInfo.dirNum > 1))

{

DAL_LOGW(tag, "<<< Disk space is not enough");

/* Delete first dir */

sscanf(diskInfo.dirPath, "/%8[^/]", delectDirName);

FATFS_DelectDir(USBHPath, delectDirName);

}

...

}

# 04 下載驗證

經過之前幾節的組件的配置,實現數據記錄的 API 函數后,最后下載到 APM32F4xx 開發板看下應用的過程。

從下面 LOG 信息可以看到,插入 U 盤后,從 UART1 輸出了 `MSC device is ready` 的 LOG 信息,這表明開發板已完成 U 盤的枚舉識別。

同時可以看到 LOG 中帶有時間戳信息,證明 RTC 已經開發工作,并按每秒打印一次的頻率輸出時間戳 LOG 信息。

...

[main] 2023-11-22 0037

[main] 2023-11-22 0038

[main] 2023-11-22 0039

[main] 2023-11-22 0040

USB Device Reset Completed

USB device speed is FS

PID: 0x1234

VID: 0x048D

Endpoint 0 max packet size if 64

USB device address: 1

Manufacturer: USB

Product: Disk 2.0k

SerialNumber: 9207156342331724518

USB device enumration ok

This is a Mass Storage device

Use 2 endpoint:

Endpoint 0x01: max packet size is 64 bytes

Endpoint 0x82: max packet size is 64 bytes

USB device has only one configuration

Set to default configuration

Inquiry Revision :2.00

Inquiry Product :ProductCode

Inquiry Vendor :VendorCo

MSC device is ready

MSC device capacity : 1006390784 bytes

MSC device block number : 1965607

MSC device block size : 512

Class is ready

緊接著,就會進行 LOG 信息的記錄,從下面 LOG 可以看到,FatFs 的操作過程。首先在 U 盤加載文件系統,然后創建或打開以 `20231122` 日期命名的文件夾并寫入數據。接著獲取 U 盤剩余空間,獲取目錄信息,最后卸載文件系統。

[main] 2023-11-22 0012

[main] ------> Update information

[main] ------> Mount U disk file system

[main] ------> Write xls file

[fatfs] >>> Open or create 20231122 LOG file success

[main] ------> Get volume information

[main] >>> (964657 / 966404) KiB Used 0.18 %

[main] ------> Get dir information

[fatfs] >>> View Directory

[fatfs] >>> 20231122, (0x10)

[fatfs] >>> 20231031, (0x10)

[fatfs] >>> 20231030, (0x10)

[fatfs] >>> 20231101, (0x10)

[fatfs] >>> Sort Directory

[main] >>> dir path :/20231030/20231031/20231101/20231122

[main] >>> dir number :4

[main] ------> Unmount U disk file system

[main] >>> U disk file system unmounted ok

我們打開 U 盤可以看到已經在設定的文件夾中創建了一個命名為 `LOG.xls` 的 Excel 文件。

106c9d5e-4e57-11ef-b8af-92fbcf53809c.jpg

以 LOG + RTC 時間戳為內容寫入到 Excel 文件中。實際應用時記錄的信息可以是系統不同任務執行情況,也可以是內核寄存器等便于維護調試的信息,或者是傳感器的信息等。

108a7856-4e57-11ef-b8af-92fbcf53809c.jpg

以上,就是用 U 盤記錄系統 LOG 信息的一些簡單步驟和方法,實際應用中還要考慮更多情況,附件是源碼,供大家參考。

審核編輯:彭菁

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 存儲器
    +關注

    關注

    38

    文章

    7492

    瀏覽量

    163834
  • 數據
    +關注

    關注

    8

    文章

    7030

    瀏覽量

    89034
  • U盤
    +關注

    關注

    7

    文章

    489

    瀏覽量

    63260
  • Log
    Log
    +關注

    關注

    0

    文章

    14

    瀏覽量

    11330

原文標題:APM32芯得 EP.36 | APM32F4實現用U盤記錄LOG信息

文章出處:【微信號:geehysemi,微信公眾號:Geehy極海半導體】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    U系統小工具

    啟動時按“del”或“F8”鍵進入BIOS設置具體設置請參閱 電腦店U系統設置U啟動教程 第五步:
    發表于 04-25 16:36

    簡單方便U系統小工具

    “del”或“F8”鍵進入BIOS設置具體設置請參閱 電腦店U系統設置U啟動教程 第五步:
    發表于 07-15 18:26

    輕松U快速裝系統工具

    U啟動教程第五步:U啟動快速安裝系統(第一種方法
    發表于 10-03 20:21

    U快速裝系統工具

    U啟動教程第五步:U啟動快速安裝系統(第一種方法
    發表于 10-07 17:38

    U快速裝系統工具

    啟動教程第五步:U啟動快速安裝系統(第一種方法)進PE
    發表于 10-19 19:23

    U快速裝系統工具

    啟動教程第五步:U啟動快速安裝系統(第一種方法)進PE
    發表于 10-21 17:07

    U系統工具

    啟動教程第五步:U啟動快速安裝系統(第一種方法)進PE
    發表于 10-29 18:21

    U做DOS啟動的制作方法及詳細步驟

    U做DOS啟動的制作方法及詳細步驟 啟動型U
    發表于 04-13 19:14 ?3154次閱讀

    quartus ii仿真實驗簡單步驟

    關于fpga實驗的簡單步驟,更利于初學者學習
    發表于 09-13 17:00 ?0次下載

    電腦卡怎么辦簡單步驟

    本視頻主要詳細介紹了電腦卡怎么辦簡單步驟,分別是卸載同類型的軟件、清理回收站、借助軟件清理電腦垃圾、定期清理磁盤碎片、系統垃圾文件、重裝系統
    的頭像 發表于 03-08 16:22 ?8812次閱讀

    怎樣U系統

    大家隨便在搜索引擎上搜索“U系統”,就能輕松找到數種重裝系統方法
    的頭像 發表于 08-29 17:35 ?2533次閱讀

    led顯示屏u怎么改字_ledu導入字幕步驟

    本文詳細闡述了led顯示屏u改字的教程,另外還闡述了ledu導入字幕的詳細
    發表于 03-27 09:11 ?9.9w次閱讀

    電腦藍屏的時候如何用u重裝系統

    本文主要介紹了電腦藍屏u重裝系統的操作步驟
    發表于 04-17 08:55 ?1w次閱讀

    linux掛載u方法

    linux掛載U具體步驟如下:
    發表于 05-19 09:14 ?2669次閱讀
    linux掛載<b class='flag-5'>u</b><b class='flag-5'>盤</b>的<b class='flag-5'>方法</b>

    使用LTpowerCAD在五個簡單步驟中設計電源

    使用LTpowerCAD在五個簡單步驟中設計電源
    發表于 04-17 16:57 ?10次下載
    使用LTpowerCAD在五個<b class='flag-5'>簡單步驟</b>中設計電源
    主站蜘蛛池模板: 国产亚洲精品线观看77| 迅雷www天堂在线资源| 爱爱456高清国语在线456| 五月婷婷俺也去开心| 在线观看视频h| 好爽好大www视频在线播放| 高清欧美性xxxx成熟| 永久免费av网站| 男男失禁play 把尿bl| 中文字幕在线色| 久久青草视频| 国产在线播放你懂的| 国产黄色三级三级三级| 4虎影院在线观看| 婷婷综合五月中文字幕欧美| 深夜视频免费看| 干干天天| 亚洲一卡2卡3卡4卡5卡乱码| 美女扒开腿让男人桶尿口| 亚洲欧美日韩在线精品2021| 五月婷婷婷婷| 欧美日本综合| 国产女人视频免费观看| 色妞在线| 女人张腿让男桶免费视频观看| 婷婷婷色| 日本黄色大片在线观看| 三级毛片在线| 久久伊人网站| 97影院理论片在线观看| 手机午夜视频| 殴美一级| 免费视频大全| 在线亚洲国产精品区| 色综合久久久久久久久五月性色| 免费看一级大片| 久久久免费精品视频| 最新eeuss影院第256页| 久久综合九色| 亚洲 欧美 成人| 四虎在线视频|