0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于RASC的keil电子时钟制作(瑞萨RA)(9)----保存数据到flash

嵌入式单片机MCU开发 来源:嵌入式单片机MCU开发 作者:嵌入式单片机MCU开 2023-12-01 15:12 次阅读

概述

本篇文章主要介绍如何使用e2studio对瑞萨进行Flash配置,并且分别对Code Flash & Data Flash进行读写操作。
Flash有Code Flash(储存程序代码)以及Data Flash(储存一般数据),其中Code Flash主要以NOR型为主,储存系统程序代码及小量数据;而Data Flash则是以NAND型为主,用于储存大量数据。

硬件准备

首先需要准备一个开发板,这里我准备的是芯片型号R7FA2E1A72DFL的开发板:

在这里插入图片描述

在这里插入图片描述

视频教程

https://www.bilibili.com/video/BV1PM4y1p7Ue/

Flash

对Code Flash进行读写操作时候,特别要注意写的地址,因为如果写的不对,会覆盖到代码区,造成运行错误,同时对于擦除,是一块的数据都会直接擦除掉。
在RA2E1中,Code flash最高为128KB,Data flash为4KB。
在这里插入图片描述

FLASH配置

点击Stacks->New Stack->Storage -> Flash (r_flash_lp)。

在这里插入图片描述

FLASH属性配置

在这里插入图片描述

Data Flash

对Data Flash进行读写操作时候,特别要注意要等待Data Flash写完才能进行后续读写操作。
在RA2E1中,Data Flash分布如下所示。
在这里插入图片描述

回调函数的话有下列事件会进行触发。

在这里插入图片描述
建flash_smg.c和flash_smg.h。
在主程序中加入该头文件
在这里插入图片描述

回调函数如下所示,在flash_smg.c里。

volatile bool               interrupt_called;
volatile flash_event_t      flash_event;


void flash_callback (flash_callback_args_t * p_args)
{
    interrupt_called = true;
    flash_event      = p_args- >event;
}

向Block0种写入时间分钟数据和小时数据,地址范围是0x40100000 - 0x40100FFF,在flash_smg.c里定义

extern fsp_err_t err ;
/*FLASH写入程序*/
void WriteFlashTest(uint32_t L,uint8_t Data[],uint32_t addr)
{


    interrupt_called = false;
    /* Erase 1 block of data flash starting at block 0. */
    err = R_FLASH_LP_Erase(&g_flash0_ctrl, FLASH_DF_BLOCK_0, 1);
    assert(FSP_SUCCESS == err);
    while (!interrupt_called)
    {
    ;
    }
    assert(FLASH_EVENT_ERASE_COMPLETE == flash_event);
    interrupt_called = false;
    flash_status_t status;
    /* Write 32 bytes to the first block of data flash. */
    err = R_FLASH_LP_Write(&g_flash0_ctrl, (uint32_t) Data, addr, L);
    assert(FSP_SUCCESS == err);

    /* Wait until the current flash operation completes. */
    do
    {
        err = R_FLASH_LP_StatusGet(&g_flash0_ctrl, &status);
    } while ((FSP_SUCCESS == err) && (FLASH_STATUS_BUSY == status));


    /* If the interrupt wasn't called process the error. */
    assert(interrupt_called);
    /* If the event wasn't a write complete process the error. */
    assert(FLASH_EVENT_WRITE_COMPLETE == flash_event);
    /* Verify the data was written correctly. */
    assert(0 == memcmp(Data, (uint8_t *) FLASH_DF_BLOCK_0, L));


}

在主程序中定义标志位进行数据保存判断。

volatile uint8_t g_src_uint8[4]={0x00,0x00,0x00,0x00};//时间保存在该数组里面
volatile uint8_t  g_src_uint8_length=4;
uint8_t flash_flag=0;//保存时间数据,一半在每过一分钟或者按键修改时间

在这里插入图片描述

