第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就不用一直轮询定时器状态了,可以去做别的事。

配置定时器中断的步骤,我总结为四步走:

  1. 初始化定时器:设置模式、时钟分频、重载值
  2. 配置中断源:选择触发中断的事件(比如溢出、比较匹配)
  3. 注册中断服务函数:把中断处理函数绑定到对应的中断向量
  4. 使能中断:打开全局中断和定时器中断

用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的占空比。

实现思路:

  1. 用T5输出PWM,驱动LED
  2. 在主循环里,每隔一段时间改变比较值
  3. 比较值从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.5ms 2.5%
90° 1.5ms 7.5%
180° 2.5ms 12.5%

配置步骤:

  1. 设置PWM频率为50Hz(周期20ms)
  2. 根据目标角度计算脉宽对应的比较值
  3. 更新比较值即可改变舵机角度

代码示例:

// 设置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会轻松很多。