瑞萨R5F1026A使用笔记

发布时间 2023-12-23 23:06:28作者: Vic001

R5F1026A一款8位MCU

一、开发环境

使用瑞萨CS+ for CA,CX IDE开发新建工程,project->create new project...,选择MCU型号,设置工程名、工程路径,注意路径不要出现中文

设置code generator

clock generator

port

interrupt

 timer

 watchdog

 点击generator code生成代码

 

二、软件代码

 添加按键处理.c.h代码

key.h

#ifndef _KEY_H_
#define _KEY_H_

#include "r_cg_macrodriver.h"
#include "r_cg_port.h"
#include "r_cg_userdefine.h"

#define COUNT_RESET    0
#define FLAG_RESET       0
#define FLAG_SET       !FLAG_RESET
#define LEVEL_HIGH        1
#define LEVEL_LOW      0

//注:按键按下时引脚电平是高电平还是低电平!!!
//             |
//             |
//            \|/
#define PRESS_LEVEL    LEVEL_HIGH
#define RELEASE_LEVEL  LEVEL_LOW

//按键引脚定义
#define KEY1_PIN    KEY_M1P_IN //KEY1按键引脚
#define KEY2_PIN    KEY_M1N_IN //KEY2按键引脚,按键2实际未使用!!!

//键盘状态
#define KEYSTATE_0    0 //初始状态
#define KEYSTATE_1    1 //消抖状态
#define KEYSTATE_2    2 //释放状态

//按键键值
#define KEY_DEFAULT           (RELEASE_LEVEL << 1 | RELEASE_LEVEL) //按键状态缺省值 0b0000_0000 //0x00
#define KEY1_VALUE              (RELEASE_LEVEL << 1 | PRESS_LEVEL    ) //按键1按下键值
#define KEY2_VALUE              (PRESS_LEVEL     << 1 | RELEASE_LEVEL) //按键2按下键值
#define KEY1_KEY2_LONG_VALUE (PRESS_LEVEL     << 1 | PRESS_LEVEL    ) //按键1、2长按按下键值

//长按、短按标志
#define NULL_PRESS               0 //无按键标志
#define SHORT_PRESS           1 //短按标志
#define LONG_PRESS               2 //长按标志
#define DOUBLE_SHORT_PRESS     3 //双击短按标志

//按键处理返回值
#define KEY1_SHORT                      1 //按键1短按
#define KEY2_SHORT                      2 //按键2短按
#define KEY1_LONG                      3 //按键1长按
#define KEY2_LONG                      4 //按键2长按
#define KEY1_KEY2_LONG               5 //按键1、2同时长按
#define KEY1_DOUBLE_SHORT_PRESS    6 //按键1双击短按
#define KEY2_DOUBLE_SHORT_PRESS    7 //按键2双击短按

//
#define DEBOUNCE_TIME          30      //消抖延时时间,单位ms
#define SHORT_PRESS_TIME       800     //判断短按时间,计时小于该值为短按,单位ms
#define WRONG_PRESS_TIME        2800 //判断短按出错时间,计时大于该值表示出错,单位ms
#define LONG_PRESS_TIME           5000 //判断长按时间值5秒,计时大于该值表示长按,单位ms
#define SHORT_PRESS_INTERVAL   300  //连击间隔时间,单位ms
#define LONG_PRESS_INTERVAL    3000 //两次长按间隔时间,单位ms

//
#define DOUBLE_SHORT_PRESS_COUNT    (COUNT_RESET + 1) // 注:用>判断取+1,用>=判断取+2

//
typedef struct
{
    unsigned char Flag; //标志
    unsigned int Count; //计数
} Variable;

extern Variable KeyPress; //按键按下
extern Variable KeyLongPressInterval; //相邻两次长按间隔
extern Variable KeyShortPressInterval; //相邻两次短按间隔
extern Variable KeyShortPress; //按键短按
extern Variable KeyLongPress; //按键长按

void Key_1ms_scan(void);
void KeyHandle(void);

#endif

key.c

#include "key.h"

//适用独立按键
Variable KeyPress; //按键按下
Variable KeyLongPressInterval; //相邻两次长按间隔
Variable KeyShortPressInterval; //相邻两次短按间隔
Variable KeyShortPress; //按键短按
Variable KeyLongPress; //按键长按

static unsigned char Key_Scan(void);
static void Key1_Short_Press(void);
//static void Key2_Short_Press(void);

