Nuru_Banmian
Nuru_Banmian
Published on 2025-07-10 / 52 Visits
0
0

通用定时器_同时测量PWM周期和占空比_寄存器&HAL库实现

通用定时器-同时测量PWM周期和占空比-寄存器&HAL库实现

使用到的相关寄存器

CC1S

通用定时器-同时测量PWM周期和占空比-CC1S-1.png

通用定时器-同时测量PWM周期和占空比-CC1S-2.png通用定时器-同时测量PWM周期和占空比-CC1S-3.png

TS

通用定时器-同时测量PWM周期和占空比-TS-1.png

通用定时器-同时测量PWM周期和占空比-TS-2.png

通用定时器-同时测量PWM周期和占空比-TS-3.png

相关寄存器设置代码

  1. 配置通道为输入并映射正确通道

/* 4. CH1通道配置为输入,并IC1映射到TI1上:CCMR1_CC1S=01 */
TIM4->CCMR1 &= ~TIM_CCMR1_CC1S_1;
TIM4->CCMR1 |= TIM_CCMR1_CC1S_0;

/* 4.1 把IC2映射到TI1上: CCMR1_CC2S=10*/
TIM4->CCMR1 |= TIM_CCMR1_CC2S_1;
TIM4->CCMR1 &= ~TIM_CCMR1_CC2S_0;

  1. 配置从模式控制器

/* 11. 必须配置从模式控制器为复位模式 SMS=100, 触发输入信号为:TI1FP1 TS=101*/
TIM4->SMCR |= TIM_SMCR_TS_2;
TIM4->SMCR &= ~TIM_SMCR_TS_1;
TIM4->SMCR |= TIM_SMCR_TS_0;

TIM4->SMCR |= TIM_SMCR_SMS_2;
TIM4->SMCR &= ~(TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0);

寄存器代码实现

TIM4.h

#ifndef __TIM4_H
#define __TIM4_H

#include "stm32f10x.h"

void TIM4_Init(void);

// 将定时器的开关包装成函数
void TIM4_Start(void);
void TIM4_Stop(void);

// 获取输入信号周期的函数
double TIM4_GetPWMCycle(void);
double TIM4_GetPWMFreq(void);

double TIM4_GetPWMDutyCycle(void);

#endif

TIM4.c

#include "tim4.h"

void TIM4_Init(void)
{
    // 1. 开启时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;

    // 2. GPIO工作模式,PB6:浮空输入 CNF-01,MODE-00
    GPIOB->CRL &= ~GPIO_CRL_MODE6;
    GPIOB->CRL &= ~GPIO_CRL_CNF6_1;
    GPIOB->CRL |= GPIO_CRL_CNF6_0;

    // 定时器配置

    // 3. 时基部分
    // 3.1 预分频值 71,得到1MHz
    TIM4->PSC = 71;

    // 3.2 重装载值,65535,尽量在信号一个周期内不要产生溢出
    TIM4->ARR = 65535;

    // 3.3 计数方向
    TIM4->CR1 &= ~TIM_CR1_DIR;

    // 4. 输入通道部分

    // 4.1 TI1的输入选择
    TIM4->CR2 &= ~TIM_CR2_TI1S;

    // 4.2 输入滤波器
    TIM4->CCMR1 &= ~TIM_CCMR1_IC1F;

    // 4.3 配置极性:上升沿触发
    TIM4->CCER &= ~TIM_CCER_CC1P;

    // 通道2:下降沿触发
    TIM4->CCER |= TIM_CCER_CC2P;

    // 4.4 选择通道1的输入映射为 TI1:CC1S - 01
    TIM4->CCMR1 &= ~TIM_CCMR1_CC1S_1;
    TIM4->CCMR1 |= TIM_CCMR1_CC1S_0;

    // 选择通道2的输入映射为 TI1:CC2S - 10
    TIM4->CCMR1 |= TIM_CCMR1_CC2S_1;
    TIM4->CCMR1 &= ~TIM_CCMR1_CC2S_0;

    // 4.5 预分频器
    TIM4->CCMR1 &= ~TIM_CCMR1_IC1PSC;
    TIM4->CCMR1 &= ~TIM_CCMR1_IC2PSC;

    // 4.6 配置触发输入信号TRGI TS - 101
    TIM4->SMCR |= TIM_SMCR_TS_2;
    TIM4->SMCR &= ~TIM_SMCR_TS_1;
    TIM4->SMCR |= TIM_SMCR_TS_0;

    // 4.7 配置从模式为复位模式 SMS - 100
    TIM4->SMCR |= TIM_SMCR_SMS_2;
    TIM4->SMCR &= ~TIM_SMCR_SMS_1;
    TIM4->SMCR &= ~TIM_SMCR_SMS_0;

    // 4.6 通道1输入捕获使能
    TIM4->CCER |= TIM_CCER_CC1E;
    // 通道2输入捕获使能
    TIM4->CCER |= TIM_CCER_CC2E;
}

