1.基础
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
2.定时器中断--1秒
控制LED0闪烁,周期为1S
1)基本配置
因为,有Tclk=72MHz,选择arr=9999,psc=7199,则溢出时间为Tout=1S
2)编辑代码
触发中断时系统会调用定义于stm32f1xx_it.c的void TIM2_IRQHandler(void);可以看到该中断服务函数又调用定义于stm32f1xx_hal_tim.c中的HAL_TIM_IRQHandler(&htim2);函数HAL_TIM_IRQHandler(&htim2)又调用回调函数PeriodElapsedCallback(htim)
重定义void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //定时器溢出中断
{
if (htim== &htim2) //确定是否是定时器2触发中断
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
}
}
需要在主函数中启动定时器,用函数HAL_TIM_Base_Start_IT(&htim2);
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
3)分析
3.输出PWM波--呼吸灯
PWM即脉冲宽度调制,在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
1)进行基本配置
2)进行编码
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//启动PWM输出
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
uint16_t pwmVal=0; //PWM占空比
while (1)
{
/* USER CODE END WHILE */
while (pwmVal< 1000)
{
pwmVal++;
__HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, pwmVal); //修改比较值,修改占空比
HAL_Delay(1);
}
while (pwmVal > 0)
{
pwmVal--;
__HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, pwmVal); //修改比较值,修改占空比
HAL_Delay(1);
}
HAL_Delay(200); //完全熄灭后,等待200ms
}
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
3)分析
4.测量PWM信号的频率及占空比
-
在定时计数器的输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
-
每个高级定时器和通用定时器都拥有4个输入捕获通道 可配置为PWMI模式,同时测量频率和占空比
-
可配合主从触发模式,实现硬件全自动测量
1)进行基本配置
time1测量周期和占空比,用其输出捕获通道1和2
time2、time3分别输出不同频率PWM波
2)进行编码
重定义time1的 捕获中断3处理函数,计算频率和占空比
// 捕获值变量
uint32_t IC1Value = 0; // 通道 1 当前捕获值(上升沿)
uint32_t Last_IC1Value = 0; // 通道 1 上一次捕获值(上升沿)
uint32_t IC2Value = 0; // 通道 2 捕获值(下降沿)
uint32_t Period = 0; // 周期时间
uint32_t HighTime = 0; // 高电平时间
uint32_t Frequency = 0; // 计算的 PWM 频率
uint32_t DutyCycle = 0; // 计算的 PWM 占空比
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1) // 确认是 TIM1
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) // 通道 1 上升沿捕获
{
Last_IC1Value = IC1Value; // 保存上一次捕获值
IC1Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // 当前捕获值
// 计算周期
if (IC1Value > Last_IC1Value)
{
Period = IC1Value - Last_IC1Value;
}
else // 计数器溢出处理
{
Period = (htim->Init.Period - Last_IC1Value) + IC1Value + 1;
}
}
else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) // 通道 2 下降沿捕获
{
IC2Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); // 捕获值(下降沿)
// 计算高电平时间
if (IC2Value > IC1Value)
{
HighTime = IC2Value - IC1Value;
}
else // 计数器溢出处理
{
HighTime = (htim->Init.Period - IC1Value) + IC2Value + 1;
}
// 计算频率和占空比
if (Period != 0) // 避免除零
{
Frequency = HAL_RCC_GetPCLK2Freq() / (htim->Init.Prescaler + 1) / Period;
DutyCycle = (HighTime * 100) / Period;
}
}
}
}
主函数主要是设置time2和time3的参数,并启动输出,以及其他time1
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1); //启动PWM输出
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,50); //ARR为100,设置占空比为50%
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); //启动PWM输出
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,600); //ARR为1000,设置占空比为60%
HAL_TIM_Base_Start(&htim1);
HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
sprintf(massage, "Frequency: %lu Hz, Duty Cycle: %lu%%\r\n", Frequency, DutyCycle);
printf("%s",massage);
HAL_Delay(1000); // 每 100 毫秒发送一次
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}