在main主程序中,定义在按键修改完毕数据后进行保存。

if(flash_flag)//按键修改完毕数据后进行保存
           {
               g_src_uint8[0]=hour;
               g_src_uint8[1]=min;
               WriteFlashTest(4,g_src_uint8 ,FLASH_DF_BLOCK_0);
               flash_flag=0;
           }

在这里插入图片描述
同时需要在按键设置完毕进行数据保存,模式3中需要定义标志位为1。

flash_flag=1;//保存数据

在这里插入图片描述

同时需要注意变量引入到timer_smg.c。

extern uint8_t flash_flag;//保存时间数据,一半在每过一分钟或者按键修改时间

在这里插入图片描述

同时在RTC时钟走到0秒时候保存一次数据。

g_src_uint8[0]=hour;
                   g_src_uint8[1]=min;
                   WriteFlashTest(4,g_src_uint8 ,FLASH_DF_BLOCK_0);

在这里插入图片描述

读取函数如下所示,在flash_smg.h中。

extern int sec,min,hour;//保存时间数据
/*FLASH读取打印程序*/
void PrintFlashTest(uint32_t addr)
{
    hour=*(__IO uint8_t*)(addr);
    min=*(__IO uint8_t*)(addr+1);

    if(hour >=24)
        hour=0;
    if(min >=60)
        min=0;
}

同时在主程序中开启flash以及将保存的数据读取出来。
由于需要在RTC开启时放入该数据 ,故需要放在RTC开启前面。

/**********************data flash***************************************/
       flash_result_t blank_check_result;
       /* Open the flash lp instance. */
    	err = R_FLASH_LP_Open(&g_flash0_ctrl, &g_flash0_cfg);
       assert(FSP_SUCCESS == err);

//       WriteFlashTest(4,g_src_uint8 ,FLASH_DF_BLOCK_0);

       PrintFlashTest(FLASH_DF_BLOCK_0);


       set_time.tm_sec=0;//时间数据 秒
       set_time.tm_min=min;//时间数据 分钟
       hour=set_time.tm_hour=hour;//时间数据 小时

在这里插入图片描述

flash_smg.c

/*
 * flash_smg.c
 *
 *  Created on: 2023年7月5日
 *      Author: a8456
 */
#include "flash_smg.h"

volatile bool               interrupt_called;
volatile flash_event_t      flash_event;


void flash_callback (flash_callback_args_t * p_args)
{
    interrupt_called = true;
    flash_event      = p_args- >event;
}


extern fsp_err_t err ;
/*FLASH写入程序*/
void WriteFlashTest(uint32_t L,uint8_t Data[],uint32_t addr)
{


    interrupt_called = false;
    /* Erase 1 block of data flash starting at block 0. */
    err = R_FLASH_LP_Erase(&g_flash0_ctrl, FLASH_DF_BLOCK_0, 1);
    assert(FSP_SUCCESS == err);
    while (!interrupt_called)
    {
    ;
    }
    assert(FLASH_EVENT_ERASE_COMPLETE == flash_event);
    interrupt_called = false;
    flash_status_t status;
    /* Write 32 bytes to the first block of data flash. */
    err = R_FLASH_LP_Write(&g_flash0_ctrl, (uint32_t) Data, addr, L);
    assert(FSP_SUCCESS == err);

    /* Wait until the current flash operation completes. */
    do
    {
        err = R_FLASH_LP_StatusGet(&g_flash0_ctrl, &status);
    } while ((FSP_SUCCESS == err) && (FLASH_STATUS_BUSY == status));


    /* If the interrupt wasn't called process the error. */
    assert(interrupt_called);
    /* If the event wasn't a write complete process the error. */
    assert(FLASH_EVENT_WRITE_COMPLETE == flash_event);
    /* Verify the data was written correctly. */
    assert(0 == memcmp(Data, (uint8_t *) FLASH_DF_BLOCK_0, L));


}

