自学内容网 自学内容网

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)!