//-----------------------------key-----------------------------
// 函数介绍:按键扫描
// 入口参数:/
// 出口参数:键值
// 备    注:/
static unsigned char Key_Scan(void)
{
    static unsigned char CurrentKeyState = KEYSTATE_0; //当前键盘状态
    static unsigned char CurrentKeyValue = KEY_DEFAULT; //当前键值,初始值设为无按键按下时的值,若变量初始值为0与按键按下时值相同,在长按键识别时,会连续返回长按键值,导致长按键处理出错
    unsigned char LongOrShortFlag = NULL_PRESS; //长/短按标志,初始清0
    unsigned char KeyPin; //所有按键引脚键值字符(单字节最多8个按键)

    /* 32bit series */
    //KeyPin = /*(KEY2_PIN << 1) |*/ KEY1_PIN; //各键值组成一个无符号字符,按键按下时IO口的电平,松开时IO口的电平,需根据实际情况而定
    /* 8bit series */
    KeyPin = /*(KEY2_PIN * 2) |*/ KEY1_PIN;

    /* 按键按下时低电平,释放时高电平 */
    //KeyPin &= KEY_DEFAULT; //读取键值
    /* 按键按下时高电平,释放时低电平 */
    KeyPin |= KEY_DEFAULT; //读取键值

    switch(CurrentKeyState) //读取当前按键状态
    {
        case KEYSTATE_0: //初始状态
            if(KeyPin != KEY_DEFAULT) //判断有无按键
            {
                CurrentKeyValue = KeyPin; //读取键值
                CurrentKeyState = KEYSTATE_1; //初始状态转消抖状态
                KeyPress.Count = COUNT_RESET; //按键按下计时清0
                KeyPress.Flag = FLAG_SET; //按键按下标志置1
            }

            break;

        case KEYSTATE_1: //消抖状态
            if(KeyPress.Count > DEBOUNCE_TIME) //按下计时大于消抖延时时间
            {
                if(KeyPin == CurrentKeyValue) //判断是否仍按下此键
                {
                    CurrentKeyState = KEYSTATE_2; //若是,消抖状态转释放状态,判断按键释放
                }
                else
                {
                    CurrentKeyState = KEYSTATE_0; //若否,消抖状态转初始状态,重新开始判断
                }

                KeyPress.Count = COUNT_RESET; //按键按下计时清0
                KeyPress.Flag = FLAG_RESET; //按键按下标志清0
            }

            break;

        case KEYSTATE_2: //释放状态
            KeyPress.Flag = FLAG_SET; //按键按下标志置1

            if(KeyPin == KEY_DEFAULT) //若按键释放
            {
                if(KeyLongPress.Flag) //若是长按键释放
                {
                    KeyLongPress.Flag = FLAG_RESET; //长按键标志清0
                }
                else //若是短按释放
                {
                    //双击
                    /*if(KeyPress.Count < SHORT_PRESS_TIME) //按下计时小于短按设定(最长)时间
                    {
                        KeyShortPress.Count++; //短按计数+1

                        if(KeyShortPressInterval.Flag == FLAG_RESET) //短按间隔计时标志为0时
                        {
                            KeyShortPressInterval.Flag = FLAG_SET; //短按间隔计时标志置1,开始计时
                        }
                        else
                        {
                            ;
                        }

                    }
                    else if(KeyPress.Count > WRONG_PRESS_TIME) //按下计时大于出错判断设定时间
                    {
                        LongOrShortFlag = NULL_PRESS; //判断为出错动作,认为无按键
                    }*/

                    //单击
                    if(KeyPress.Count < SHORT_PRESS_TIME) //按下计时小于短按设定(最长)时间
                    {
                        LongOrShortFlag = SHORT_PRESS; //判断为短按(单击)动作
                    }
                    else if(KeyPress.Count > WRONG_PRESS_TIME) //按下计时大于出错判断设定时间
                    {
                        LongOrShortFlag = NULL_PRESS; //判断为出错动作,认为无按键
                    }
                }

                KeyLongPressInterval.Flag = FLAG_RESET; //长按间隔计时标志清0
                KeyPress.Flag = FLAG_RESET; //按键按下标志清0
                KeyPress.Count = COUNT_RESET; //按键按下计数清0
                CurrentKeyState = KEYSTATE_0; //转初始状态
            }
            else if(KeyPin == CurrentKeyValue) //判断是否仍按下此键
            {
                if(KeyPress.Count >= LONG_PRESS_TIME) //按下计时大于长按设定时间
                {
                    KeyPress.Count = LONG_PRESS_TIME; //
                    LongOrShortFlag = LONG_PRESS; //判断为长按动作
                    KeyLongPress.Flag = FLAG_SET; //按键长按标志置1
                }
            }

            break;

        default:

            break;
    }
    //双击
    /*if(KeyShortPressInterval.Count > SHORT_PRESS_INTERVAL) //短按间隔计时大于设定时间
    {
        if(KeyShortPress.Count > DOUBLE_SHORT_PRESS_COUNT) //短按计数大于设定次数(双击大于1次)
        {
            LongOrShortFlag = DOUBLE_SHORT_PRESS; //判断为双击短按动作
        }
        else //短按计数小于设定次数
        {
            LongOrShortFlag = SHORT_PRESS; //判断为短按(单击)动作
        }

        KeyShortPressInterval.Flag = FLAG_RESET; //短按间隔计时标志清0
        KeyShortPressInterval.Count = COUNT_RESET; //短按间隔计数清0
        KeyShortPress.Count = COUNT_RESET; //短按计数清0
    }*/

    if(LongOrShortFlag != NULL_PRESS) //有键按下,长/短一起处理
    {
        switch(CurrentKeyValue) //识别键值 //(KEY2<<1 | KEY1)
        {
            case KEY1_VALUE:
                if(LongOrShortFlag == DOUBLE_SHORT_PRESS) //双击短按动作
                {
                    return KEY1_DOUBLE_SHORT_PRESS; // 双击返回值
                }
                else if(LongOrShortFlag == SHORT_PRESS) //短按动作
                {
                    KeyLongPressInterval.Flag = FLAG_RESET; //长按间隔计时标志清0
                    return KEY1_SHORT; //短按返回值
                }
                else if((LongOrShortFlag == LONG_PRESS) && (KeyLongPressInterval.Flag == FLAG_RESET)) //连续长按按键
                {
                    KeyLongPressInterval.Flag = FLAG_SET; //长按间隔计时标志置1
                    KeyPress.Count = COUNT_RESET; //按键按下计时清0
//                    if(KeyLongPressInterval.Count > LONG_PRESS_INTERVAL)
//                    {
//                        KeyLongPressInterval.Count = COUNT_RESET;
//                        KeyLongPressInterval.Flag = FLAG_RESET;
                    return KEY1_LONG; //长按返回值
//                    }
                }

                if(KeyLongPressInterval.Count > LONG_PRESS_INTERVAL) //长按间隔计时大于设定时间
                {
                    KeyLongPressInterval.Flag = FLAG_RESET; //长按间隔计时标志清0
                    KeyLongPressInterval.Count = COUNT_RESET; //长按间隔计时清0
                }

                break;

            case KEY2_VALUE:
                if(LongOrShortFlag == DOUBLE_SHORT_PRESS) //双击短按动作
                {
                    return KEY2_DOUBLE_SHORT_PRESS; //双击返回值
                }
                else if(LongOrShortFlag == SHORT_PRESS) //短按动作
                {
                    KeyLongPressInterval.Flag = FLAG_RESET;
                    return KEY2_SHORT; //短按返回值
                }
                else if((LongOrShortFlag == LONG_PRESS) && (KeyLongPressInterval.Flag == FLAG_RESET)) //连续长按按键
                {
                    KeyLongPressInterval.Flag = FLAG_SET;
                    KeyPress.Count = COUNT_RESET;
//                    if(KeyLongPressInterval.Count > LONG_PRESS_INTERVAL)
//                    {
//                        KeyLongPressInterval.Count = COUNT_RESET;
//                        KeyLongPressInterval.Flag = FLAG_RESET;
                    return KEY2_LONG; //长按返回值
//                    }
                }

                if(KeyLongPressInterval.Count > LONG_PRESS_INTERVAL) //长按间隔计时大于设定时间
                {
                    KeyLongPressInterval.Flag = FLAG_RESET; //长按间隔计时标志清0
                    KeyLongPressInterval.Count = COUNT_RESET; //长按间隔计时清0
                }

                break;

            case KEY1_KEY2_LONG_VALUE:
                if((LongOrShortFlag == LONG_PRESS) && (KeyLongPressInterval.Flag == FLAG_RESET)) //连续长按按键
                {
                    KeyLongPressInterval.Flag = FLAG_SET;
                    KeyPress.Count = COUNT_RESET;
//                    if(KeyLongPressInterval.Count > LONG_PRESS_INTERVAL)
//                    {
//                        KeyLongPressInterval.Count = COUNT_RESET;
//                        KeyLongPressInterval.Flag = FLAG_RESET;
                    return KEY1_KEY2_LONG; //长按返回值
//                    }
                }

                if(KeyLongPressInterval.Count > LONG_PRESS_INTERVAL) //长按间隔计时大于设定时间
                {
                    KeyLongPressInterval.Flag = FLAG_RESET; //长按间隔计时标志清0
                    KeyLongPressInterval.Count = COUNT_RESET; //长按间隔计时清0
                }

                break;

            /*
            case :
                break;

            case :
                break;

            ...扩展按键处理
            */

            default:
                break;
        }
    }

    return 0; //无键按下,返回0
}