extern int sec,min,hour;//保存时间数据
/*FLASH读取打印程序*/
void PrintFlashTest(uint32_t addr)
{
    hour=*(__IO uint8_t*)(addr);
    min=*(__IO uint8_t*)(addr+1);

    if(hour >=24)
        hour=0;
    if(min >=60)
        min=0;
}

flash_smg.h

/*
 * flash_smg.h
 *
 *  Created on: 2023年6月29日
 *      Author: a8456
 */

#ifndef FLASH_SMG_H_
#define FLASH_SMG_H_

#include "hal_data.h"

#define FLASH_DF_BLOCK_0                0x40100000U/*   1 KB: 0x40100000 - 0x401003FF */

/*FLASH写入程序*/
void WriteFlashTest(uint32_t L,uint8_t Data[],uint32_t addr);
/*FLASH读取打印程序*/
void PrintFlashTest(uint32_t addr);

#endif /* FLASH_SMG_H_ */

主程序

#include "hal_data.h"
#include < stdio.h >
#include "smg.h"
#include "timer_smg.h"
#include "flash_smg.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

//数码管变量
uint8_t num1=1,num2=4,num3=6,num4=8;//4个数码管显示的数值
uint8_t num_flag=0;//4个数码管和冒号轮流显示,一轮刷新五次

//RTC变量
/* rtc_time_t is an alias for the C Standard time.h struct 'tm' */
rtc_time_t set_time =
{
    .tm_sec  = 50,      /* 秒,范围从 0 到 59 */
    .tm_min  = 59,      /* 分,范围从 0 到 59 */
    .tm_hour = 23,      /* 小时,范围从 0 到 23*/
    .tm_mday = 29,       /* 一月中的第几天,范围从 0 到 30*/
    .tm_mon  = 11,      /* 月份,范围从 0 到 11*/
    .tm_year = 123,     /* 自 1900 起的年数,2023为123*/
    .tm_wday = 6,       /* 一周中的第几天,范围从 0 到 6*/
//    .tm_yday=0,         /* 一年中的第几天,范围从 0 到 365*/
//    .tm_isdst=0;        /* 夏令时*/
};


//RTC闹钟变量
rtc_alarm_time_t set_alarm_time=
{
     .time.tm_sec  = 58,      /* 秒,范围从 0 到 59 */
     .time.tm_min  = 59,      /* 分,范围从 0 到 59 */
     .time.tm_hour = 23,      /* 小时,范围从 0 到 23*/
     .time.tm_mday = 29,       /* 一月中的第几天,范围从 1 到 31*/
     .time.tm_mon  = 11,      /* 月份,范围从 0 到 11*/
     .time.tm_year = 123,     /* 自 1900 起的年数,2023为123*/
     .time.tm_wday = 6,       /* 一周中的第几天,范围从 0 到 6*/

     .sec_match        =  1,//每次秒到达设置的进行报警
     .min_match        =  0,
     .hour_match       =  0,
     .mday_match       =  0,
     .mon_match        =  0,
     .year_match       =  0,
     .dayofweek_match  =  0,
    };

bsp_io_level_t sw1;//按键SW1状态
bsp_io_level_t sw2;//按键SW2状态
bsp_io_level_t sw3;//按键SW3状态
bsp_io_level_t sw4;//按键SW4状态
bsp_io_level_t qe_sw;//触摸电容状态

int sw1_num1=0;//按键SW1计数值,去抖和长按短按判断
int sw2_num1=0;//按键SW2计数值,去抖和长按短按判断
int sw3_num1=0;//按键SW3计数值,去抖和长按短按判断
int sw4_num1=0;//按键SW4计数值,去抖和长按短按判断
int qe_sw_num1=0;//触摸按键计数值,去抖和长按短按判断
void qe_touch_sw(void);

