keil electronic clock production based on RASC (Renesas RA) (8) - button to modify the digital tube time

Based on RASC-based keil electronic clock production 8_ button to modify the digital tube time

overview

In the previous courses, the digital tube and RTC have been driven separately. At the same time, the digital tube has been integrated to display the specific time, but the time cannot be modified. In this section, we will configure the use of buttons to modify the specific date.

hardware preparation

First, you need to prepare a development board. Here I am preparing a development board with chip model R7FA2E1A72DFL:

insert image description here

insert image description here

video tutorial

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

keil electronic clock production based on RASC (Renesas RA)----(8) button to modify the digital tube time

Configure button pins

The corresponding pins of the buttons here are as follows.
insert image description here

Configure the pin as input mode, and add a pull-up at the same time, so that the default level is high level, and the corresponding pin is low level when the button is pressed.
insert image description here

Key setting

You can use the R_IOPORT_PinRead() function to read the level status of the IO port. This function can only read the level of one port.
Define a variable to save the key state.

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;//定时器刷新时间,实现闪烁效果

insert image description here
Define the while loop of the main program to execute once every 10ms, which is convenient for key reading and time setting.

       R_BSP_SoftwareDelay(10U, BSP_DELAY_UNITS_MILLISECONDS);
 

Add variable definition in timer_smg.c.

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

extern int sw1_num1;//按键SW1计数值,去抖和长按短按判断
extern int sw2_num1;//按键SW2计数值,去抖和长按短按判断
extern int sw3_num1;//按键SW3计数值,去抖和长按短按判断
extern int sw4_num1;//按键SW4计数值,去抖和长按短按判断
extern int qe_sw_num1;//触摸按键计数值,去抖和长按短按判断

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

insert image description here

Set to press the sw1 button for 1 second to enter the next mode, sw2 to modify the time hour and minute downward, and sw3 to modify the time hour and minute upward.

void set_smg_button(void)
{
    
    

     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07, &sw1);
     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_08, &sw2);
     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_09_PIN_13, &sw3);
     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_09_PIN_14, &sw4);
    if(sw1+sw2+sw3+sw4==4&&qe_sw==0)//按键都没按下,清除按键按下计数值
     {
    
    
         sw1_num1=0;
         sw2_num1=0;
         sw3_num1=0;
         sw4_num1=0;
         qe_sw_num1=0;
     }
     else if(sw1==0&&sw2&&sw3&&sw4&&qe_sw==0)//只有SW1按下
     {
    
    
         if(sw1_num1<1001)//按下小于10s,1001是防止变量在1000时候一直切换模式
         sw1_num1++;
         if(sw1_num1%200==0)//模式切换,按下
         {
    
    
             //buzzer_num=20;//蜂鸣器叫200ms
             if(smg_mode>2)
                 smg_mode=0;
             else
             smg_mode++;
         }
         if(smg_mode==6)
             smg_mode=0;

     }
     else if(sw2==0&&sw1&&sw3&&sw4&&qe_sw==0)//只有SW2按下
     {
    
    
         if(sw2_num1<30)//300ms 减一次
             sw2_num1++;
         else
         {
    
    
             sw2_num1=0;
             if(smg_mode==1)
             {
    
    
                 if(hour>0)
                     hour--;
                 else
                     hour=23;

             }
             else if(smg_mode==2)
             {
    
    
                 if(min>0)
                     min--;
                 else
                     min=59;
             }
         }
     }
     else if(sw3==0&&sw1&&sw2&&sw4&&qe_sw==0)//只有SW3按下
     {
    
    
         if(sw3_num1<30)//300ms 减一次
             sw3_num1++;
         else
         {
    
    
             sw3_num1=0;
             if(smg_mode==1)
             {
    
    
                 if(hour<23)
                     hour++;
                 else
                     hour=0;

             }
             else if(smg_mode==2)
             {
    
    
                 if(min<59)
                     min++;
                 else
                     min=0;
             }
         }
     }



}

Add this function in timer_smg.c.
insert image description here

At the same time, it needs to be declared in timer_smg.h.

void set_smg_button(void);//处理数码管显示,当前状态修改

insert image description here

Since we need to modify our RTC clock value, we need to introduce a structure that defines RTC.

extern rtc_time_t set_time;//RTC时间定义

