第十一章 通用定时器(下篇)

第十一章 通用定时器(下篇)

目录

第十一章 通用定时器(下篇)

1 程序设计

1.1 TIM_InputCapture例程

3.4 TIM_OutPwm例程

3.5 TIM_Tim9例程

3.6 TIM_Touch例程

2 下载验证

2.1 TIM_InputCapture例程

2.2 TIM_OutPwm例程

2.3 TIM_Tim9例程

2.4 TIM_Touch例程


1 程序设计

1.1 TIM_InputCapture例程

此例程聚焦于 W55MH32 的定时器输入捕获功能,借助 TIM3 对外部信号的高电平持续时间展开测量,同时运用串口输出相关信息。下面是详细的程序分析:

1.初始化

  • 配置系统时钟:RCC_ClkConfiguration()
  • 初始化延时函数:delay_init()
  • 配置串口:UART_Configuration(),波特率设为 115200。
  • 获取系统时钟频率并输出。
  • 配置定时器 3:TIM_Configuration(),用于输入捕获。

2.主循环

 while (1)
    {
        if (TIM3_CAPTURE_STA & 0X80) //Successfully captured a rising edge
        {
            temp  = TIM3_CAPTURE_STA & 0X3F;
            temp *= 65536;                  //sum of overflow times
            temp += TIM3_CAPTURE_VAL;       //Get the total high time
            printf("HIGH:%d us\r\n", temp); //Print total peak time
            TIM3_CAPTURE_STA = 0;           //Initiate the next capture
        }
    }
  • 持续检查 TIM3_CAPTURE_STA 标志,若成功捕获到一个完整的高电平脉冲(TIM3_CAPTURE_STA & 0X80 为真),则计算高电平持续时间,输出该时间,接着重新初始化捕获状态,准备下一次捕获。

3.定时器中断服务程序

void TIM_Configuration(void)
{
    // ...(GPIO和时基配置略)...

    NVIC_InitTypeDef NVIC_InitStructure;

    // 1. 配置NVIC中断优先级
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;           // 选择TIM3中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级(数值越小优先级越高)
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        // 子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // 使能中断
    NVIC_Init(&NVIC_InitStructure);                           // 应用配置

    // 2. 使能TIM3中断类型
    TIM_ITConfig(TIM3, TIM_IT_Update | TIM_IT_CC2, ENABLE);    // 使能更新中断(计数器溢出)和通道2捕获中断
    TIM_Cmd(TIM3, ENABLE);                                    // 启动定时器
}
  • 若尚未成功捕获((TIM3_CAPTURE_STA & 0X80) == 0),则处理定时器更新中断与捕获中断。
  • 捕获到上升沿时,标记已捕获上升沿,把计数器清零,同时将捕获极性设为下降沿捕获。
  • 捕获到下降沿时,标记已成功捕获高电平脉冲宽度,记录捕获值,再把捕获极性设为上升沿捕获。
  • 处理定时器溢出情况。
  • 清除中断标志。

4.串口输出函数

  • SER_PutChar()函数用于向串口发送单个字符。
  • fputc()函数重定向标准输出,使 printf 能通过串口输出。

3.4 TIM_OutPwm例程

该例程借助对系统时钟、UART 和定时器的配置,实现了系统时钟的初始化、UART 通信以及定时器 PWM 输出的功能。通过printf()函数能够输出系统时钟频率信息,方便调试和监控。下面是详细的程序分析:

1.系统时钟配置

  • 使用 8MHz 外部晶振(HSE)经 PLL9 倍频生成 72MHz 系统时钟
  • 配置总线频率:HCLK=72MHz, PCLK1=36MHz, PCLK2=72MHz
  • 使能内部低速(LSI)和高速(HSI)时钟

2.串口通信

  • USART1 配置为 115200 波特率,8 位数据位,1 位停止位
  • PA9(TX)设为复用推挽输出,PA10(RX)浮空输入
  • 重定向printf到串口,自动添加\r\n转换

3.定时器 PWM 输出

