瑞萨单片机论坛
直播中

HonestQiao

9年用户 577经验值
擅长:嵌入式技术
私信 关注

【瑞萨RA4系列开发板体验】GPT定时器的基础使用

在RA4M2的系统重,提供了三种定时器,从手册之中可以了解:

image.png

三种定时器分别是:

  • 普通PWM 32位定时器:GPT32
  • 普通PWM 16位定时器:GPT16
  • 低功耗用用异步定时器:AGT

其中普通GPT比较常用,主要是用于生成PWM波形,从而控制例如无刷电机等外部设备。当然,也可以不进行输出,直接当做定时器使用,在定时回调中,进行我们需要的处理。

从手册上可以了解这些定时器的具体功能规范:

image.png

下面,就以点灯的实例,来展示GPT的基础使用。

一、FPS设置

要启用GPT,首先就需要在FPS种进行设置。

关于LED部分的设置,就不重新说了,这个是基础。

GPT设置步骤如下:

iShot_2022-12-14_23.40.45.png

上述步骤,就是先添加一个GPT的Stack,然后设置其初始化参数和回调参数:

初始化参数:

  • Name: 名称

  • Channel: 通道

  • Mode: 模式,选择周期性

  • Period: 周期位1

  • Period Unit: 周期的单位位秒

    也就是定时器1秒触发一次

周期单位可以详细设置,具体如下:

image.png

在bsp_delay.h中,也有类似的定义:

typedef enum
{
    BSP_DELAY_UNITS_SECONDS      = 1000000, ///< Requested delay amount is in seconds
    BSP_DELAY_UNITS_MILLISECONDS = 1000,    ///< Requested delay amount is in milliseconds
    BSP_DELAY_UNITS_MICROSECONDS = 1        ///< Requested delay amount is in microseconds
} bsp_delay_units_t;

回调参数:

  • Callback:回调函数名称,定时器触发时,会调用该函数,在其中进行具体的操作处理

  • Overflow/Crest Interrupts Priority:定时器的中断登记,用10就可以

    其他的先不用管,默认即可。
    设置好,生成代码以后,就转入代码部分的操作了。
    在代码部分,我们需要添加两个调用,一个是GPT初始化,一个是回调函数,具体如下:

static bool status = false;

/* GPT 初始化函数 */
void GPT_Timing_Init(void)
{
    /* 初始化 GPT0 模块 */
    R_GPT_Open(&g_timer_gpt0_ctrl, &g_timer_gpt0_cfg);

    /* 启动 GPT0 定时器 */
    R_GPT_Start(&g_timer_gpt0_ctrl);
}

/* GPT 中断回调函数 */
void gpt0_timing_callback(timer_callback_args_t * p_args)
{
    /* 定时器溢出事件 */
    if (TIMER_EVENT_CYCLE_END == p_args->event)
    {
        /* 翻转 LED1 */
        //每秒翻转一次
        status = ! status;
        if(status) {
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_HIGH); // 点亮LED
        } else {
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_LOW); // 关闭LED
        }
    }
}

在上述代码终,GPT_Timing_Init()负责初始化,因为我们只用了gpt0,所以只需要初始化gpt0即可。

gpt0对应的控制变量,以及回调函数的预定义,在hal_data.h终有定义,具体如下:

extern gpt_instance_ctrl_t g_timer_gpt0_ctrl;
extern const timer_cfg_t g_timer_gpt0_cfg;

#ifndef gpt0_timing_callback
void gpt0_timing_callback(timer_callback_args_t * p_args);
#endif

在hal_data.c中,有关于g_timer_gpt0_ctrl和g_timer_gpt0_cfg的具体定义:

const timer_cfg_t g_timer_gpt0_cfg =
{
    .mode                = TIMER_MODE_PERIODIC,
    /* Actual period: 1 seconds. Actual duty: 50%. */
    .period_counts = (uint32_t) 0x5f5e100,
    .duty_cycle_counts = 0x2faf080,
    .source_div = (timer_source_div_t)0,
    .channel             = 0,
    .p_callback          = gpt0_timing_callback,
    /** If NULL then do not add & */
#if defined(NULL)
    .p_context           = NULL,
#else
    .p_context           = &NULL,
#endif
    .p_extend            = &g_timer_gpt0_extend,
    .cycle_end_ipl       = (10),
#if defined(VECTOR_NUMBER_GPT0_COUNTER_OVERFLOW)
    .cycle_end_irq       = VECTOR_NUMBER_GPT0_COUNTER_OVERFLOW,
#else
    .cycle_end_irq       = FSP_INVALID_VECTOR,
#endif
};
/* Instance structure to use this module. */
const timer_instance_t g_timer_gpt0 =
{
    .p_ctrl        = &g_timer_gpt0_ctrl,
    .p_cfg         = &g_timer_gpt0_cfg,
    .p_api         = &g_timer_on_gpt
};

在前面代码终,还添加了一个status变量,用于表示LED的状态,true则电量LED1,false则熄灭LED1。其中,BSP_IO_PORT_04_PIN_15对应LED1的引脚。

然后,在hal_entry()终调用初始化,就能够启动定时器了,具体如下:

void hal_entry(void)
{
    /* TODO: add your own code here */
    fsp_err_t err;                                       //
    err = R_IOPORT_Open(&g_ioport_ctrl, &g_bsp_pin_cfg); // 初始化引脚
    assert(FSP_SUCCESS == err);                          // 判断是否初始化成功

    GPT_Timing_Init();  // GPT 初始化
    while(1)
    {        R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
    }


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

使用GPT_Timing_Init()进行初始化后,定时器就会启动,并按照预定的周期,调用gpt0_timing_callback()。

代码终的R_BSP_SoftwareDelay()表示演示,以免while(1)疯狂运行。

编写好代码之后,编译下载到开发板上,就可以看到LED1,每秒闪烁一次了。

在前面的gpt cfg定义中,有两个很重要,但设置为1秒的时候,对应的值为:

/* Actual period: 1 seconds. Actual duty: 50%. */
.period_counts = (uint32_t) 0x5f5e100,
.duty_cycle_counts = 0x2faf080,

当设置为100毫秒的时候,对应的值为:

/* Actual period: 0.1 seconds. Actual duty: 50%. */ 
.period_counts = (uint32_t) 0x989680, 
.duty_cycle_counts = 0x4c4b40,

在上述配置中,period_counts表示定时器一个周期的计数次数,达到计数次数,则调用一次回调函数。

duty_cycle_counts表示占空比的技术次数,上述两个值,都为period_counts的一半,所以如果是PWM输出,则其对应的占空比为50%。

如果使用0.1seconds的配置,然后编译烧录,就可以看到LED快速闪烁了。

如果将1秒的period_counts除以0.1秒的period_counts,可以得到倍差值:0x5f5e100/0x989680 = 0xa,也就是10倍。

明白了这一点,那我们想要及时修改定时器的定时周期测试的时候,就不用再去FSP中操作了。等调整了定时器,达到实际需要了,再到FSP中进行一次设置,使得配置能够写入到xml配置文件中。

演示效果.gif

演示效果

更多回帖

发帖
×
20
完善资料,
赚取积分