SMT32 FatFs,RTC,记录文件操作时间

介绍

官网地址:http://elm-chan.org/fsw/ff/

STM32F103Zet6

1.修改sdio.c中的代码
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
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进行设置当前时间
c 复制代码
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 中完善获取时间函数,当对文件进行操作时便会记录当前时间
c 复制代码
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.获取文件的日期时间信息
c 复制代码
		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的一些方法

bash 复制代码
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);
bash 复制代码
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
相关推荐
恶魔泡泡糖2 小时前
stm32F103C8T6标准库串口接收之中断方式2
stm32·单片机·嵌入式硬件
充哥单片机设计2 小时前
【STM32开源项目】智能小区充电桩
stm32·单片机·嵌入式硬件·毕业设计·小区充电桩·智能小区充电桩
充哥单片机设计4 小时前
【STM32开源项目】智能语音台灯
stm32·单片机·嵌入式硬件·毕业设计·单片机设计·智能语音台灯
Brilliantwxx6 小时前
【STM32】 SPI阻塞式通信与HAL源码 (源码分析)
stm32·单片机·嵌入式硬件
WWJA王文举7 小时前
Bootloader、App 和升级分区之间是什么关系?
stm32·freertos·嵌入式开发·在线升级
LCG元8 小时前
STM32F103 NTC 热敏电阻测温实战:分压网络设计、Steinhart-Hart 标定与 ADC 采样优化实测
stm32·单片机·嵌入式硬件
怀民民民9 小时前
嵌入式软件学习路线与项目实践记录:STM32、FreeRTOS、Linux 与 OpenMV
stm32·freertos·嵌入式软件·嵌入式linux·openmv
辰域电子10 小时前
STM32项目开源:实验室消防预警控制系统(代码 + 原理图 + 仿真)
stm32·单片机·嵌入式硬件·开源·proteus
ysu_03141 天前
TinyML 模型部署:从 Edge Impulse 到 STM32F103
驱动开发·stm32·嵌入式硬件·mcu·硬件架构·硬件工程·dsp开发
糖糖单片机设计1 天前
基于STM32的电子密码锁设计与实现(矩阵键盘+防拆检测+GSM远程报警)
人工智能·stm32·单片机·嵌入式硬件