实验要求:每1s输出一次最新RTC时间。定时把RTC时间存入到FLASH中,当系统重新启动后,能够恢复FLASH中的RTC时间,继续进行计时。
项目下载地址:https://pan.baidu.com/s/1NGh6u9MMCn_9fhaP8DopKg 提取码:whv6
实验思路:系统上电后先读取fatfs文件信息,当读到time标志后将后面的时间数据提取出来进行解析并赋值给my_sTime和my_sDate,如果没有读到time标志则认为fatfs数据不可用 并给my_sTime和my_sDate赋默认值,进入主循环后获取当前时间并输出,然后将当前信息存储到SD卡中,延时1s。
主函数中代码较多,所以讲挂载、格式化、读磁盘状态、读文件、写文件的相应代码分别封装成函数以便使用。
函数详解:
写文件:
void file_write(uint8_t res, FIL *pf, RTC_TimeTypeDef *my_sTime, RTC_DateTypeDef *my_sDate)
{
res = f_open(pf, "0:/test.txt", FA_OPEN_ALWAYS | FA_WRITE);
if (res == FR_OK)
{
printf("creat ok\n");
}
else
{
printf("creat failed\n");
printf("error code: %d\n",res);
}
// char tr1[]="1234567890abc!\n";
f_printf(pf, "time%d-%d-%d %d:%d:%d*",my_sDate->Year, my_sDate->Month, my_sDate->Date, my_sTime->Hours, \
my_sTime->Minutes, my_sTime->Seconds); // 格式化输出
//f_printf(pf, "0000000000000000000000000000000000000000000000000000");
res = f_close(pf);
if (res != FR_OK)
{
printf("close file error\n");
printf("error code: %d\n",res);
}
else
{
// printf("write data OK");
}
}
将时间数据格式化写入SD卡,并在数据前加上time作为标志。
读文件:
uint8_t *file_read(uint8_t res, FIL *file, uint8_t num)
{
//FIL file;
//FRESULT res;
unsigned int bw;
uint8_t static rbuf[100] = {0};
res = f_open(file, "0:/test.txt", FA_READ);
if (res != FR_OK)
{
printf("open error: %d\n",res);
}
else
{
f_read(file, rbuf, num, &bw);
printf("read data:%s\n", rbuf);
res = f_close(file);
if (res != FR_OK)
{
printf("close file error\n");
printf("error code: %d\n",res);
}
}
return rbuf;
}
传入参数新增num,用来控制读取几个字节数据。
时间字符串解析:
void fuckme(uint8_t *buf)
{
int i = 5;
while(buf[i] != '-' && buf[i] != ':')
i++;
year = (buf[i-2]-0x30)*10 + (buf[i-1]-0x30);
i++;
while(buf[i] != '-' && buf[i] != ':')
i++;
if(buf[i-2] == '-' || buf[i-2] == ':')
month = (buf[i-1]-0x30);
else
month = (buf[i-2]-0x30)*10 + (buf[i-1]-0x30);
if(buf[i+2] == 0x20)
date = (buf[i+1]-0x30);
else
date = (buf[i+1]-0x30)*10 + (buf[i+2]-0x30);
i++;
while(buf[i] != '-' && buf[i] != ':')
i++;
if(buf[i-2] == '-' || buf[i-2] == ':' || buf[i-2] == 0x20)
hour = (buf[i-1]-0x30);
else
hour = (buf[i-2]-0x30)*10 + (buf[i-1]-0x30);
i++;
while(buf[i] != '-' && buf[i] != ':')
i++;
if(buf[i-2] == '-' || buf[i-2] == ':')
minutes = (buf[i-1]-0x30);
else
minutes = (buf[i-2]-0x30)*10 + (buf[i-1]-0x30);
if(buf[i+2] == '*')
seconds = (buf[i+1]-0x30);
else
seconds = (buf[i+1]-0x30)*10 + (buf[i+2]-0x30);
}
在SD卡中有时间数据的情况下将读到的数据进行解析,这块代码有些繁琐,有更好的方法请教教我。
主函数逻辑:
rebuf = file_read(res, &file, 4);
if (!strcmp(rebuf, "time"))
{
f_read(&file, rbuf, 25, &bw);
fuckme(rbuf);
RTC_init(hour, minutes, seconds, 1, date, month, year);
}
else
RTC_init(1,1,1,1,1,1,19);
while (1)
{
RTC_TimeTypeDef my_sTime;
RTC_DateTypeDef my_sDate;
HAL_RTC_GetTime(&hrtc,&my_sTime,RTC_FORMAT_BIN);
printf("%d:%d:%d ",my_sTime.Hours,my_sTime.Minutes,my_sTime.Seconds);
HAL_RTC_GetDate(&hrtc,&my_sDate,RTC_FORMAT_BIN);
printf("%d-%d-%d\n",my_sDate.Year,my_sDate.Month,my_sDate.Date);
file_write(res, pf, &my_sTime, &my_sDate);
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
}
这块为了方便理解,我把和逻辑无关的代码都去掉了(只是为了更好理解,程序中必须写全)。先读4个字节并判断是不是“time”,是的话再从头读25个字节,通过fuckme函数解析数据(解析好的数据在函数中已经赋值给hour、minuts…)调用时钟初始化函数。否则将时间修改为默认值19-1-1 1:1:1。在while循环内疯狂获取时间、输出时间、向SD卡写入时间数据、延时1s。
实验效果:
当SD卡中没有时间数据时:
当SD卡中有时间数据时:
项目的实现和实验要求并非完全相同,项目代码还需稍加修改。