文章目录
一、STM32定时器原理
1、基本概念
定时器是一种计时的工具,它具有延时、频率测量、PWM输出、电机控制及编码接口等功能.STM32F103微控制器内部集成了多个可编程定时器,可以分为基本定时器(TIM6和TIM7)、通用定时器(TIM2~TIM5)和高级定时器(TIM1、TIM8)3种类型。从功能上看,基本定时器的功能是通用定时器的子集,而通用定时器的功能又是高级定时器的一个子集。
2、工作原理
时钟源选择:首先需要选择定时器的时钟源。STM32定时器可以选择内部时钟源(如内部RC振荡器)或外部时钟源(如外部晶体振荡器)作为时钟输入。
预分频器设置:定时器的时钟源经过预分频器分频后作为计数器的时钟输入。预分频器可以将时钟源的频率降低,以适应不同的应用需求。
计数器配置:配置计数器的计数模式(向上计数、向下计数、向上/向下计数)、计数方向(递增或递减)以及计数器的初始值。
中断和事件配置:可以配置定时器的中断和事件,以便在计数器达到特定值或特定条件满足时触发中断或事件。
定时器操作:启动定时器后,计数器开始根据时钟源的输入递增或递减。可以通过读取计数器的值来获取定时器的当前计数值。
3、应用
STM32定时器广泛应用于各种领域,例如工业自动化、智能家居、医疗设备、汽车电子等。其中,常见的应用包括PWM波控制、脉冲计数、定时中断、输入捕获等。通过使用STM32定时器,可以实现对各种设备的精确控制和调节,提高系统的稳定性和可靠性
二、用定时器计数方式,控制LED以2s的频率周期性地亮-灭
1、创建工程
2.
3.
4.
5.
6.
7.
8.
2、代码修改
1.打开定时器
HAL_TIM_Base_Start_IT(&htim2); //打开定时器TIM2
2.mian.c添加定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint32_t time_cnt =0; //记录中断次数
if(htim->Instance == TIM2)
{
if(++time_cnt >= 40) //判断是否已经达到两秒
{
time_cnt =0; //点灯用的中断次数归零
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_7); //改变LED所接引脚的电平
}
}
}
3、烧录执行结果
用定时器计数方式,控制LED以2s的频率周期性地亮-灭
三、采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒
1、工程创建
以下为变动处
1.输出管脚为A1
2.
3.
2、代码编写
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
int pwm = 0;
2.主函数while循环中添加
while(pwm<500)
{
pwm = pwm + 10;
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,pwm);
HAL_Delay(20);//延时20毫秒
}
while(pwm>0)
{
pwm = pwm - 10;
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,pwm);
HAL_Delay(20);
}
3、烧录执行结果
呼吸灯
4、观察PWM输出波形
2.
3.
4.结果
PWM波形图
四、采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示
1、工程创建
2、代码编写
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "string.h"
#include "stdio.h"
void SystemClock_Config(void);
uint8_t i = 0;
float Duty = 0;
float Frequency = 0;
uint16_t Cap_val1 = 0;
uint16_t Cap_val2 = 0;
int main(void)
{
HAL_Init();
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
printf("串口通信测试\r\n");
HAL_TIM_Base_Start_IT(&htim2); // 使能定时器及其更新中断
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); // 使能定时器及其PWM输出
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1); // 使能定时器及其输入捕获
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2); // 使能定时器及其输入捕获
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 10); // 设置一个PWM波形进行测量
while (1)
{
// 串口发送 频率 占空比
printf("Cap_val1 is :%d , Cap_val2 is : %d \r\n", Cap_val1, Cap_val2);
printf("Duty is :%0.2f%% Frequency is : %0.2f ms\r\n", Duty, Frequency);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
// 定时输入捕获回调函数 计算占空比和频率
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
Cap_val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
}
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
Cap_val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
Duty = 100 - (float)Cap_val2 / (float)Cap_val1 * 100;
Frequency = 0.001 * Cap_val1;
}
}
}
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif /* USE_FULL_ASSERT */
3、烧录执行结果
参考:
1.https://blog.youkuaiyun.com/liuwei1015/article/details/134234729
2.https://blog.youkuaiyun.com/qq_64120195/article/details/134222208
3.https://blog.youkuaiyun.com/m0_63650001/article/details/134169585