27.8
实验3:输入捕获——脉宽和周期测量
上一个实验使用了GPT的输出功能,本次实验要使用GPT的输入功能,通过GPT的输入捕获进行脉宽和周期测量。其测量的原理如下图所示。

首先启动GPT定时器,在上升沿A处进行捕获,记此时时间为A;紧接着在下降沿B处进行捕获,记此时时间为B;最后再次在上升沿C处进行捕获,记此时时间为C或者A’。设PWM的周期为T,占空比为D,频率为f,则:

27.8.1
硬件设计
以野火启明6M5开发板为例,本实验使用P600和P603这两个引脚,P600用于输出PWM信号,P603用于输入捕获。将P600与P603使用杜邦线连接,引脚在引出排针处,如下图所示。

注
野火启明6M5开发板例程选用的PWM输出引脚为:P600(GTIOC6B);选用的输入捕获引脚为:P603(GTIOC7A)。
野火启明4M2开发板例程选用的PWM输出引脚为:P405(GTIOC1A);选用的输入捕获引脚为:P414(GTIOC0B)。
野火启明2L1开发板例程选用的PWM输出引脚为:P115(GTIOC4A);选用的输入捕获引脚为:P113(GTIOC2A)。
本次实验需要将PWM输出引脚与输入捕获引脚使用杜邦线连接起来。
27.8.2
软件设计
27.8.2.1
新建工程
由于本实验的目标是测量PWM的周期、占空比,因此我们在上一个实验的基础上修改程序。
对于e2studio开发环境:拷贝一份我们之前的e2s工程“27_GPT_PWM_Output”,然后将工程文件夹重命名为“27_GPT_Input_Capture”,最后再将它导入到我们的e2studio工作空间中。
对于Keil开发环境:拷贝一份我们之前的Keil工程“27_GPT_PWM_Output”,然后将工程文件夹重命名为“27_GPT_Input_Capture”,并进入该文件夹里面双击Keil工程文件,打开该工程。
工程新建好之后,在工程根目录的“src/gpt”路径下面,新建源文件和头文件:
bsp_gpt_input_capture.c
bsp_gpt_input_capture.h
工程文件结构如下:
列表9:文件结构
左右滑动查看完整内容
27_GPT_Input_Capture ├─ ...... └─ src ├─ led │ ├─ bsp_led.c │ └─ bsp_led.h ├─ debug_uart │ ├─ bsp_debug_uart.c │ └─ bsp_debug_uart.h ├─ gpt │ ├─ bsp_gpt_pwm_output.c │ ├─ bsp_gpt_pwm_output.h │ ├─ bsp_gpt_input_capture.c //新增文件 │ └─ bsp_gpt_input_capture.h //新增文件 └─ hal_entry.c
27.8.2.2
FSP配置
下面以野火启明6M5开发板为例来讲解相关的FSP配置。
由于在上一个实验中我们已经配置好了P600用于输出PWM信号,因此本实验中只需要添加输入捕获需要使用到IO引脚P603,需要在“Pins”配置页面中配置GPT7所使用的引脚。

