深入了解STM32定时器原理,掌握脉宽调制pwm生成方法。
一. 使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
二. 接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。
三. 再接上,采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示
四. 学习 HC-SR04超声波测距模块工作原理,使用 stm32F103 完成一个超声波测距方案(第9周之前选做)。
基于STM32和HC-SR04模块实现超声波测距功能(标准库)
2串口通信与点灯
1)创建新项目
3)配置RCC
配置SYS
配置IO口输出
配置定时器2和定时器3
7)配置中断
开启定时器2和定时器3的中断。
配置USART
配置项目
)代码
启动定时器
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
定时器中断回调函数
二. 接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint32_t time_cnt =0;
static uint32_t time_cnt3 =0;
if(htim->Instance == TIM2)
{
if(++time_cnt >= 400)
{
time_cnt =0;
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);
}
}
if(htim->Instance == TIM3)
{
if(++time_cnt3 >= 1000)
{
time_cnt3 =0;
HAL_UART_Transmit(&huart1,hello,20,100000);
}
}
}
实验结果
二. 接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。
1)新建工程
RCC配置
SYS配置
配置定时器
我们选择定时器3和定时器4两个定时器
定时器3和定时器4我们的设置一样:通道1选择“PWM Generation CH1”,分频系数为71,计数周期为500,其它默认。设置占空比初始值为10
配置中断
开启定时器3和4的中断。生成定时器3和4中断优先级配置代码
设置时钟
代码
uint16_t duty_num3 = 10;
uint16_t duty_num4 = 10;
定义定时器3和4的占空比初始值
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);
开启定时器3和4并输出PWM
HAL_Delay(50);
duty_num3 = duty_num3 + 10;
duty_num4 = duty_num4 + 10;
if(duty_num3 > 500)
{
duty_num3 = 0;
}
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,duty_num3);
if(duty_num4 > 500)
{
duty_num4 = 0;
}
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_1,duty_num4);
在while函数中设置每隔50毫秒,占空比加10,如果超过500(也就是PWM周期),自动变成0。(即灯会从亮倒暗,逐渐变化)定时中断回调函数。
编译烧录,实验结果
引脚
A6–LED
PB6 – PC13
PWM输出波形
再接上,采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示。
1)使用HAL库建立工程
配置RCC
配置SYS
单片机端口配置使用
串口通信配置,如下图所示
定时器定时配置(TIM2),按照图中步骤进行配置即可
PWM波形捕获(TIM1),按照图中步骤进行配置即可
PWM生成配置(TIM3),按照图中步骤进行配置即可
#include “main.h”
#include “tim.h”
#include “usart.h”
#include “gpio.h”
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();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN WHILE */
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);
}
}
// 定时TIM2 定时亮灯的中断函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *tim)
{
if (tim == &htim2)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
}
// 定时输入捕获回调函数 计算占空比和频率
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;
}
}
}