/* put the function in 1ms interrupt */
void Key_1ms_scan(void)
{
//    Key_Value = Key_Scan();
    // 按键按下计时
    if(KeyPress.Flag)
    {
        if(KeyPress.Count < 65535)
        {
            KeyPress.Count++;
        }
    }
    else
    {
        KeyPress.Count = COUNT_RESET;
    }

    // 相邻两次长按间隔计时
    if(KeyLongPressInterval.Flag)
    {
        if(KeyLongPressInterval.Count < 65535)
        {
            KeyLongPressInterval.Count++;
        }
    }
    else
    {
        KeyLongPressInterval.Count = COUNT_RESET;
    }

    // 相邻两次短按间隔计时
    if(KeyShortPressInterval.Flag)
    {
        if(KeyShortPressInterval.Count < 65535)
        {
            KeyShortPressInterval.Count++;
        }
    }
    else
    {
        KeyShortPressInterval.Count = COUNT_RESET;
    }

}

static void Key1_Short_Press(void)
{
    KeyShortPressProc();
}

static void Key1_Double_Short_Press(void)
{
    KeyDoubleShortPressProc();
}

/*static void Key2_Short_Press(void)
{

}*/

/*static void Key1_Key2_Long_Press(void)
{
    ;
}*/

/* put the function in main.c */
void KeyHandle(void)
{
    switch(Key_Scan()) //Key_Value
    {
        case KEY1_SHORT:
            Key1_Short_Press();
            break;

        /*case KEY2_SHORT:
            Key2_Short_Press();
            break;*/
        
        //双击
        //case KEY1_DOUBLE_SHORT_PRESS:
        //    Key1_Double_Short_Press();
        //    break;

        /*
        case KEY1_KEY2_LONG:
            Key1_Key2_Long_Press();
            break;

        case :
        break;

        case :
        break;

        ...add key hanlde
        */
        default:
            break;
    }
}

 需注意的是,工程中使用P122引脚作为INTP2功能,而芯片默认使用P13引脚,因此需要设置IO重定向寄存器

 