insert image description here
After the modification is completed, the digital tube can be flashed in the timer to remind the user.


void timer0_callback(timer_callback_args_t *p_args)
{
    
    
    /* TODO: add your own code here */
    if (TIMER_EVENT_CYCLE_END == p_args->event)
    {
    
    
        time_mode_num++;
        if(time_mode_num>200)
            time_mode_num=0;


        if(smg_mode==0)
        {
    
    
            if(num_flag==0)
                smg_1(num1);
            else if(num_flag==1)
                smg_2(num2);
            else if(num_flag==2)
                smg_3(num3);
            else if(num_flag==3)
                smg_4(num4);
            else if(num_flag==4)
                smg_maohao_open(1);   //冒号
        }
        else if(smg_mode==1)//修改时间小时
        {
    
    
            if(time_mode_num<100)
            {
    
    
                if(num_flag==0)
                    smg_1(hour/10);
                else if(num_flag==1)
                    smg_2(hour%10);
                else if(num_flag==2)
                    smg_3(min/10);
                else if(num_flag==3)
                    smg_4(min%10);
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
            else
            {
    
    
                if(num_flag==0)
                    smg_1_close();
                else if(num_flag==1)
                    smg_2_close();
                else if(num_flag==2)
                    smg_3(min/10);
                else if(num_flag==3)
                    smg_4(min%10);
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
        }
        else if(smg_mode==2)//修改时间分钟
        {
    
    
            if(time_mode_num<100)
            {
    
    
                if(num_flag==0)
                    smg_1(hour/10);
                else if(num_flag==1)
                    smg_2(hour%10);
                else if(num_flag==2)
                    smg_3(min/10);
                else if(num_flag==3)
                    smg_4(min%10);
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
            else
            {
    
    
                if(num_flag==0)
                    smg_1(hour/10);
                else if(num_flag==1)
                    smg_2(hour%10);
                else if(num_flag==2)
                    smg_3_close();
                else if(num_flag==3)
                    smg_4_close();
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
        }
        else if(smg_mode==3)//保存数据
        {
    
    
            set_time.tm_sec=sec;
            set_time.tm_min =min;
            set_time.tm_hour  =hour ;
            R_RTC_CalendarTimeSet(&g_rtc0_ctrl, &set_time);
            smg_mode=0;
        }



        num_flag++;
        if(num_flag==5)
            num_flag=0;
    }
}

When the initialization is complete, we need to save the time data.

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

insert image description here

In the main program, whenever the second is 0, save the minutes and hours data to min and hour, which is convenient for reading when setting the time and updating to the RTC after setting the time.

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

               } 

insert image description here
Add key processing function in the main program.

set_smg_button();

insert image description here

main program

#include "hal_data.h"
#include <stdio.h>
#include "smg.h"
#include "timer_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;//定时器刷新时间,实现闪烁效果




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


/**********************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(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 w\n",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;//时间数据 小时
               }
           }
           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
}

timer_smg.c

/*
 * timer_smg.c
 *
 *  Created on: 2023年7月3日
 *      Author: a8456
 */
#include "timer_smg.h"
//数码管变量
extern uint8_t num1,num2,num3,num4;//4个数码管显示的数值
extern uint8_t num_flag;//4个数码管和冒号轮流显示,一轮刷新五次

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

extern int sw1_num1;//按键SW1计数值,去抖和长按短按判断
extern int sw2_num1;//按键SW2计数值,去抖和长按短按判断
extern int sw3_num1;//按键SW3计数值,去抖和长按短按判断
extern int sw4_num1;//按键SW4计数值,去抖和长按短按判断
extern int qe_sw_num1;//触摸按键计数值,去抖和长按短按判断

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


extern rtc_time_t set_time;//RTC时间定义



void timer0_callback(timer_callback_args_t *p_args)
{
    
    
    /* TODO: add your own code here */
    if (TIMER_EVENT_CYCLE_END == p_args->event)
    {
    
    
        time_mode_num++;
        if(time_mode_num>200)
            time_mode_num=0;

        if(smg_mode==0)
        {
    
    
            if(num_flag==0)
            smg_1(num1);
            else if(num_flag==1)
            smg_2(num2);
            else if(num_flag==2)
            smg_3(num3);
            else if(num_flag==3)
            smg_4(num4);
            else if(num_flag==4)
            smg_maohao_open(1);   //冒号
        }
        else if(smg_mode==1)//修改时间小时
        {
    
    
            if(time_mode_num<100)
            {
    
    
                if(num_flag==0)
                    smg_1(hour/10);
                else if(num_flag==1)
                    smg_2(hour%10);
                else if(num_flag==2)
                    smg_3(min/10);
                else if(num_flag==3)
                    smg_4(min%10);
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
            else
            {
    
    
                if(num_flag==0)
                    smg_1_close();
                else if(num_flag==1)
                    smg_2_close();
                else if(num_flag==2)
                    smg_3(min/10);
                else if(num_flag==3)
                    smg_4(min%10);
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
        }
        else if(smg_mode==2)//修改时间分钟
        {
    
    
            if(time_mode_num<100)
            {
    
    
                if(num_flag==0)
                    smg_1(hour/10);
                else if(num_flag==1)
                    smg_2(hour%10);
                else if(num_flag==2)
                    smg_3(min/10);
                else if(num_flag==3)
                    smg_4(min%10);
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
            else
            {
    
    
                if(num_flag==0)
                    smg_1(hour/10);
                else if(num_flag==1)
                    smg_2(hour%10);
                else if(num_flag==2)
                    smg_3_close();
                else if(num_flag==3)
                    smg_4_close();
                else if(num_flag==4)
                    smg_maohao_open(1);   //冒号
            }
        }
        else if(smg_mode==3)//保存数据
        {
    
    
            set_time.tm_sec=sec;
            set_time.tm_min =min;
            set_time.tm_hour  =hour ;
            R_RTC_CalendarTimeSet(&g_rtc0_ctrl, &set_time);
            smg_mode=0;
        }



        num_flag++;
        if(num_flag==5)
            num_flag=0;





    }
}

void set_smg_button(void)
{
    
    

     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07, &sw1);
     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_08, &sw2);
     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_09_PIN_13, &sw3);
     R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_09_PIN_14, &sw4);
    if(sw1+sw2+sw3+sw4==4&&qe_sw==0)//按键都没按下,清除按键按下计数值
     {
    
    
         sw1_num1=0;
         sw2_num1=0;
         sw3_num1=0;
         sw4_num1=0;
         qe_sw_num1=0;
     }
     else if(sw1==0&&sw2&&sw3&&sw4&&qe_sw==0)//只有SW1按下
     {
    
    
         if(sw1_num1<1001)//按下小于10s,1001是防止变量在1000时候一直切换模式
         sw1_num1++;
         if(sw1_num1%200==0)//模式切换,按下
         {
    
    
             //buzzer_num=20;//蜂鸣器叫200ms
             if(smg_mode>2)
                 smg_mode=0;
             else
             smg_mode++;
         }
         if(smg_mode==6)
             smg_mode=0;

     }
     else if(sw2==0&&sw1&&sw3&&sw4&&qe_sw==0)//只有SW2按下
     {
    
    
         if(sw2_num1<30)//300ms 减一次
             sw2_num1++;
         else
         {
    
    
             sw2_num1=0;
             if(smg_mode==1)
             {
    
    
                 if(hour>0)
                     hour--;
                 else
                     hour=23;

             }
             else if(smg_mode==2)
             {
    
    
                 if(min>0)
                     min--;
                 else
                     min=59;
             }
         }
     }
     else if(sw3==0&&sw1&&sw2&&sw4&&qe_sw==0)//只有SW3按下
     {
    
    
         if(sw3_num1<30)//300ms 减一次
             sw3_num1++;
         else
         {
    
    
             sw3_num1=0;
             if(smg_mode==1)
             {
    
    
                 if(hour<23)
                     hour++;
                 else
                     hour=0;

             }
             else if(smg_mode==2)
             {
    
    
                 if(min<59)
                     min++;
                 else
                     min=0;
             }
         }
     }



}




timer_smg.h

/*

  • timer_smg.h
  • Created on: July 3, 2023
  •  Author: a8456
    

*/

#ifndef TIMER_SMG_H_
#define TIMER_SMG_H_

#include “hal_data.h”
void set_smg_button(void);//Process the digital tube display, modify the current state
#endif /* TIMER_SMG_H_ */

Guess you like

Origin blog.csdn.net/qq_24312945/article/details/132131422