SMT32 FatFs,RTC,记录文件操作时间
介绍
官网地址:http://elm-chan.org/fsw/ff/
STM32F103Zet6
1.修改sdio.c中的代码
void MX_SDIO_SD_Init(void)
{
/* USER CODE BEGIN SDIO_Init 0 */
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = SDIO_INIT_CLK_DIV ;// SDIO_TRANSFER_CLK_DIV 用注释这个也是正常 // 0x04;
if (HAL_SD_Init(&hsd) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_1B) != HAL_OK)
{
Error_Handler();
}
return;
/* USER CODE END SDIO_Init 0 */
}
2.修改CubeMX自动生成的bsp_driver_sd.c
这是自动生成的代码,因为用的是__weak标记,所以我们重写就不会走该方法了
__weak uint8_t BSP_SD_Init(void)
{
uint8_t sd_state = MSD_OK;
/* Check if the SD card is plugged in the slot */
if (BSP_SD_IsDetected() != SD_PRESENT)
{
return MSD_ERROR;
}
/* HAL SD initialization */
sd_state = HAL_SD_Init(&hsd);
/* Configure SD Bus width (4 bits mode selected) */
if (sd_state == MSD_OK)
{
/* Enable wide operation */
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
sd_state = MSD_ERROR;
}
}
return sd_state;
}
在main.c中 重写该方法直接返回OK
uint8_t BSP_SD_Init(void)
{
uint8_t sd_state = MSD_OK;
return sd_state;
}
3.添加rtc进行设置当前时间
1.首先要打开 项目xxx.ioc 启用rtc,时钟树RTC设置为低速外部时钟,
rcc中LSE配置成 Crystal/Ceramic Resonator。
------------------------------
kk_rtc.c 提供了设置当前时间和获取当前时间
------------------------------
#include "kk_rtc.h"
#include <stdio.h>
#include <string.h>
extern RTC_HandleTypeDef hrtc;
static HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef *hrtc)
{
uint32_t tickstart = 0U;
tickstart = HAL_GetTick();
/* Wait till RTC is in INIT state and if Time out is reached exit */
while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
{
if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
return HAL_OK;
}
static HAL_StatusTypeDef RTC_ExitInitMode(RTC_HandleTypeDef *hrtc)
{
uint32_t tickstart = 0U;
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
tickstart = HAL_GetTick();
/* Wait till RTC is in INIT state and if Time out is reached exit */
while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
{
if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
return HAL_OK;
}
uint32_t RTC_ReadTimeCounter(RTC_HandleTypeDef *hrtc)
{
uint16_t high1 = 0U, high2 = 0U, low = 0U;
uint32_t timecounter = 0U;
high1 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
low = READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT);
high2 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
if (high1 != high2)
{
/* In this case the counter roll over during reading of CNTL and CNTH registers,
read again CNTL register then return the counter value */
timecounter = (((uint32_t) high2 << 16U) | READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT));
}
else{
timecounter = (((uint32_t) high1 << 16U) | low);
}
return timecounter;
}
HAL_StatusTypeDef RTC_WriteTimeCounter(RTC_HandleTypeDef *hrtc, uint32_t TimeCounter)
{
HAL_StatusTypeDef status = HAL_OK;
/* Set Initialization mode */
if (RTC_EnterInitMode(hrtc) != HAL_OK){
status = HAL_ERROR;
}
else{
/* Set RTC COUNTER MSB word */
WRITE_REG(hrtc->Instance->CNTH, (TimeCounter >> 16U));
/* Set RTC COUNTER LSB word */
WRITE_REG(hrtc->Instance->CNTL, (TimeCounter & RTC_CNTL_RTC_CNT));
/* Wait for synchro */
if (RTC_ExitInitMode(hrtc) != HAL_OK)
{
status = HAL_ERROR;
}
}
return status;
}
HAL_StatusTypeDef KK_RTC_SetTime(struct tm *time){
//mktime将tm日期时间结构体转换为时间戳
uint32_t unixTime = mktime(time);
return RTC_WriteTimeCounter(&hrtc, unixTime);
}
struct tm* KK_RTC_GetTime(){
//得到时间戳
time_t unixTime = RTC_ReadTimeCounter(&hrtc);
//将时间戳转换为tm结构体
return gmtime(&unixTime);
}
void KK_SetCurrentTime(void){
struct tm time = {
.tm_year = 2025 - 1900, //设置时间必须在当前实际年减去1900
.tm_mon = 1 - 1, //必须减1
.tm_mday = 17,
.tm_hour = 22,
.tm_min = 58,
.tm_sec = 50,
};
KK_RTC_SetTime(&time);
}
#define KK_RTC_DEF_Code 0x2122
void KK_RTC_Init(){
//避免重复设置,导致时间不准
uint32_t initFlag = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
if(initFlag == KK_RTC_DEF_Code){
return;
}
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
KK_SetCurrentTime();
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, KK_RTC_DEF_Code);
}
4.Fatfs 中完善获取时间函数,当对文件进行操作时便会记录当前时间
1.修改fatfs.c文件
DWORD get_fattime(void)
{
/* USER CODE BEGIN get_fattime */
//uint16_t date_time[6] = {2024,5,20,01,20,10};
//获得时间
//DWORD 记录文件日期和时间信息的是一个32位的寄存器,
//以下描述在32位的不同的不同范围内分别代表的值
//31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31)
//15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
struct tm *now;
now = KK_RTC_GetTime(); //从RTC中获取当前日期和时间
DWORD u16_dateTime;
//由于RTC中保存的年份在实际年份的基础上减去了1900所以要加1900到正确年份。
//由于fatfs中的年份又是在实际年份上减1980才得到真正保存的年份
//待从文件信息中读取日期时间时需要加1980得到实际年份
u16_dateTime = (now->tm_year + 1900 - 1980);
u16_dateTime = u16_dateTime<<25; //偏移到年份所处的位
u16_dateTime |= (now->tm_mon + 1)<<21;
u16_dateTime |= (now->tm_mday)<<16;
u16_dateTime |= (now->tm_hour)<<11;
u16_dateTime |= (now->tm_min)<<5;
//实际秒数除以2得到保存的秒数
//4-0: Second(0-29 *2) 由于描述占5位(1 1 1 1 1),最大只能保存的值是 31
u16_dateTime |= (now->tm_sec / 2 );
return u16_dateTime;
}
5.获取文件的日期时间信息
char fileNmae[] = "MyFatfsFile.txt";
FILINFO FileInf;
FR_Status = f_stat(fileNmae, &FileInf);
if(FR_Status == FR_OK){
printf("\r\n get file info \r\n");
printf("日:%d\r\n",FileInf.fdate&0x1F);/* 日 */
printf("月:%d\r\n",(FileInf.fdate&0x1E0)>>5);/* 月 */
printf("年:%d\r\n",((FileInf.fdate&0xFE00)>>9)+1980);/* 年 */
printf("秒:%d\r\n",(FileInf.ftime&0x1F)*2);/* 秒 */
printf("分:%d\r\n",(FileInf.ftime&0x7E0)>>5);/* 分 */
printf("时:%d\r\n",(FileInf.ftime&0xF800)>>11);/* 时 */
}else{
printf("\r\n Failed to get file info \r\n");
}
Fatfs的一些方法
The f_getfree function gets number of the free clusters on the volume.
FRESULT f_getfree (
const TCHAR* path, /* [IN] Logical drive number */
DWORD* nclst, /* [OUT] Number of free clusters */
FATFS** fatfs /* [OUT] Corresponding filesystem object */
);
Parameters
path
Pointer to the null-terminated string that specifies the logical drive. A null-string means the default drive.
nclst
Pointer to the DWORD variable to store number of free clusters.
fatfs
Pointer to pointer that to store a pointer to the corresponding filesystem object.
FATFS *fs;
DWORD fre_clust, fre_sect, tot_sect;
/* Get volume information and free clusters of drive 1 */
res = f_getfree("1:", &fre_clust, &fs);
if (res) die(res);
/* Get total sectors and free sectors */
//一个簇包含多个扇区 ,假如一个扇区等于 512byte字节
//(fs->n_fatent - 2) 计算出总的簇
//fs->csize 得到一个簇有多少个扇区
//tot_sect 总的扇区
tot_sect = (fs->n_fatent - 2) * fs->csize;
fre_sect = fre_clust * fs->csize;
/* Print the free space (assuming 512 bytes/sector) */
printf("%10lu KiB total drive space.\n%10lu KiB available.\n", tot_sect / 2, fre_sect / 2);
Application Interface layer
FatFs provides various filesystem functions for the applications as shown below.
File Access
f_open - Open/Create a file
f_close - Close an open file
f_read - Read data from the file
f_write - Write data to the file
f_lseek - Move read/write pointer, Expand size
f_truncate - Truncate file size
f_sync - Flush cached data
f_forward - Forward data to the stream
f_expand - Allocate a contiguous block to the file
f_gets - Read a string
f_putc - Write a character
f_puts - Write a string
f_printf - Write a formatted string
f_tell - Get current read/write pointer
f_eof - Test for end-of-file
f_size - Get size
f_error - Test for an error
Directory Access
f_opendir - Open a directory
f_closedir - Close an open directory
f_readdir - Read a directory item
f_findfirst - Open a directory and read the first item matched
f_findnext - Read a next item matched
File and Directory Management
f_stat - Check existance of a file or sub-directory
f_unlink - Remove a file or sub-directory
f_rename - Rename/Move a file or sub-directory
f_chmod - Change attribute of a file or sub-directory
f_utime - Change timestamp of a file or sub-directory
f_mkdir - Create a sub-directory
f_chdir - Change current directory
f_chdrive - Change current drive
f_getcwd - Retrieve the current directory and drive
Volume Management and System Configuration
f_mount - Register/Unregister the work area of the volume
f_mkfs - Create an FAT volume on the logical drive
f_fdisk - Create partitions on the physical drive
f_getfree - Get free space on the volume
f_getlabel - Get volume label
f_setlabel - Set volume label
f_setcp - Set active code page
原文地址:https://blog.csdn.net/fwjzm/article/details/145028335
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!