13 GPT 输入捕获实验

开发板官网(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.c 和 gpt_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” 按钮,让软件自动生成配置代码即可。
- 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)
},
};
- 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 的周期、占空比等数据。
- 打开 GPT 设备
R_GPT_Open(timer_ctrl_t * const p_ctrl, timer_cfg_t const * const p_cfg);
p_ctrl:timer_ctrl_t 结构体指针参数,本质是一个 void 类型的参数,指向 st_gpt_instance_ctrl 类型变量;
p_cfg:timer_cfg_t 结构体指针参数,在程序中会指向在 hal_data.c 中定义的 g_timer_cfg 静态全局变量;
- 开启/停止 GPT 计数
R_GPT_Start(timer_ctrl_t * const p_ctrl);
R_GPT_Stop(timer_ctrl_t * const p_ctrl);
必须要在 GPT 打开状态下使用这两个函数。
- 捕获中断函数
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%。
