1 前言
瑞萨RA生态工作室为本次开发板试用提供了一份实验手册,一共有四个小实验,包括PWM呼吸灯、ADC电压采集、RTC时钟日历以及触摸按键。这里就依次序完成四个实验学习开发板的功能,然后做一个低功耗的桌面摆件项目。
这次评测报告内容是PWM呼吸灯。
2 硬件部分
2.1 LED
这块RA2L1开发板载有2颗LED灯,通过原理图可知它们接在了P103和P104引脚上,串了限流电阻接地。

2.2 GPT介绍
通用 PWM 定时器(GPT,General PWM Timer)是 RA MCU 的其中一种 32/16 位的定时器外设。 在 GPT 当中,可分为 GPT32 和 GPT16,它们最主要的区别是计数器的不同。 GPT32 是 32 位的定时器,包含的计数器是 32 位的,所能计数的范围为:0 ~ 0xFFFF_FFFF; 而 GPT16 是 16 位的定时器,包含的计数器是 16 位的,所能计数的范围为:0 ~ 0xFFFF。
定时器(Timer)最基本的功能就是定时,比如定时发送串口数据、定时采集AD数据、定时触发中断处理其它事务等等。 如果把定时器与 GPIO 引脚结合起来使用的话可以实现更加丰富的功能, 可以对输入信号进行计数,可以测量输入信号的脉冲宽度,可以输出单个脉冲、PWM 等波形,等等。 通过定时器生成 PWM 波形信号来控制电机状态是工业控制的普遍方法,这方面知识非常值得深入了解。
GPT 模块可用于计数事件、测量外部输入信号、作为通用计时器并产生周期性中断、以及输出周期性或 PWM 信号到 GTIOC 引脚。 GPT 也可用于输出单个脉冲,但是注意这是通过软件来实现的,GPT 硬件本身不支持输出单个脉冲(One-Shot)功能。 当使用单个脉冲(One-Shot)模式时,必须要开启中断,计时器需要在脉冲周期结束后在 ISR 中断服务函数中被停止。
2.3 PWM介绍
PWM 的全称是脉冲宽度调制(Pulse Width Modulation),简称脉宽调制,通俗的讲就是调节脉冲的宽度。 其原理是通过将有效的电信号分散成离散形式从而来降低电信号所传递的平均功率, 根据面积等效法则,可以通过对改变脉冲的时间宽度,来等效地获得所需要合成的相应幅值和频率的波形。 PWM 有着非常广泛的应用,比如直流电机控制、开关电源、逆变器等等。
3 软件部分
将先前的项目模板复制一份,重命名为01_PWM-lED
3.1 GPT-PWM配置
点击configuration.xml文件,
| 步骤 |
操作 |
|---|
| 1 |
在左侧项目资源管理器中,点击configuration.xml文件。 |
| 2 |
点击界面下方标签栏中的Pins标签,进入引脚配置界面。 |
| 3 |
在Pin Selection区域,展开Timers:GPT,选择GPT2。 |
| 4 |
在Pin Configuration区域,将Operation Mode设置为GTIOCA or GTIOCB。 |
| 5 |
在Pin Configuration区域,勾选GTIOCA下的P103引脚。 |

接着来到Stacks选项卡,
| 步骤 |
操作 |
|---|
| 1 |
在界面下方标签栏,点击Stacks标签,进入堆栈配置页面 |
| 2 |
在HAL/Common Stacks区域,点击New Stack按钮 |
| 3 |
在弹出菜单中,选择Timers选项 |
| 4 |
在Timers子菜单中,选择Timer, General PWM (r_gpt) |

| 序号 |
操作 |
|---|
| 1 |
在HAL/Common Stacks区域,点击选中g_timer2 Timer, General PWM (r_gpt)。 |
| 2 |
在下方属性设置区域,找到General部分,配置参数:Name为g_timer2,Channel为2,Mode为Periodic,Period为1,Period Unit为Kilohertz。 |
| 3 |
在Custom Waveform部分,设置Duty Cycle Percent (only applicable in PWM mode)为50,GTIOCA Output Enabled为True,GTIOCA Stop Level为Pin Level Low,GTIOCB Output Enabled为False,GTIOCB Stop Level为Pin Level Low。 |
| 4 |
在Pins部分,确认GTIOCA2A对应P103。 |

配置完成后,生成项目代码。
3.2 代码编写
3.2.1 PWM.c
新建一个源文件PWM.c,里面内容如下:
#include "hal_data.h"
void GPT_PWM_SetDuty(uint8_t duty)
{
timer_info_t info;
R_GPT_InfoGet(&g_timer2_ctrl, &info);
uint32_t current_period_counts = info.period_counts;
uint32_t duty_cycle_counts = (uint32_t)(((uint64_t)current_period_counts * duty) / 100);
R_GPT_DutyCycleSet(&g_timer2_ctrl, duty_cycle_counts, GPT_IO_PIN_GTIOCA);
}
3.2.2 PWM.h
新建一个头文件PWM.c,里面内容如下:
#ifndef PWM_H_
#define PWM_H_
void GPT_PWM_SetDuty(uint8_t duty);
#endif
3.2.3 修改hal_entry.c
在包含头文件部分,添加:
#include "PWM.h"
在hal_entry函数中,添加代码:
typedef enum
{
up = 0,
down
} Direction;
uint8_t dutyNum = 0;
Direction d = up;
Debug_UART9_Init();
R_GPT_Open(&g_timer2_ctrl, &g_timer2_cfg);
R_GPT_Start(&g_timer2_ctrl);
while (1)
{
if (d == up)
{
if (dutyNum == 100)
{
d = down;
}
dutyNum++;
}
else
{
if (dutyNum == 0)
{
d = up;
}
dutyNum--;
}
GPT_PWM_SetDuty(dutyNum);
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
}
这段代码作用是,每隔10ms设置一次PWM占空比的值dutyNum。dutyNum是从0递增,若达到100,则转为递减,若降低到0,则转为递增,循环往复。
4 下载测试
把编译好的程序下载到开发板并复位,可以观察到LED灯从暗到亮再到暗的循环变化。
利用示波器,也能看到该引脚的PWM波形