在“Stacks”配置页面中加入GPT,按如下图所示的配置进行设置。需要注意的是,因为“Input”里面的各类配置项目若是展开来的话篇幅比较长,因此在图中并未展开出来,我们要注意勾上以下几个选项:
展开Input->Capture ASource并勾上(在GTIOCA的上升沿启用输入捕获A,无论GTIOCB引脚是:
–GTIOCA Rising Edge While GTIOCB Low
–GTIOCA Rising Edge While GTIOCB High
展开Input->Capture BSource并勾上(在GTIOCA的下降沿启用输入捕获B,无论GTIOCB引脚是:
–GTIOCA Falling Edge While GTIOCB Low
–GTIOCA Falling Edge While GTIOCB High

点击可查看大图
GPT的“Input”选项卡的属性描述:
表7:GPT属性描述:“Input”

点击可查看大图
27.8.2.3
GPT初始化
初始化GPT模块用于输入捕获的函数如下。在这个函数中,我们先初始化GPT模块,然后调用R_GPT_Info Get函数获取GPT的配置信息,主要是为了获取计数器的计数周期,即GPT一个周期的计数次数,并保存到全局变量period中。
最后使能输入捕获,并启动GPT定时器。
列表10:GPT初始化
左右滑动查看完整内容
timer_info_t info; //用于获取定时器参数信息
uint32_t period; //输入捕获计数器的计数周期
/* GPT 初始化函数*/
voidGPT_InputCapture_Init(void)
{
/* 初始化GPT 模块*/
R_GPT_Open(&g_timer_gpt7_ctrl, &g_timer_gpt7_cfg);
/* 获取当前参数*/
(void) R_GPT_InfoGet(&g_timer_gpt7_ctrl, &info);
/* 获取计数周期:GPT 的一个周期的计数次数*/
period = info.period_counts;
/* 使能输入捕获*/
R_GPT_Enable(&g_timer_gpt7_ctrl);
/* 启动GPT 定时器*/
R_GPT_Start(&g_timer_gpt7_ctrl);
}
27.8.2.4
GPT中断回调函数
GPT输入捕获中断回调函数如下。
列表11:GPT中断回调函数
滑动查看完整内容
/* 保存所测量的PWM 信号的信息*/
uint32_t pwm_period; //PWM 周期
uint32_t pwm_high_level_time; //PWM 高电平的时间
uint32_t pwm_freq; //PWM 频率
uint32_t pwm_duty; //PWM 占空比
/* GPT 输入捕获中断回调函数*/
voidgpt7_input_capture_callback(timer_callback_args_t * p_args)
{
staticuint32_t a_time; // A 上升沿捕获的时间
staticuint32_t b_time; // B 下降沿捕获的时间
staticuint32_t c_time; // C 上升沿捕获的时间(其实也就是A 可以用A'表示)
staticuint32_t overflow_times; //计数器溢出次数
staticuint8_t one_period_flag=0; //用于表示是否完成对一个完整周期的测量
switch(p_args->event)
{
/* 捕获到上升沿-- 有可能是A 或者C (A') 位置*/
case TIMER_EVENT_CAPTURE_A:
/* A 开始对某个周期进行测量*/
if (0 == one_period_flag)
{
a_time = p_args->capture; //记录捕获的时间A
overflow_times = 0; //初始化计数器溢出次数
one_period_flag ++; //表示即将完成对某个周期的测量
}
/* C (A') 如果测量完了一个周期,则计算PWM 信号周期和高电平的时间*/
elseif (1 == one_period_flag)
{
c_time = p_args->capture + overflow_times * period; //记录捕
获的时间C
//计算PWM 周期
pwm_period = c_time - a_time;
//清零所有标志位
overflow_times = 0;
one_period_flag = 0; //标志位清0, 重新进入下一轮的测量
}
break;
/* 捕获到下降沿-- 是B 位置*/
case TIMER_EVENT_CAPTURE_B:
//如果是在测量周期内检测到下降沿
if (1 == one_period_flag)
{
b_time = p_args->capture + overflow_times * period; //记录捕
获的时间B
pwm_high_level_time = b_time - a_time; //计算高电平时间
}
break;
/* 定时器计数溢出事件*/
case TIMER_EVENT_CYCLE_END:案件 TIMER_EVENT_CYCLE_END:
/* 输入捕获期间计数器溢出,则记录溢出次数+1 */
overflow_times++;
break;
default:
break;
}
}
在GPT中断回调函数中,我们使用switch语句判断触发中断的事件类型。GPT在引脚输入PWM信号的上升沿触发捕获A事件,在PWM信号的下降沿触发捕获B事件,并在计数器溢出时触发定时器计数溢出事件。
警告
建议不要在中断回调函数中打印数据,因为PWM频率一般很高,而printf函数执行所消耗的时间比较长,可能会阻塞中断服务函数的运行。同时也应该时刻注意中断优先级的问题。
27.8.2.5
hal_entry入口函数
列表12:hal_entry入口函数
滑动查看完整内容
/* 用户头文件包含*/
#include"led/bsp_led.h"
#include"debug_uart/bsp_debug_uart.h"
#include"gpt/bsp_gpt_pwm_output.h"
#include"gpt/bsp_gpt_input_capture.h"
// 外部变量声明
externtimer_info_t info; //用于获取定时器参数信息
externuint32_t pwm_period; //PWM 周期
externuint32_t pwm_high_level_time; //PWM 高电平的时间
externuint32_t pwm_freq; //PWM 频率
externuint32_t pwm_duty; //PWM 占空比
voidhal_entry(void)
{
/* TODO: add your own code here */
LED_Init(); // LED 初始化
Debug_UART4_Init(); // SCI4 UART 调试串口初始化
GPT_PWM_Init(); // GPT PWM 输出初始化
GPT_InputCapture_Init(); // GPT 输入捕获初始化
printf("这是一个GPT 的PWM 输出+ 输入捕获功能实验
");
printf("使用杜邦线连接P600 和P603 引脚,然后打开串口助手查看串口的打印信息
,→");
while(1)
{
/* 计算PWM 的频率*/
pwm_freq = info.clock_frequency / pwm_period;
/* 计算PWM 的占空比*/
pwm_duty = pwm_high_level_time * 100 / pwm_period;
// 打印
printf("High=%d, Period=%d, ", pwm_high_level_time, pwm_period);
printf("Friquency = %dHz, Duty_Cycle = %d%%
", pwm_freq, pwm_
,→duty);
pwm_period = pwm_high_level_time = pwm_freq = 0; //打印完后旧数据清零
// LED1 闪烁指示程序正在运行...
LED1_TOGGLE;
// 间隔1s
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
27.8.3
下载验证
以野火启明6M5开发板为例,编译并下载程序后,复位开发板使程序重新运行,然后使用杜邦线连接P600和P603引脚,然后打开串口助手查看串口的打印信息。串口会打印出PWM信号的频率和占空比等信息,实验现象如下图所示。

点击可查看大图
全部0条评论
快来发表一下你的评论吧 !