void R_Systeminit(void)
{
    PIOR = 0x01U;//PIOR = 0x00U; // 允许INTP2引脚重定向
    R_CGC_Get_ResetSource();
    R_CGC_Create();
    R_PORT_Create();
    R_TAU0_Create();
    R_WDT_Create();
    R_INTC_Create();
    IAWCTL = 0x00U;
}
void R_INTC_Create(void)
{
    PMK0 = 1U;    /* disable INTP0 operation */
    PIF0 = 0U;    /* clear INTP0 interrupt flag */
    PMK1 = 1U;    /* disable INTP1 operation */
    PIF1 = 0U;    /* clear INTP1 interrupt flag */
    PMK2 = 1U;    /* disable INTP2 operation */
    PIF2 = 0U;    /* clear INTP2 interrupt flag */
    PMK3 = 1U;    /* disable INTP3 operation */
    PIF3 = 0U;    /* clear INTP3 interrupt flag */
    /* Set INTP2 low priority */
    PPR12 = 1U;
    PPR02 = 1U;
    EGP0 = _04_INTP2_EDGE_RISING_SEL;
    /* Set INTP2 pin */
    //PMC1 &= 0xF7U; //INTP2引脚重定向后删除
    //PM1 |= 0x08U;
}

 

三、工程文件

 https://files.cnblogs.com/files/Jayisingraduateschool/20231219%E5%8D%95%E5%87%BB.zip?t=1703343815&download=true