本帖最后由 lulugl 于 2023-8-7 17:52 编辑

时钟.jpg

【感谢】感谢面包板论坛,感谢瑞萨,能为我提供这个RA4E1开发板的试用机会。

【前言】我前后试用的瑞萨的多款开发板,都给我留下很好的印象。这次是我第一次在面包板社区参与评测活动。拿到开发板后,我认真的阅读了官方的资料,结合我以前的经验,移植了一个OLED显示时间的示例。示例中用到了硬件I2C驱动、RTC驱动,结合在一起我制作了一个综合示例。现在将示例的制作过程分享如下:

一、新建工程:

1、打开RASC,新建工程如下图所示:

forum.jpg

选择FSP,我这里选4.2版本的,再选择芯片,按昭下图指引,再选择生成目标工程,我这里选择mdk5,然后选择下一步:

forum.jpg

选择非安全分离的选项,如下:

forum.jpg

选择非操作系统:

forum.jpg

选择默认,点击finish生成工程:

forum.jpg

要显示时间,我们这里驱动OLED屏,为i2c接口的ssd1306,我们这里配置iic_master stack

forum.jpg

配置i2c0的地址、IO、中断回调函数、如下图:

forum.jpg

为是获取时间,我们还需要开启RTC,用周期中断来获取时间。如下图所示添加RTC

forum.jpg

配置RTC的中断回调函数、开启同期中断。配置如下图所示:

forum.jpg

生成工程:

forum.jpg

到此rasc配置生成工程结束,rasc为我们做了很多前期的工作,使得后面的工作只需要实现指定的中断回调,以及实现指定的功能。

工程代码实现:

打开工程,找到colock文件夹下面,打开mdk工程:

forum.jpg

打开工程后,我们编译,会报错,就是我们的RTC、I2C中断回调函数没有实现:

forum.jpg

RASC,在生成功工程时,已经帮我把把i2c的低层代码实现,我们只需要执行R_IIC_MASTER_Open就可以了代码为:

err =R_IIC_MASTER_Open(&g_i2c_master0_ctrl, &g_i2c_master0_cfg);

   assert(FSP_SUCCESS == err);

同时我们定义一个i2c中断枚举的变量:i2c_master_event_t g_i2c_callback_event = I2C_MASTER_EVENT_ABORTED;

在中断回调中,我们更新这个标志位,以便程序中判断数据发送与接收的情况,中断回调函数如下:

void i2c_callback(i2c_master_callback_args_t * p_args)

{


g_i2c_callback_event = I2C_MASTER_EVENT_ABORTED;

    if (NULL != p_args)

    {

        /* capture callback event for validating the i2c transfer event*/

        g_i2c_callback_event = p_args->event;

    }

}

OLED驱动,oled驱动,我们移植从其他工程上的代码过来,我们只需要更新一个oledinit、i2cwritebite两个函数就行了。在OLED_I2C_Init中,我们打开i2c然后判断打开情况:

fsp_err_t err;

void OLED_I2C_Init(void)

{



err =R_IIC_MASTER_Open(&g_i2c_master0_ctrl, &g_i2c_master0_cfg);

   assert(FSP_SUCCESS == err);

}

在I2C_WriteByte函数中,我们首先组装发送字符数据,主要是区分向ssd1306发送的是写命令,还是写数据,然后用系统的函数来发送数据,并且对发送情况进行判断,如果发送结束了就返回。同时添加了一个超时标志,如果发送超时也会退出。代码如下:

//向OLED寄存器地址写一个byte的数据

int I2C_WriteByte(uint8_t mode,uint8_t data)

{


uint8_t g_txBuff[2] = {0};


uint16_t timeout_ms = 0;


if(mode)



g_txBuff[0] = 0x40;


else



g_txBuff[0] = 0x000;


g_txBuff[1] = data;



err = R_IIC_MASTER_Write(&g_i2c_master0_ctrl, g_txBuff,2,true);

//


assert(FSP_SUCCESS == err);


timeout_ms = 10;



while((I2C_MASTER_EVENT_TX_COMPLETE != g_i2c_callback_event) && timeout_ms)


{



R_BSP_SoftwareDelay(100U, BSP_DELAY_UNITS_MICROSECONDS);



timeout_ms--;


}


g_i2c_callback_event = I2C_MASTER_EVENT_ABORTED;




return 0;

}

