第4章 GPT12模块配置:定时器原理、中断与PWM实战
各位同学,欢迎来到第4章。今天我们来聊聊GPT12模块。说实话,这个模块在嵌入式开发里太常用了。无论是做电机控制、信号测量,还是生成PWM波,都离不开它。我个人习惯把GPT12叫做“万能定时器”,因为它既能做普通计时,又能输出PWM,还能捕获输入信号。
嗯,咱们这一章的重点有三个:定时器原理、中断配置、PWM生成。最后我会带大家做两个实战项目——呼吸灯和舵机控制。这两个项目做下来,你对GPT12的理解绝对会上一个台阶。
4.1 GPT12定时器原理
先说说GPT12是什么。它是AURIX系列芯片里的一个通用定时器模块。说白了,就是一个可以计数的硬件单元。你给它一个时钟源,它就开始数数,数到某个值就触发事件。
GPT12模块内部有5个定时器单元:
- T2、T3、T4:三个16位基本定时器
- T5、T6:两个16位定时器,支持捕获/比较功能
每个定时器都有自己的控制寄存器和状态寄存器。我刚开始学的时候,总觉得寄存器太多记不住。后来发现,其实只要掌握几个核心寄存器就够了:
| 寄存器 | 功能 | 关键位 |
|---|---|---|
| T2CON / T3CON / T4CON | 定时器控制 | 模式选择、时钟分频、重载使能 |
| T5CON / T6CON | 捕获/比较控制 | 捕获模式、比较模式、PWM模式 |
| T2 / T3 / T4 | 定时器计数值 | 当前计数值 |
| T5 / T6 | 捕获/比较值 | 捕获到的值或比较阈值 |
定时器的工作模式主要有三种:
- 定时模式:内部时钟驱动,计数值递增或递减
- 门控模式:外部信号控制定时器启停
- 计数模式:外部事件触发计数
我在项目中遇到过一个问题:用定时器做延时,结果发现时间不准。后来排查发现是时钟分频没配好。你想想看,如果时钟源是100MHz,不分频的话,定时器每10ns就跳一次,16位定时器65535个计数值,总共才655微秒。所以要根据实际需求选择合适的分频系数。
核心要点:定时器的精度取决于时钟源和分频系数。分频越大,计时越长,但精度越低。这是一个权衡。
4.2 定时器中断配置
定时器中断,说白了就是让定时器在计数值达到某个条件时,触发一个中断服务函数。这样CPU就不用一直轮询定时器状态了,可以去做别的事。
配置定时器中断的步骤,我总结为四步走:
- 初始化定时器:设置模式、时钟分频、重载值
- 配置中断源:选择触发中断的事件(比如溢出、比较匹配)
- 注册中断服务函数:把中断处理函数绑定到对应的中断向量
- 使能中断:打开全局中断和定时器中断
用iLLD库配置,代码其实很简洁。我给大家看一个T3定时器中断的例子:
// 1. 初始化T3定时器,时钟分频64,重载值5000
// 时钟源100MHz,分频64后为1.5625MHz,5000个计数值约3.2ms
IfxGpt12_T3_init(&gpt12, &gpt12Config);
IfxGpt12_T3_setTimerValue(&gpt12, 5000);
IfxGpt12_T3_setMode(&gpt12, IfxGpt12_Mode_timer);
// 2. 配置中断源:T3溢出中断
IfxGpt12_T3_clearInterrupt(&gpt12);
IfxGpt12_T3_enableInterrupt(&gpt12);
// 3. 注册中断服务函数
// 注意:中断向量号要查手册,T3溢出中断对应SRC_GPT12_T3
IfxSrc_init(gpt12Config.interrupt.src,
gpt12Config.interrupt.priority);
IfxSrc_enable(gpt12Config.interrupt.src);
// 4. 启动定时器
IfxGpt12_T3_run(&gpt12, TRUE);
中断服务函数怎么写呢?
// T3定时器中断服务函数
IFX_INTERRUPT(gpt12T3Isr, 0, gpt12Config.interrupt.priority);
void gpt12T3Isr(void)
{
// 清除中断标志
IfxGpt12_T3_clearInterrupt(&gpt12);
// 用户代码:比如翻转LED
IfxPort_togglePin(&MODULE_P13, 0);
}
小技巧:中断服务函数里不要做耗时操作。我曾经见过有人直接在中断里做printf打印,结果系统卡死。中断里只做标志位设置或简单操作,复杂逻辑放到主循环里处理。
4.3 PWM生成
PWM生成,其实就是利用定时器的比较功能。定时器不断计数,当计数值和比较值匹配时,输出电平翻转。这样就能产生占空比可调的方波。
GPT12的T5和T6定时器支持PWM输出。配置步骤:
- 设置定时器为比较模式
- 配置输出引脚为PWM功能
- 设置周期值和比较值
- 启动定时器
举个例子,用T5输出一个1kHz、50%占空比的PWM:
// 配置T5为比较模式,输出PWM
IfxGpt12_T5_init(&gpt12, &gpt12Config);
IfxGpt12_T5_setMode(&gpt12, IfxGpt12_Mode_timer);
// 设置周期值:100MHz / 64分频 / 1000Hz = 1562
IfxGpt12_T5_setTimerValue(&gpt12, 1562);
// 设置比较值:50%占空比 = 1562 / 2 = 781
IfxGpt12_T5_setCompareValue(&gpt12, 781);
// 配置输出引脚
IfxGpt12_T5_setOutputMode(&gpt12, IfxGpt12_OutputMode_centerAligned);
// 启动定时器
IfxGpt12_T5_run(&gpt12, TRUE);
这里要注意,PWM的频率由周期值决定,占空比由比较值决定。改变比较值就能实时调整占空比。
避坑指南:我曾经在项目里犯过一个低级错误——比较值设置得比周期值还大。结果PWM输出一直为高电平,电机全速运转,差点烧了。记住:比较值必须小于周期值!
4.4 实战:呼吸灯
呼吸灯,就是让LED的亮度从暗到亮、再从亮到暗循环变化。说白了,就是不断改变PWM的占空比。
实现思路:
- 用T5输出PWM,驱动LED
- 在主循环里,每隔一段时间改变比较值
- 比较值从0递增到周期值,再从周期值递减到0
代码实现:
// 全局变量
uint16 g_pwmPeriod = 1000;
uint16 g_pwmDuty = 0;
uint8 g_direction = 1; // 1:递增, 0:递减
// 主循环
while(1)
{
// 每10ms更新一次占空比
wait(10);
if(g_direction)
{
g_pwmDuty += 10;
if(g_pwmDuty >= g_pwmPeriod)
{
g_pwmDuty = g_pwmPeriod;
g_direction = 0;
}
}
else
{
if(g_pwmDuty >= 10)
g_pwmDuty -= 10;
else
{
g_pwmDuty = 0;
g_direction = 1;
}
}
// 更新比较值
IfxGpt12_T5_setCompareValue(&gpt12, g_pwmDuty);
}
嗯,这里要注意步进值的选择。步进太大,呼吸效果会显得很生硬;步进太小,变化又太慢。我一般选周期值的1%到2%作为步进,效果比较自然。
4.5 实战:舵机控制
舵机控制,是PWM应用的经典场景。舵机的角度由PWM的脉宽决定,通常是0.5ms到2.5ms对应0°到180°。
舵机控制的关键参数:
| 角度 | 脉宽 | 占空比(50Hz) |
|---|---|---|
| 0° | 0.5ms | 2.5% |
| 90° | 1.5ms | 7.5% |
| 180° | 2.5ms | 12.5% |
配置步骤:
- 设置PWM频率为50Hz(周期20ms)
- 根据目标角度计算脉宽对应的比较值
- 更新比较值即可改变舵机角度
代码示例:
// 设置PWM频率为50Hz
// 100MHz / 64分频 / 50Hz = 31250
#define PWM_PERIOD 31250
#define PULSE_MIN 1562 // 0.5ms对应的计数值
#define PULSE_MAX 7812 // 2.5ms对应的计数值
// 设置舵机角度
void servo_setAngle(uint8 angle)
{
// 角度范围0-180,映射到脉宽范围
uint32 pulse = PULSE_MIN + (uint32)(PULSE_MAX - PULSE_MIN) * angle / 180;
// 更新比较值
IfxGpt12_T5_setCompareValue(&gpt12, (uint16)pulse);
}
// 使用示例
servo_setAngle(90); // 转到90°
经验之谈:舵机对PWM的精度要求比较高。我建议用定时器的中心对齐模式,这样PWM的上升沿和下降沿更对称,舵机抖动会小很多。
4.6 常见问题与调试技巧
最后,我分享几个调试GPT12时容易踩的坑:
- 定时器不工作:检查时钟源是否使能,分频配置是否正确
- 中断不触发:确认中断标志是否清除,中断优先级是否配置正确
- PWM输出异常:检查引脚复用功能配置,确认输出模式设置正确
- 舵机抖动:可能是PWM频率不稳定,建议用硬件定时器而不是软件延时
调试时,我习惯先用示波器看PWM波形。频率对不对?占空比准不准?一眼就能看出来。如果没有示波器,也可以用逻辑分析仪,或者干脆用万用表测平均电压——占空比50%时,电压应该是3.3V的一半。
好了,这一章的内容就到这里。GPT12模块虽然看起来寄存器多,但只要掌握了核心原理,配置起来其实不难。下一章我们会讲GTM模块,那才是真正的大杀器。大家先把GPT12练熟,后面学GTM会轻松很多。