跳到主要内容

13 GPT 输入捕获实验

在这里插入图片描述

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

本系列教程目录:


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 所使用的引脚。

插图01

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

插图02

属性配置参数如下:

插图03

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

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

插图04

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

插图05

“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 SelectGTIOCA 输入噪声滤波器的采样时钟选择。
Noise Filter B Sampling Clock SelectGTIOCB 输入噪声滤波器的采样时钟选择。

“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%。

插图06