在这里插入图片描述

开发板官网(https://www.edevkit.com/)

本系列教程目录:
- 瑞萨单片机开发教程[一] e2-studio + DAP LINK开发环境搭建
- 瑞萨单片机开发教程[二] Keil/RASC开发环境搭建
- 瑞萨单片机开发教程[三] 新建RASC工程
- 瑞萨单片机开发教程[四] GPIO输出——led实验
- 瑞萨单片机开发教程[五] GPIO输入——按键key实验
- 瑞萨单片机开发教程[六] ICU外部中断实验
- 瑞萨单片机开发教程[七] SCI UART串口通信实验
- 瑞萨单片机开发教程[八] DMAC 串口数据传输实验
- 瑞萨单片机开发教程[九] ADC 电压采集实验


GPT 输入捕获实验

本章目标:

  • 了解 RA6M5 处理器的 GPT 外设;
  • 学会使用 RASC 配置 GPT 实现信号的输入捕获;

硬件设计

(略,参见配套硬件原理图)

软件设计

新建工程

本实验的目标是测量 PWM 的周期、占空比,复制一份“12 GPT_PWM_Output”修改文件夹名“13 GPT_Input_Capture”,双击打开 EBF_RA6M5.uvprojx 工程,通过 Keil 的新建文件新建 gpt_input.cgpt_input.h,保存到目录下的 \src 文件夹下。

FSP 配置

Keil 界面选择“Tools”→“RA Smart Configurator”打开 RASC 界面。

在 PWM 实验配置好了 P600 用于输出 PWM 信号,本实验中只需要添加输入捕获需要使用到的 IO 引脚 P304,需要在“Pins”配置页面中配置 GPT7 所使用的引脚。

下一步还是添加一个 GPT 模块,把属性参数配置成输入捕获。

属性配置参数如下:

①处“Input”需要展开配置“Capture A Source”和“Capture B Source”的捕获电平参数。

在 GTIOCA 的上升沿启用输入捕获 A,无论 GTIOCB 引脚是高电平还是低电平。

在 GTIOCA 的下降沿启用输入捕获 B,无论 GTIOCB 引脚是高电平还是低电平。

“Input”属性:

Count Up Source 选择计数器向上计数的外部源。
如果某个外部向上计数源被选中,该定时器将在该源的驱动下进行计数,而不是计数 PCLKD 周期。
Count Down Source 选择计数器向下计数的外部源。
如果某个外部向下计数源被选中,该定时器将在该源的驱动下进行计数,而不是计数 PCLKD 周期。
Start Source 选择外部源来启动定时器。
Stop Source 选择外部源来停止定时器。
Clear Source 选择外部源来清除定时器。
Capture A Source 选择外部源来触发一个捕获 A 事件。
Capture B Source 选择外部源来触发一个捕获 B 事件。
Noise Filter A Sampling Clock Select GTIOCA 输入噪声滤波器的采样时钟选择。
Noise Filter B Sampling Clock Select GTIOCB 输入噪声滤波器的采样时钟选择。

“Interrupts”配置属性:

Callback 中断回调函数名。
Overflow/Crest Interrupts Priority 选择上溢中断的优先级。如果选择 Disabled 则禁止该中断。
该中断亦是三角波的波峰中断。
Capture A Interrupts Priority 选择捕获 A 中断的优先级。如果选择 Disabled 则禁止该中断。
Capture B Interrupts Priority 选择捕获 B 中断的优先级。如果选择 Disabled 则禁止该中断。
Underflow/Trough Interrupts Priority 选择下溢中断的优先级。如果选择 Disabled 则禁止该中断。
该中断亦是三角波的波谷中断。

配置完成之后可以按下快捷键“Ctrl + S”保存,最后点击 “Generate Project Content” 按钮,让软件自动生成配置代码即可。

  1. GPT 的引脚信息

使用 GPT 配置输入捕获引脚 P304。

const ioport_pin_cfg_t g_bsp_pin_cfg_data[] = {
    ......
    {.pin = BSP_IO_PORT_03_PIN_04,
    .pin_cfg = ((uint32_t) IOPORT_CFG_PERIPHERAL_PIN 
              | (uint32_t) IOPORT_PERIPHERAL_GPT1)
    },
};
  1. GPT配置信息

GPT 模块的配置信息在 hal_data.c 中以 timer_cfg_t 类型的结构体变量表示。

const timer_cfg_t g_timer0_gpt7_cfg =
{
    .mode                = TIMER_MODE_PERIODIC,
    /* Actual period: 0.00065536 seconds. Actual duty: 50%. */
        .period_counts = (uint32_t) 0x10000, 
        .duty_cycle_counts = 0x8000, 
        .source_div = (timer_source_div_t)0,
    .channel             = 7,
    .p_callback          = gpt7_input_capture_callback,
    /** If NULL then do not add & */
#if defined(NULL)
    .p_context           = NULL,
#else
    .p_context           = &NULL,
#endif
    .p_extend            = &g_timer0_gpt7_extend,
    .cycle_end_ipl       = (9),
#if defined(VECTOR_NUMBER_GPT7_COUNTER_OVERFLOW)
    .cycle_end_irq       = VECTOR_NUMBER_GPT7_COUNTER_OVERFLOW,
#else
    .cycle_end_irq       = FSP_INVALID_VECTOR,
#endif
};

mode 表示 GPT 的类型,此处是周期;

第 05~06 行:表示周期参数;

channel 表示使用的 GPT 的通道;

使用 GPT 的 open 函数打开 GPT 设备时,就会使用这些配置信息初始化 GPT。

程序设计

实现 GPT7 的输入捕获测量 PWM 周期和占空比,开启 P600 通道的 PWM,设置输出的占空比,接入到 P304 的捕获引脚,在捕获中断中测量计算输入的 PWM 的周期、占空比等数据。

  1. 打开 GPT 设备
R_GPT_Open(timer_ctrl_t * const p_ctrl, timer_cfg_t const * const p_cfg);

p_ctrltimer_ctrl_t 结构体指针参数,本质是一个 void 类型的参数,指向 st_gpt_instance_ctrl 类型变量;

p_cfgtimer_cfg_t 结构体指针参数,在程序中会指向在 hal_data.c 中定义的 g_timer_cfg 静态全局变量;

  1. 开启/停止 GPT 计数
R_GPT_Start(timer_ctrl_t * const p_ctrl);
R_GPT_Stop(timer_ctrl_t * const p_ctrl);

必须要在 GPT 打开状态下使用这两个函数。

  1. 捕获中断函数
void gpt7_input_capture_callback(timer_callback_args_t * p_args)
{
    switch(p_args->event)
    {
       /* 捕获到上升沿 -- 有可能是 A 或者 C (A') 位置 */
       case TIMER_EVENT_CAPTURE_A:

       break;
       /* 捕获到下降沿 -- 是 B 位置 */
       case TIMER_EVENT_CAPTURE_B:

       break;
       /* 定时器计数溢出事件 */
       case TIMER_EVENT_CYCLE_END:

       break;
    }
}

在 GPT 中断回调函数中,使用 switch 语句判断触发中断的事件类型。GPT 在引脚输入 PWM 信号的上升沿触发捕获 A 事件,在 PWM 信号的下降沿触发捕获 B 事件,并在计数器溢出时触发定时器计数溢出事件。

程序编写

gpt_input.h 头文件里定义初始化函数、打印测试数据函数。

#ifndef _GPT_INPUT_CAPTURE_H
#define _GPT_INPUT_CAPTURE_H
#include "hal_data.h"

void gpt7_InputCapture_Init(void);

void printf_PWM_Info(void);

#endif

gpt_input.c 里实现初始化函数、中断函数和打印测试数据函数。

初始化函数里打开 GPT 设备并启动定时器。

中断函数通过检测上升沿和下降沿标志,检测到 PWM 一个周期后,计算 PWM 的周期和占空比。

#include "gpt_input.h"

timer_info_t gptInfo; 
uint32_t periodCnt;  //定时器一个周期计数值 

void gpt7_InputCapture_Init(void)
{
    //初始化 GPT7 输入捕获模块
    R_GPT_Open(&g_timer0_gpt7_ctrl, &g_timer0_gpt7_cfg);

    //获取GPT7周期的计数次数
    R_GPT_InfoGet(&g_timer0_gpt7_ctrl, &gptInfo);
    periodCnt = gptInfo.period_counts;

    //使能输入捕获
      R_GPT_Enable(&g_timer0_gpt7_ctrl);

    //启动 GPT 定时器
    R_GPT_Start(&g_timer0_gpt7_ctrl);
}

//测量PWM参数
uint32_t pwm_period;      //PWM周期
uint32_t pwm_freq;        //PWM频率
uint32_t pwm_high_time;   //PWM高电平的时间
uint32_t pwm_duty;        //PWM占空比

//过程记录数据
uint32_t a_time;  // A 上升沿捕获的时间
uint32_t b_time;  // B 下降沿捕获的时间
uint32_t a1_time; // 下次A上升沿捕获的时间
uint32_t overflowCnts=0;     //计数器溢出次数
uint8_t  one_period_flag=0;  //是否完成一个完整周期的测量

//GPT7 输入捕获中断函数 
void gpt7_input_capture_callback(timer_callback_args_t * p_args)
{

    switch(p_args->event)
    {
        // 捕获到上升沿, A 或者 A1 位置
        case TIMER_EVENT_CAPTURE_A:
            //A 开始对某个周期进行测量
            if (0 == one_period_flag)
            {
                a_time = p_args->capture; //记录捕获的时间 A
                overflowCnts = 0;         //初始化计数器溢出次数
                one_period_flag = 1;      //表示即将完成对某个周期的测量
            }
            //A1 再次检测到上升沿, A--B--A1表示测到一个周期结束
                        else if (1 == one_period_flag)
            {
                            //记录捕获的时间 A1
              a1_time = p_args->capture + overflowCnts * periodCnt; 

              //计算 PWM 周期
              pwm_period = a1_time - a_time;

              //清零所有标志位
              overflowCnts = 0;
                            //标志位清0,重新进入下一轮的测量
              one_period_flag = 0;         
            }
         break;

        //捕获到下降沿, B 位置, A到B是高电平时间
        case TIMER_EVENT_CAPTURE_B:
            //在检测到A后才检测B
            if (1 == one_period_flag)
            {
                            //记录B捕获的时间 
              b_time = p_args->capture + overflowCnts * periodCnt; 

                            //计算高电平时间
              pwm_high_time = b_time - a_time;  
            }
            break;

        //定时器计数溢出, 表示过了一个周期的时间
        case TIMER_EVENT_CYCLE_END:
            // 输入捕获期间计数器溢出,则记录溢出次数+1
            overflowCnts++;
            break;

        default:
            break;
    }
}

//打印测试数据
void printf_PWM_Info(void)
{
    //计算PWM频率
    pwm_freq = gptInfo.clock_frequency / pwm_period;

    //计算PWM占空比
    pwm_duty = pwm_high_time * 100 / pwm_period;

    //打印数据
    printf("\r\n High=%d, Period=%d \r\n", pwm_high_time, pwm_period);
  printf("Frequency = %dHz, Duty_Cycle = %d%%\r\n", pwm_freq, pwm_duty);

  pwm_period = 0;
    pwm_high_time = 0;
    pwm_freq = 0; 
}

hal_entry.c 文件中添加头文件 gpt_input.h,在 hal_entry 入口函数初始化 GPT。在循环中打印测试数据。

void hal_entry(void)
{
    /* TODO: add your own code here */

    led_Init(); // led 初始化
  uart0_Init();
    gpt_PWM_Init();
    gpt7_InputCapture_Init();

    printf("start GPT Input Capture test\r\n");

    while(1)
    {
        LED1_TOGGLE();
        R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS); //延时1秒

        //打印数据
        printf_PWM_Info();
    }


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

下载验证

首先用杜邦线连接 PWM 输出引脚 P600 和捕获引脚 P304。把 PWM 占空比设置为 75%。

连接下载器,将程序编译并下载到开发板之后,按下复位按键来复位开发板,程序启动初始化完成后,观察实验结果。

观察打印数据,检测到 PWM 频率为 20 kHz,占空比 75%。

更多推荐