【瑞萨RA4系列开发板体验】GPT定时器的基础使用
作者:HonestQiao
在RA4M2的系统重,提供了三种定时器,从手册之中可以了解:
三种定时器分别是: - 普通PWM 32位定时器:GPT32
- 普通PWM 16位定时器:GPT16
- 低功耗用用异步定时器:AGT
其中普通GPT比较常用,主要是用于生成PWM波形,从而控制例如无刷电机等外部设备。当然,也可以不进行输出,直接当做定时器使用,在定时回调中,进行我们需要的处理。 从手册上可以了解这些定时器的具体功能规范:
下面,就以点灯的实例,来展示GPT的基础使用。 一、FPS设置 要启用GPT,首先就需要在FPS种进行设置。 关于LED部分的设置,就不重新说了,这个是基础。 GPT设置步骤如下:
上述步骤,就是先添加一个GPT的Stack,然后设置其初始化参数和回调参数: 初始化参数: - Name: 名称
- Channel: 通道
- Mode: 模式,选择周期性
- Period: 周期位1
Period Unit: 周期的单位位秒 也就是定时器1秒触发一次
周期单位可以详细设置,具体如下:
在bsp_delay.h中,也有类似的定义:
- typedef enum
- {
- BSP_DELAY_UNITS_SECONDS = 1000000, ///< Requested delay amount is in seconds
- BSP_DELAY_UNITS_MILLISECONDS = 1000, ///< Requested delay amount is in milliseconds
- BSP_DELAY_UNITS_MICROSECONDS = 1 ///< Requested delay amount is in microseconds
- } bsp_delay_units_t;
复制代码回调参数:
- static bool status = false;
- /* GPT 初始化函数 */
- void GPT_Timing_Init(void)
- {
- /* 初始化 GPT0 模块 */
- R_GPT_Open(&g_timer_gpt0_ctrl, &g_timer_gpt0_cfg);
- /* 启动 GPT0 定时器 */
- R_GPT_Start(&g_timer_gpt0_ctrl);
- }
- /* GPT 中断回调函数 */
- void gpt0_timing_callback(timer_callback_args_t * p_args)
- {
- /* 定时器溢出事件 */
- if (TIMER_EVENT_CYCLE_END == p_args->event)
- {
- /* 翻转 LED1 */
- //每秒翻转一次
- status = ! status;
- if(status) {
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_HIGH); // 点亮LED
- } else {
- R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_LOW); // 关闭LED
- }
- }
- }
复制代码在上述代码终,GPT_Timing_Init()负责初始化,因为我们只用了gpt0,所以只需要初始化gpt0即可。 gpt0对应的控制变量,以及回调函数的预定义,在hal_data.h终有定义,具体如下:
- extern gpt_instance_ctrl_t g_timer_gpt0_ctrl;
- extern const timer_cfg_t g_timer_gpt0_cfg;
- #ifndef gpt0_timing_callback
- void gpt0_timing_callback(timer_callback_args_t * p_args);
- #endif
复制代码 在hal_data.c中,有关于g_timer_gpt0_ctrl和g_timer_gpt0_cfg的具体定义:
- const timer_cfg_t g_timer_gpt0_cfg =
- {
- .mode = TIMER_MODE_PERIODIC,
- /* Actual period: 1 seconds. Actual duty: 50%. */
- .period_counts = (uint32_t) 0x5f5e100,
- .duty_cycle_counts = 0x2faf080,
- .source_div = (timer_source_div_t)0,
- .channel = 0,
- .p_callback = gpt0_timing_callback,
- /** If NULL then do not add & */
- #if defined(NULL)
- .p_context = NULL,
- #else
- .p_context = &NULL,
- #endif
- .p_extend = &g_timer_gpt0_extend,
- .cycle_end_ipl = (10),
- #if defined(VECTOR_NUMBER_GPT0_COUNTER_OVERFLOW)
- .cycle_end_irq = VECTOR_NUMBER_GPT0_COUNTER_OVERFLOW,
- #else
- .cycle_end_irq = FSP_INVALID_VECTOR,
- #endif
- };
- /* Instance structure to use this module. */
- const timer_instance_t g_timer_gpt0 =
- {
- .p_ctrl = &g_timer_gpt0_ctrl,
- .p_cfg = &g_timer_gpt0_cfg,
- .p_api = &g_timer_on_gpt
- };
复制代码在前面代码终,还添加了一个status变量,用于表示LED的状态,true则电量LED1,false则熄灭LED1。其中,BSP_IO_PORT_04_PIN_15对应LED1的引脚。 然后,在hal_entry()终调用初始化,就能够启动定时器了,具体如下:
- void hal_entry(void)
- {
- /* TODO: add your own code here */
- fsp_err_t err; //
- err = R_IOPORT_Open(&g_ioport_ctrl, &g_bsp_pin_cfg); // 初始化引脚
- assert(FSP_SUCCESS == err); // 判断是否初始化成功
- GPT_Timing_Init(); // GPT 初始化
- while(1)
- { R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
- }
- #if BSP_TZ_SECURE_BUILD
- /* Enter non-secure code */
- R_BSP_NonSecureEnter();
- #endif
- }
复制代码使用GPT_Timing_Init()进行初始化后,定时器就会启动,并按照预定的周期,调用gpt0_timing_callback()。 代码终的R_BSP_SoftwareDelay()表示演示,以免while(1)疯狂运行。 编写好代码之后,编译下载到开发板上,就可以看到LED1,每秒闪烁一次了。 在前面的gpt cfg定义中,有两个很重要,但设置为1秒的时候,对应的值为:
- /* Actual period: 1 seconds. Actual duty: 50%. */
- .period_counts = (uint32_t) 0x5f5e100,
- .duty_cycle_counts = 0x2faf080,
复制代码 当设置为100毫秒的时候,对应的值为:
- /* Actual period: 0.1 seconds. Actual duty: 50%. */
- .period_counts = (uint32_t) 0x989680,
- .duty_cycle_counts = 0x4c4b40,
复制代码在上述配置中,period_counts表示定时器一个周期的计数次数,达到计数次数,则调用一次回调函数。 duty_cycle_counts表示占空比的技术次数,上述两个值,都为period_counts的一半,所以如果是PWM输出,则其对应的占空比为50%。 如果使用0.1seconds的配置,然后编译烧录,就可以看到LED快速闪烁了。 如果将1秒的period_counts除以0.1秒的period_counts,可以得到倍差值:0x5f5e100/0x989680 = 0xa,也就是10倍。 明白了这一点,那我们想要及时修改定时器的定时周期测试的时候,就不用再去FSP中操作了。等调整了定时器,达到实际需要了,再到FSP中进行一次设置,使得配置能够写入到xml配置文件中。
|