更改网站的布局,企业网站该怎么做,南京江宁网站制作,wordpress如何实现收费会员制e2studio开发RA2E1.9--定时器GPT配置输入捕获 概述视频教学样品申请硬件准备参考程序源码下载选择计时器时钟源UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user_uart_callback ()printf输出重定向到串口定时器输入捕获配… e2studio开发RA2E1.9--定时器GPT配置输入捕获 概述视频教学样品申请硬件准备参考程序源码下载选择计时器时钟源UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user_uart_callback ()printf输出重定向到串口定时器输入捕获配置占空比与频率计算回调函数gpt5_callback主程序演示 概述
本文将探讨如何在 Renesas RA 系列微控制器上使用 GPT通用定时器模块来配置输入捕获功能。输入捕获是定时器的一项重要功能它允许我们捕获外部信号如脉冲或波形的时间戳广泛应用于频率计数、脉冲宽度测量以及其他需要精确时间记录的应用。
最近在瑞萨RA的课程需要样片的可以加qun申请925643491。 视频教学
https://www.bilibili.com/video/BV1QrP1ejEAZ/ e2studio开发RA2E1(9)----定时器GPT配置输入捕获 样品申请
https://www.wjx.top/vm/rCrkUrz.aspx
硬件准备
首先需要准备一个开发板这里我准备的是自己绘制的开发板需要的可以进行申请。 主控为R7FA2E1A72DFL#AA0 参考程序
https://github.com/CoreMaker-lab/RA2E1
https://gitee.com/CoreMaker/RA2E1
源码下载
选择计时器
RA MCU 有两个定时器外设通用 PWM 定时器 (GPT) 和异步通用定时器 (AGT)。 时钟源
GPT 使用 PCLKD外设时钟D 作为主时钟源。该时钟可以通过 可配置的分频器 进行调整最大分频因子为 1024。 选择 XTAL 12MHz 作为时钟源Clock Src: XTAL。PCLKD 时钟的分频器设置为 Div /1意味着 PCLKD 直接运行在 12MHz。
UART配置 点击Stacks-New Stack-Connectivity - UART(r_sci_uart)。 UART属性配置 设置e2studio堆栈
printf函数通常需要设置堆栈大小。这是因为printf函数在运行时需要使用栈空间来存储临时变量和函数调用信息。如果堆栈大小不足可能会导致程序崩溃或不可预期的行为。 printf函数使用了可变参数列表它会在调用时使用栈来存储参数在函数调用结束时再清除参数这需要足够的栈空间。另外printf也会使用一些临时变量如果栈空间不足会导致程序崩溃。 因此为了避免这类问题应该根据程序的需求来合理设置堆栈大小。 e2studio的重定向printf设置 在嵌入式系统的开发中尤其是在使用GNU编译器集合GCC时–specs 参数用于指定链接时使用的系统规格specs文件。这些规格文件控制了编译器和链接器的行为尤其是关于系统库和启动代码的链接。–specsrdimon.specs 和 --specsnosys.specs 是两种常见的规格文件它们用于不同的场景。 –specsrdimon.specs 用途: 这个选项用于链接“Redlib”库这是为裸机bare-metal和半主机semihosting环境设计的C库的一个变体。半主机环境是一种特殊的运行模式允许嵌入式程序通过宿主机如开发PC的调试器进行输入输出操作。 应用场景: 当你需要在没有完整操作系统的环境中运行程序但同时需要使用调试器来处理输入输出例如打印到宿主机的终端这个选项非常有用。 特点: 它提供了一些基本的系统调用通过调试接口与宿主机通信。 –specsnosys.specs 用途: 这个选项链接了一个非常基本的系统库这个库不提供任何系统服务的实现。 应用场景: 适用于完全的裸机程序其中程序不执行任何操作系统调用比如不进行文件操作或者系统级输入输出。 特点: 这是一个更“裸”的环境没有任何操作系统支持。使用这个规格文件程序不期望有操作系统层面的任何支持。 如果你的程序需要与宿主机进行交互如在开发期间的调试并且通过调试器进行基本的输入输出操作则使用 --specsrdimon.specs。 如果你的程序是完全独立的不需要任何形式的操作系统服务包括不进行任何系统级的输入输出则使用 --specsnosys.specs。 R_SCI_UART_Open()函数原型 故可以用 R_SCI_UART_Open()函数进行配置开启和初始化UART。 /* Open the transfer instance with initial configuration. */err R_SCI_UART_Open(g_uart9_ctrl, g_uart9_cfg);assert(FSP_SUCCESS err);回调函数user_uart_callback ()
当数据发送的时候可以查看UART_EVENT_TX_COMPLETE来判断是否发送完毕。 可以检查检查 “p_args” 结构体中的 “event” 字段的值是否等于 “UART_EVENT_TX_COMPLETE”。如果条件为真那么 if 语句后面的代码块将会执行。
fsp_err_t err FSP_SUCCESS;
volatile bool uart_send_complete_flag false;
void user_uart_callback (uart_callback_args_t * p_args)
{if(p_args-event UART_EVENT_TX_COMPLETE){uart_send_complete_flag true;}
}
printf输出重定向到串口
打印最常用的方法是printf所以要解决的问题是将printf的输出重定向到串口然后通过串口将数据发送出去。 注意一定要加上头文件#include stdio.h
#ifdef __GNUC__ //串口重定向#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endifPUTCHAR_PROTOTYPE
{err R_SCI_UART_Write(g_uart9_ctrl, (uint8_t *)ch, 1);if(FSP_SUCCESS ! err) __BKPT();while(uart_send_complete_flag false){}uart_send_complete_flag false;return ch;
}int _write(int fd,char *pBuffer,int size)
{for(int i0;isize;i){__io_putchar(*pBuffer);}return size;
}定时器输入捕获配置
操作 “New Stack Timers Timer, General PWM (r_gpt)” 在项目中添加GPT定时器。 这里设置P102进行捕获PWM。 ● Pin Output Support设为 Enabled允许 PWM 信号输出到外部引脚。 ● Name设置为 g_timer5这是模块的唯一标识符用于代码中引用此定时器实例。 ● Channel设定为 5表示该定时器使用通道 5 进行计数和控制。 ● Mode设为 Periodic表示该定时器工作在周期模式将在设定周期内重复运行。 ● Period周期值设置为 0x10000表示定时器的周期为 65536 个时钟周期。根据时钟源频率的不同实际的周期时间可以转换为相应的实际时间。 ● Period Unit单位选择为 Raw Counts表示周期单位为原始计数即计数器溢出的周期。 ● Capture B Source设为 GPT5 CAPTURE COMPARE B表示捕获源为 GPT5 定时器的比较匹配B事件用于捕获输入信号的时间戳。 ● GTIOCB Rising Edge While GTIOCA Low表示当 GTIOCA 为低电平时捕获 GTIOCB 引脚的上升沿事件。 ● GTIOCB Rising Edge While GTIOCA High表示当 GTIOCA 为高电平时捕获 GTIOCB 引脚的上升沿事件。 ● GTIOCB Falling Edge While GTIOCA Low表示当 GTIOCA 为低电平时捕获 GTIOCB 引脚的下降沿事件。 ● GTIOCB Falling Edge While GTIOCA High表示当 GTIOCA 为高电平时捕获 GTIOCB 引脚的下降沿事件。 ● Callback设置为 gpt5_callback指定了当定时器触发中断时调用的回调函数。在此情况下回调函数 gpt5_callback 将在捕获事件发生时执行。 ● Capture/Compare match B Interrupt Priority设置为 Priority 2表示启用比较匹配 B 中断且其优先级为 2。 ● GTIOC5B指定 GTIOC5B 引脚为另一个定时器输入/输出引脚连接到外部引脚 P102。 占空比与频率计算
在波形中 ● up1_capture_time 是第一次上升沿的捕获时间。 ● down_capture_time 是下降沿的捕获时间。 ● up2_capture_time 是第二次上升沿的捕获时间。 脉冲周期pulse_period完整周期为上升沿up1_capture_time到第二次上升沿up2_capture_time之间的时间差也就是脉冲的完整周期。 ● 频率计算我在频率计算中使用了 pulse_period确保了计算是在第一次和第二次上升沿之间。 ● 占空比计算计算占空比时使用了从 down_capture_time 到第二次上升沿 up2_capture_time 之间的时间差来计算脉冲宽度。 回调函数gpt5_callback
上升沿捕获 ○ 在上升沿捕获时更新第一次和第二次上升沿的捕获时间。 ○ 计算 脉冲周期即第二次上升沿与第一次上升沿之间的时间差。 ○ 计算 频率通过时钟频率除以脉冲周期。 ○ 计算 占空比通过计算从上升沿到下降沿的脉冲宽度然后用脉冲宽度除以脉冲周期来计算占空比。下降沿捕获 ○ 在下降沿捕获时更新下降沿的捕获时间。
需要注意的是代码中计算占空比时用 (100.0f - (pulse_width*100 / (double)pulse_period)) 来计算正占空比。
volatile uint32_t up1_capture_time 0; // 用于存储第一次上升沿捕获的时间
volatile uint32_t down_capture_time 0; // 用于存储第一次上升沿捕获的时间
volatile uint32_t up2_capture_time 0; // 用于存储第二次上升沿捕获的时间
volatile uint32_t pulse_width 0; // 用于存储脉冲宽度
volatile uint32_t pulse_period 0; // 用于存储脉冲周期
volatile double duty_cycle 0; // 用于存储正占空比
volatile double frequency 0; // 用于存储频率void gpt5_callback(timer_callback_args_t *p_args)
{/* TODO: add your own code here */if ((TIMER_EVENT_CAPTURE_B p_args-event)) // 捕获事件{bsp_io_level_t p_port_value_port_102;// 读取端口电平状态如果是低电平则发生的是下降沿高电平则是上升沿R_IOPORT_PinRead(g_ioport_ctrl, BSP_IO_PORT_01_PIN_02, p_port_value_port_102);// 获取当前定时器的时钟频率和周期timer_info_t info;(void) R_GPT_InfoGet(g_timer5_ctrl, info);uint64_t clock_frequency info.clock_frequency; // 定时器时钟频率uint32_t current_period_counts info.period_counts; // 定时器周期uint32_t current_time p_args-capture; // 获取当前捕获时间计数值if (p_port_value_port_102 BSP_IO_LEVEL_HIGH) // 上升沿{// 记录第一次和第二次上升沿的时间戳up1_capture_timeup2_capture_time;up2_capture_timecurrent_time;// 计算脉冲周期从第一次到第二次上升沿的时间差if(up2_capture_timeup1_capture_time)pulse_period (up2_capture_time-up1_capture_time);elsepulse_period (current_period_counts -up1_capture_time) up2_capture_time;// 计算频率频率 时钟频率 / 脉冲周期frequency (double) (clock_frequency/pulse_period);// 计算脉冲宽度从下降沿到第二次上升沿的时间差if(up2_capture_timedown_capture_time)pulse_widthup2_capture_time-down_capture_time;elsepulse_width(current_period_counts -down_capture_time) up2_capture_time;// 计算占空比占空比 脉冲宽度 / 脉冲周期duty_cycle 100.0f-(pulse_width*100 / (double)pulse_period);}else // 下降沿{// 更新下降沿的捕获时间down_capture_timecurrent_time;}}
}主程序
void hal_entry(void)
{/* TODO: add your own code here */fsp_err_t err FSP_SUCCESS;/* Initializes the module. */err R_GPT_Open(g_timer8_ctrl, g_timer8_cfg);/* Handle any errors. This function should be defined by the user. */assert(FSP_SUCCESS err);/* Start the timer. */(void) R_GPT_Start(g_timer8_ctrl);R_BSP_SoftwareDelay (20, BSP_DELAY_UNITS_MILLISECONDS);err R_GPT_PeriodSet(g_timer8_ctrl, 12000);//频率assert(FSP_SUCCESS err);R_BSP_SoftwareDelay (20, BSP_DELAY_UNITS_MILLISECONDS);//不加延时可能会设置不成功err R_GPT_DutyCycleSet(g_timer8_ctrl, 3000, GPT_IO_PIN_GTIOCA);// 设置占空比assert(FSP_SUCCESS err);err R_GPT_DutyCycleSet(g_timer8_ctrl, 9000, GPT_IO_PIN_GTIOCB);// 设置占空比assert(FSP_SUCCESS err);R_BSP_SoftwareDelay (20, BSP_DELAY_UNITS_MILLISECONDS);// err R_GPT_Close(g_timer8_ctrl);
// assert(FSP_SUCCESS err);
// R_BSP_SoftwareDelay (20, BSP_DELAY_UNITS_MILLISECONDS);/* Open the transfer instance with initial configuration. */err R_SCI_UART_Open(g_uart9_ctrl, g_uart9_cfg);assert(FSP_SUCCESS err);printf(hello\n);/* Initializes the module. */err R_GPT_Open(g_timer5_ctrl, g_timer5_cfg);/* Handle any errors. This function should be defined by the user. */assert(FSP_SUCCESS err);/* Start the timer. */(void) R_GPT_Start(g_timer5_ctrl);(void) R_GPT_Enable(g_timer5_ctrl);R_BSP_SoftwareDelay (20, BSP_DELAY_UNITS_MILLISECONDS);while(1){printf(frequency%.2f,duty cycle%.2f\n,frequency,duty_cycle);duty_cycle 0; // 重置占空比frequency 0; // 重置频率R_BSP_SoftwareDelay (200, BSP_DELAY_UNITS_MILLISECONDS);}#if BSP_TZ_SECURE_BUILD/* Enter non-secure code */R_BSP_NonSecureEnter();
#endif
}演示
分别接入P101和P100。