//数码管显示状态,0正常显示,1修改小时,2修改分钟,3保存修改数据,4温度,5湿度
int smg_mode=0;
int sec=0,min=0,hour=0;//保存时间数据
uint16_t time_mode_num=0;//定时器刷新时间,实现闪烁效果

volatile uint8_t g_src_uint8[4]={0x00,0x00,0x00,0x00};//时间保存在该数组里面
volatile uint8_t  g_src_uint8_length=4;
uint8_t flash_flag=0;//保存时间数据,一半在每过一分钟或者按键修改时间


//RTC回调函数
volatile bool rtc_flag = 0;//RTC延时1s标志位
volatile bool rtc_alarm_flag = 0;//RTC闹钟
/* Callback function */
void rtc_callback(rtc_callback_args_t *p_args)
{
    /* TODO: add your own code here */
    if(p_args- >event == RTC_EVENT_PERIODIC_IRQ)
        rtc_flag=1;
    else if(p_args- >event == RTC_EVENT_ALARM_IRQ)
        rtc_alarm_flag=1;
}


fsp_err_t err = FSP_SUCCESS;
volatile bool uart_send_complete_flag = false;
void user_uart_callback (uart_callback_args_t * p_args)
{
    if(p_args- >event == UART_EVENT_TX_COMPLETE)
    {
        uart_send_complete_flag = true;
    }
}

#ifdef __GNUC__                                 //串口重定向
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
        err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
        if(FSP_SUCCESS != err) __BKPT();
        while(uart_send_complete_flag == false){}
        uart_send_complete_flag = false;
        return ch;
}

int _write(int fd,char *pBuffer,int size)
{
    for(int i=0;i< size;i++)
    {
        __io_putchar(*pBuffer++);
    }
    return size;
}


/*******************************************************************************************************************//**
 * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
 * is called by main() when no RTOS is used.
 **********************************************************************************************************************/