其余,还有就是修改一下延时函数,使用R_BSP_SoftwareDelay(500,BSP_DELAY_UNITS_MILLISECONDS);

OlED驱动好后,我们继续添加RTC的代码。

RTC时钟模块是一个时间外设,主要用于日期时间的存储和控制,有别于一般MCU中的Timer,RTC时钟有两种计时模式,日期模式和计时模式,RTC常见的操作包括设置时间、设置定时闹铃、配置周期性中断以及启动或停止操作。

我们这个示例主要使用RTC的日期与周期中断,利用每一秒中断,来更新OLED的显示标志。

用R_RTC_Open()函数进行初始化和开启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);

用R_RTC_CalendarTimeGet ()函数进行获取RTC计数时间。

R_RTC_CalendarTimeGet(&g_rtc0_ctrl, &get_time);//获取RTC计数时间

用R_RTC_PeriodicIrqRateSet()函数进行设置周期中断

/* Set the periodic interrupt rate to 1 second */

    R_RTC_PeriodicIrqRateSet(&g_rtc0_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);

我们赋与初值:

rtc_time_t set_time =

{

    .tm_sec  = 0,      /* 秒,范围从 0 到 59 */

    .tm_min  = 30,      /* 分,范围从 0 到 59 */

    .tm_hour = 12,      /* 小时,范围从 0 到 23*/

    .tm_mday =

06

,       /* 一月中的第几天,范围从 1 到 31*/

    .tm_mon  =

08

,      /* 月份,范围从 0 到 11*/

    .tm_year = 12

3

,     /* 自 1900 起的年数,2021为121*/

    .tm_wday = 5,       /* 一周中的第几天,范围从 0 到 6*/

//    .tm_yday=0,         /* 一年中的第几天,范围从 0 到 365*/

//    .tm_isdst=0;        /* 夏令时*/

};

在初始化时,更新RTC时间。

我们添回RTC中断函数,如果1秒产生了中断,则更新标与,以便主程序查询到标志。

/* 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;

}

在主程序中,我们查询RTC周期中断标志,如果标与更新了,则获取当时RTC时间,更新OLED显示:

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;


while(1)


{



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;//周




H1 = rtc_hour/10;




H2 = rtc_hour%10;




M1 = rtc_minute/10;




M2 = rtc_minute%10;




S1 = rtc_second/10;




S2 = rtc_second%10;



}



Draw_Rolling_Clock();


以上是编程的思路,程序源码,我附在附件中。

【注意事项】

生成的工程中有几点需要注意

1、工程中不要有中文路径,要不mdk编译时会提示找不到文件。

2、打开例程时,需要用RASC重新生成一下工程,要不会提示找不到源文件。

3、生成的示例,在Flash Download时里面没有正确配置内存起始、长度,需要我们手工添加:

image.png

4、在使用SEGGER——RTT打印时,不同的固件,连接地址也不时,大家可以打开.map文件,找到_SEGGER_RTT地址,来指定,要不会看不到打印内容:

image.png

image.png


6、FSP现在版本更新很快,有些低版本与新版本的工程不一定兼容。

【总结】

RA4E1这款芯片性价比非常高,在低功耗领域可以应该在许多的工程之中。

【附工程源码】 clock.zip (1.11 MB, 下载次数: 1)

全部回复 1
  • 69 主题
  • 113 帖子
  • 1725 积分
身份:LV4 高级技术员
E币:1694
视频介绍:https://www.bilibili.com/video/BV1XX4y177tV/?vd_source=e1bd226340c8b87027d5dcfc6b0c3344
回复楼主
您需要登录后才可以评论 登录 立即注册