// 将定时器的开关包装成函数
void TIM4_Start(void)
{
    TIM4->CR1 |= TIM_CR1_CEN;
}

void TIM4_Stop(void)
{
    TIM4->CR1 &= ~TIM_CR1_CEN;
}

// cycle单位为us,返回周期单位为ms
double TIM4_GetPWMCycle(void)
{
    return TIM4->CCR1 / 1000.0;
}

double TIM4_GetPWMFreq(void)
{
    return 1000000.0 / TIM4->CCR1;
}

double TIM4_GetPWMDutyCycle(void)
{
    return TIM4->CCR2 * 1.0 / TIM4->CCR1;
}

main.c

#include "usart.h"
#include "tim5.h"
#include "tim4.h"
#include "delay.h"

int main(void)
{
	// 初始化
	USART_Init();
	TIM4_Init();
	TIM5_Init();

	printf("Hello, world!\n");

	// 开启定时器
	TIM5_Start();
	TIM4_Start();

	TIM5_SetDutyCycle(78);

	while (1)
	{
		printf("T = %.2f ms, f = %.2f Hz, duty = %.2f %%\n", 
			TIM4_GetPWMCycle(), TIM4_GetPWMFreq(), TIM4_GetPWMDutyCycle() * 100);
		Delay_ms(1000);
	}
}

HAL库代码实现

软件设置

通用定时器-同时测量PWM周期和占空比-HAL库设置.png

tim.c 添加代码

/* USER CODE BEGIN 1 */
/* 返回PWM的周期 ms*/
double Driver_TIM4_GetPWMCycle(void)
{
    // return TIM4->CCR1 / 1000.0;;

    return (__HAL_TIM_GetCompare(&htim4, TIM_CHANNEL_1) + 1) / 1000.0;
}

/* 返回PWM的频率 */
double Driver_TIM4_GetPWMFreq(void)
{
    // return 1000000.0 / TIM4->CCR1;

    return 1000000.0 / (__HAL_TIM_GetCompare(&htim4, TIM_CHANNEL_1) + 1);
}

// 返回占空比
double Driver_TIM4_GetDutyCycle(void)
{
    // return TIM4->CCR2 * 1.0 / TIM4->CCR1;

    return (1 + __HAL_TIM_GetCompare(&htim4, TIM_CHANNEL_2)) * 1.0 / (1 + __HAL_TIM_GetCompare(&htim4, TIM_CHANNEL_1));
}

/* USER CODE END 1 */

main函数代码

int main(void)
{
 
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM4_Init();
  MX_TIM5_Init();
  MX_USART1_UART_Init();
 
    HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_2);

    HAL_TIM_IC_Start(&htim4, TIM_CHANNEL_1);
    HAL_TIM_IC_Start(&htim4, TIM_CHANNEL_2);
    double t, f, dutyCycle;
    while (1)
    {
        t = Driver_TIM4_GetPWMCycle();
        f = Driver_TIM4_GetPWMFreq();
        dutyCycle = Driver_TIM4_GetDutyCycle();
        printf("t=%.4fms, f=%.4fHz, dutyCycle=%.2f%%\r\n", t, f, dutyCycle * 100); // 40%
        HAL_Delay(1000);
    }
}


Comment