void TIM_Configuration(void)
{
    GPIO_InitTypeDef        GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef       TIM_OCInitStructure;

    // 使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    // ================== GPIO配置:PA7为TIM3_CH2复用输出 ==================
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;    // PA7对应TIM3_CH2
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP; // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // ================== 时基配置:1MHz计数时钟,100μs周期 ==================
    TIM_TimeBaseStructure.TIM_Period        = 99;         // 周期值(0-99,共100个计数周期)
    TIM_TimeBaseStructure.TIM_Prescaler     = 35;         // PCLK1=36MHz预分频36倍(35+1)
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    // ================== PWM配置:50%占空比,PWM模式2 ==================
    TIM_OCInitStructure.TIM_OCMode       = TIM_OCMode_PWM2; // PWM模式2
    TIM_OCInitStructure.TIM_OutputState  = TIM_OutputState_Enable; // 使能输出
    TIM_OCInitStructure.TIM_Pulse        = 49;         // 脉冲值(决定占空比)
    TIM_OCInitStructure.TIM_OCPolarity   = TIM_OCPolarity_Low; // 低电平有效
    TIM_OC2Init(TIM3, &TIM_OCInitStructure); // 初始化通道2

    // 使能预装载和自动重装载
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM3, ENABLE);

    // 启动定时器
    TIM_Cmd(TIM3, ENABLE);
    TIM_CtrlPWMOutputs(TIM3, ENABLE); // 适用于高级定时器的输出控制
}
  • TIM3 通道 2 在 PA7 输出 50% 占空比 PWM
  • 周期 100μs(计数周期 99),频率 10kHz
  • 时基配置:PCLK1 (36MHz) 预分频 36 得到 1MHz 计数时钟

3.5 TIM_Tim9例程

此例程主要实现了 W55MH32 的定时器(TIM9)中断测试以及 UART 串口通信功能,以下为其工作流程总结:

1. 初始化阶段

延时函数初始化:调用delay_init()函数,对延时功能进行初始化。

UART 串口配置:借助UART_Configuration(115200)函数,把 USART1 的波特率设定为 115200,并完成 GPIO 引脚和 USART 的初始化工作。

获取时钟频率:运用RCC_GetClocksFreq(&clocks)函数获取系统时钟频率,然后通过printf()函数将系统时钟、HCLK、PCLK1、PCLK2 以及 ADCCLK 的频率信息打印出来。

2. 定时器配置阶段

使能时钟:开启 TIM9 的时钟。

定时器初始化:对定时器 TIM9 的周期、预分频器、时钟分割和计数模式等参数进行配置。

使能中断:使能 TIM9 的更新中断,并对 NVIC 中断优先级进行设置。

启动定时器:启动 TIM9 定时器。

3. 主循环阶段

主函数中的while (1)是一个无限循环,程序在此处持续等待定时器中断的发生。

1.中断处理阶段

void TIM1_BRK_TIM9_IRQHandler(void)
{
    // 4.1 检查更新中断标志
    if (TIM_GetITStatus(TIM9, TIM_IT_Update) != RESET)
    {
        // 4.2 清除中断标志
        TIM_ClearITPendingBit(TIM9, TIM_IT_Update);
        // 4.3 串口输出中断信息(打印函数名)
        printf("%s\n", __FUNCTION__);
    }
}

当定时器 TIM9 产生更新中断时,TIM1_BRK_TIM9_IRQHandler()函数会被调用。在该函数里,会先检查中断标志位,若标志位被置位,则清除该标志位,并通过printf()函数打印出当前函数名。

2.串口输出阶段

// 5.1 单字符发送函数(阻塞式发送)
int SER_PutChar(int ch)
{
    while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC)); // 等待发送完成
    USART_SendData(USART_TEST, (uint8_t)ch);
    return ch;
}

// 5.2 重定向fputc函数(支持printf)
int fputc(int c, FILE *f)
{
    if (c == '\n') // 自动添加回车符(适配串口终端)
    {
        SER_PutChar('\r');
    }
    return SER_PutChar(c);
}
  • SER_PutChar()函数:用于向 USART1 发送单个字符,会等待发送完成标志位被置位后再发送字符。
  • fputc()函数:对标准库的fputc()函数进行重定向,实现将字符输出到 USART1。若遇到换行符\n,会先发送回车符\r,再发送换行符\n。

该例程的核心功能是配置定时器 TIM9 使其按设定参数产生中断,在中断发生时通过串口输出信息,同时利用串口输出系统时钟频率等信息。

3.6 TIM_Touch例程

此例程的主要作用是实现触摸检测功能,并通过 LED 灯状态的改变直观地反馈触摸事件,同时借助串口输出相关调试信息,方便开发人员进行调试与监测。下面是具体功能的详细介绍:

1.初始化阶段

  • 系统初始化:调用delay_init()进行延时初始化
  • 串口配置:通过UART_Configuration(115200)配置 USART1 为 115200 波特率
  • 时钟信息输出:获取并打印系统时钟各频率参数
  • 硬件初始化:调用LED_Init()初始化 LED 控制引脚,调用TPAD_Init(6)初始化触摸检测模块

2.主循环阶段

  • 触摸检测:通过TPAD_Scan(0)实时检测触摸事件检测到触摸时:打印 "Touch" 并翻转 LED1 状态
  • LED0 周期性闪烁:通过计数器实现 150ms 周期(15×10ms)翻转 LED0
  • 循环延时:每次循环执行 10ms 延时

3.硬件控制

// LED初始化函数(根据开发板类型选择不同引脚)
void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

#ifdef PIN48_BOARD
    // 48脚开发板: LED0->PA7, LED1->PB0
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;  // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_SetBits(GPIOA, GPIO_Pin_7);  // 初始状态熄灭LED

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB, GPIO_Pin_0);

#else
    // 64脚开发板: LED0->PC2, LED1->PC3
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_SetBits(GPIOC, GPIO_Pin_3 | GPIO_Pin_2);  // 初始状态熄灭LED
#endif
}
// 触摸检测初始化(依赖tpad.h库实现)
void TPAD_Init(u8 sysclk)
{
    // 实际代码在tpad.c中实现,此处为函数声明
    // 配置触摸检测相关GPIO和定时器
}

// 触摸扫描函数(返回1表示检测到触摸)
u8 TPAD_Scan(u8 mode)
{
    // 实际代码在tpad.c中实现,此处为函数声明
    // mode=0: 单次触发模式
    // mode=1: 连续触发模式
}
  • LED 控制:根据开发板类型(PIN48/PIN64)控制对应 GPIO 引脚
  • 触摸检测:通过 TPAD 模块实现触摸信号采集与处理(具体实现由 tpad 库提供)

4.功能特点

  • 双 LED 状态控制:LED0 周期性闪烁,LED1 触摸触发翻转
  • 串口调试支持:通过 printf 输出系统信息和触摸事件
  • 硬件无关性:通过条件编译适应不同开发板(PIN48/PIN64)

2 下载验证

2.1 TIM_InputCapture例程

程序下载到开发板运行后,串口会先输出系统时钟频率信息与“TIM Input CaptureTest.”提示信息。之后,若PA7引脚有信号输入,每当成功捕获到一个完整高电平脉冲,串口就会输出该高电平的持续时间(单位为微秒),并自动准备下一次捕获。若信号频率过高致计数器溢出,或信号电平异常,捕获可能出现异常,需重新上电复位;若没有信号输入则无捕获结果输出。

2.2 TIM_OutPwm例程

该程序下载运行后,通过USART1(PA9/PA10)以115200波特率输出系统时钟信息:"SYSCLK: 72.0Mhz, HCLK: 72.0Mhz, PCLK1: 36.0Mhz, PCLK2: 72.0Mhz, ADCCLK: 72.0Mhz"和"TIM Out Test."。PA7引脚持续输出10kHz频率、50%占空比的PWM信号(低电平有效),周期100μs。程序执行完毕后进入无限循环保持运行状态,CPU空闲但PWM输出持续。验证时需用示波器观察PA7波形,通过串口工具配置相同波特率查看打印信息,同时确保硬件连接正确(PA7接示波器、PA9接串口转USB模块)。

如果想查看PWM输出的占空比,可以在循环里加这段代码:

 uint16_t pwm_value = TIM_GetCapture2(TIM3);
float duty_cycle = (float)pwm_value / 99 * 100;
printf("PWM Duty Cycle: %.2f%%\n", duty_cycle);
delay_ms(1000);

这样可以打印出PWM的占空比:

2.3 TIM_Tim9例程

程序启动后,先进行延时和串口初始化,输出系统时钟频率信息与 “TIM Tim9 Base Test.” 提示,接着配置并启动定时器 TIM9,随后进入无限循环;当 TIM9 产生更新事件触发中断时,中断服务函数会清除中断标志并通过串口输出自身函数名,之后继续等待下一次中断。

2.4 TIM_Touch例程

程序运行后,LED0以150ms周期闪烁,检测到触摸时LED1状态翻转并通过串口打印"Touch",同时启动时输出系统时钟频率信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值