void hal_entry(void)
{
    /* TODO: add your own code here */

    /* Open the transfer instance with initial configuration. */
       err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
       assert(FSP_SUCCESS == err);
/**********************数码管测试***************************************/
//              ceshi_smg();
/**********************定时器开启***************************************/
    /* Initializes the module. */
    err = R_GPT_Open(&g_timer0_ctrl, &g_timer0_cfg);
    /* Handle any errors. This function should be defined by the user. */
    assert(FSP_SUCCESS == err);
    /* Start the timer. */
    (void) R_GPT_Start(&g_timer0_ctrl);

/**********************data flash***************************************/
    flash_result_t blank_check_result;
    /* Open the flash lp instance. */
    err = R_FLASH_LP_Open(&g_flash0_ctrl, &g_flash0_cfg);
    assert(FSP_SUCCESS == err);

    //       WriteFlashTest(4,g_src_uint8 ,FLASH_DF_BLOCK_0);

    PrintFlashTest(FLASH_DF_BLOCK_0);


    set_time.tm_sec=0;//时间数据 秒
    set_time.tm_min=min;//时间数据 分钟
    hour=set_time.tm_hour=hour;//时间数据 小时



/**********************RTC开启***************************************/
    /* Initialize the RTC module*/
    err = R_RTC_Open(&g_rtc0_ctrl, &g_rtc0_cfg);
    /* Handle any errors. This function should be defined by the user. */
    assert(FSP_SUCCESS == err);

    /* Set the RTC clock source. Can be skipped if "Set Source Clock in Open" property is enabled. */
    R_RTC_ClockSourceSet(&g_rtc0_ctrl);

/* R_RTC_CalendarTimeSet must be called at least once to start the RTC */
    R_RTC_CalendarTimeSet(&g_rtc0_ctrl, &set_time);
    /* Set the periodic interrupt rate to 1 second */
    R_RTC_PeriodicIrqRateSet(&g_rtc0_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);

           R_RTC_CalendarAlarmSet(&g_rtc0_ctrl, &set_alarm_time);
           uint8_t rtc_second= 0;      //秒
           uint8_t rtc_minute =0;      //分
           uint8_t rtc_hour =0;         //时
           uint8_t rtc_day =0;          //日
           uint8_t rtc_month =0;      //月
           uint16_t rtc_year =0;        //年
           uint8_t rtc_week =0;        //周
           rtc_time_t get_time;


           sec=set_time.tm_sec;//时间数据 秒
            min=set_time.tm_min;//时间数据 分钟
            hour=set_time.tm_hour;//时间数据 小时

       while(1)
       {
           if(flash_flag)//按键修改完毕数据后进行保存
           {
               g_src_uint8[0]=hour;
               g_src_uint8[1]=min;
               WriteFlashTest(4,g_src_uint8 ,FLASH_DF_BLOCK_0);
               flash_flag=0;
           }


           if(rtc_flag)
           {
               R_RTC_CalendarTimeGet(&g_rtc0_ctrl, &get_time);//获取RTC计数时间
               rtc_flag=0;
               rtc_second=get_time.tm_sec;//秒
               rtc_minute=get_time.tm_min;//分
               rtc_hour=get_time.tm_hour;//时
               rtc_day=get_time.tm_mday;//日
               rtc_month=get_time.tm_mon;//月
               rtc_year=get_time.tm_year; //年
               rtc_week=get_time.tm_wday;//周
               printf(" %d y %d m %d d %d h %d m %d s %d wn",rtc_year+1900,rtc_month,rtc_day,rtc_hour,rtc_minute,rtc_second,rtc_week);

                //时间显示
               num1=rtc_hour/10;
               num2=rtc_hour%10;

               num3=rtc_minute/10;
               num4=rtc_minute%10;
               if(rtc_second==0&&smg_mode==0)//这个时候刷新变量
               {
                   sec=rtc_second;//时间数据 秒
                   min=rtc_minute;//时间数据 分钟
                   hour=rtc_hour;//时间数据 小时

                   g_src_uint8[0]=hour;
                   g_src_uint8[1]=min;
                   WriteFlashTest(4,g_src_uint8 ,FLASH_DF_BLOCK_0);


               }
           }
           if(rtc_alarm_flag)
           {
               rtc_alarm_flag=0;
               printf("/************************Alarm Clock********************************/n");
           }
           set_smg_button();
           R_BSP_SoftwareDelay(10U, BSP_DELAY_UNITS_MILLISECONDS);
       }

#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FlaSh
    +关注

    关注

    10

    文章

    1551

    浏览量

    146671
  • 瑞萨
    +关注

    关注

    32

    文章

    22214

    浏览量

    84915
  • keil
    +关注

    关注

    68

    文章

    1196

    浏览量

    165315
  • 电子时钟
    +关注

    关注

    11

    文章

    197

    浏览量

    24124
收藏 人收藏

    评论

    相关推荐

    基于RASCkeil电子时钟制作(瑞萨RA)(1)----安装RASC

    RA Smart Configurator"是一种基于"灵活组合软件"概念的代码生成辅助工具。它可以自动生成微控制器的初始配置程序。该工具提供了基本的引脚配置功能,并提
    的头像 发表于 12-01 14:39 347次阅读
    基于<b class='flag-5'>RASC</b>的<b class='flag-5'>keil</b><b class='flag-5'>电子时钟</b><b class='flag-5'>制作</b>(瑞萨<b class='flag-5'>RA</b>)(1)----安装<b class='flag-5'>RASC</b>

    基于RASCkeil电子时钟制作(瑞萨RA)(2)----配置keil以及使用串口进行打印

    本篇文章主要介绍了一种基于瑞萨RA系列微控制器的电子时钟制作方法,重点关注如何利用瑞萨RA Smart Configurator生成串口配置,以及在具体实践中如何对瑞萨
    的头像 发表于 12-01 14:47 389次阅读
    基于<b class='flag-5'>RASC</b>的<b class='flag-5'>keil</b><b class='flag-5'>电子时钟</b><b class='flag-5'>制作</b>(瑞萨<b class='flag-5'>RA</b>)(2)----配置<b class='flag-5'>keil</b>以及使用串口进行打印

    RA4系列开发板体验】+ Keil环境下的LED编程

    我使用了Keil软件进行了LED程序的开发。一、开发环境的建立1、安装Keil编程软件。我想,凡是参加该活动的朋友的计算机里面肯定已经安装了Keil软件。2、安装RA软件包。该软件可以
    发表于 11-14 21:56

    RA4系列开发板体验】开发环境搭建和新手点灯指南

    RA4系列开发板体验】开发环境搭建和新手点灯指南修改记录:2022-11-20 初版开始2022-11-24 初版完成本文介绍将如何从零搭建RA4M2
    发表于 11-24 22:54

    RA4系列开发板体验】Keil开发环境搭建+初探IO操作

    前言: 非常感谢电子发烧友和生态工作室能够给这次试用开发板的机会,后续根据生RA态工作室提供的资料进行功能测试。此篇根据RA Smart
    发表于 11-29 14:50

    RA4系列开发板体验】开箱

    首先感谢电子 & 电子发烧友给与的机会。RA-Eco-RA4M2-100PIN基于R7FA4M2AD3CFP MCU,采用了Co
    发表于 12-05 08:28

    RA4系列开发板体验】10. 我的试用总结

    之前发帖:【RA4系列开发板体验】1. 新建工程+按键控制LED【RA4系列开发板体验】
    发表于 12-10 22:34

    RA4系列开发板体验】1、开发板要来了(1)

    了,先体现进行一下准备工作。由于板子还没有到手,咱们主要先了解一下开发环境。RA系列的单片机有一个自己的开发环境e2 studio,这个是官方首推的,是
    发表于 12-12 17:04

    RA4系列开发板体验】体验过程

    、使用 RASC 生成 Keil 工程+点亮LED参照“ 【RA4系列开发板体验】2. 使用RASC
    发表于 12-18 16:20

    RA4系列开发板体验】+ 开发环境搭建

    pack就可以支持RA系列所有的MCU。这个pack可以从官网下载。安装之后,需要新建一个keil的工程。这里必须要使用RA Smart
    发表于 12-21 23:50

    RA4M2设计挑战赛】1. RASC配置FreeRTOS

    过往分享下面是参加RA4M2使用活动的分享:【RA4系列开发板体验】1. 新建工程+按键控制LED【
    发表于 02-11 19:17

    RA4M2-KEIL-RTOS+使用线程方式驱动LED

    一、前言RA4M2开发板能够使用KEIL编写程序,并调试,但是使用JLINK下载的话要注版本,开发板自带串口下载,使用USB-TPYE-C下载线使用公司的芯片程序下载软件也能够快速
    发表于 03-05 21:56

    FPB-RA6E1快速原型板】简单开箱和RASC+Keil开发环境搭建

    不支持RA系列MCU,需要安装RA系列MCU Keil支持包才能支持RA系列MCU。 FSP
    发表于 05-22 23:13

    FPB-RA6E1快速原型板】CoreMark移植完全指南——UART输出和SysTick计时

    性能的程序,类似PC上的Cinebench、CPU-Z之类的CPU性能测试工具。 了解了CoreMark是什么之后,接下来我们尝试在FPB-RA6E1快速原型板上跑一下CoreMark,看看分数
    发表于 05-28 17:18

    FPB-RA6E1快速原型板】使用TinyMaix识别手写数字

    中找到。 所以,在我们这次试用的主角FPB-RA6E1快速原型板上运行TinyMaix完全是没有任何压力的(1MB Flash 256KB SRAM)。接下来,我将介绍如何在
    发表于 06-04 21:39