一、定时器简介
1. 功能简介
三种定时器功能如下:
STM32 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:
1. 16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。 |
---|
2. 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~ 65535 之间的任意数值。 |
3. 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为: A.输入捕获 B.输出比较 C.PWM 生成(边缘或中间对齐模式) D.单脉冲模式输出 |
4. 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外 一个定时器)的同步电路。 |
5. 如下事件发生时产生中断/DMA: A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) C.输入捕获 D.输出比较 E.支持针对定位的增量(正交)编码器和霍尔传感器电路 F.触发输入作为外部时钟或者按周期的电流管理 |
2. 计数器模式
-
向上计数模式
在向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始
计数并且产生一个计数器溢出事件。
-
向下计数模式
在向下模式中,计数器从自动装入的值(TIMx_ARR计数器的值)开始向下计数到0,然后从自动
装入的值重新开始并且产生一个计数器向下溢出事件。
-
中央对齐计数模式
在中央对齐模式,计数器从0开始计数到自动加载的值(TIMx_ARR寄存器)−1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器下溢事件;然后再从0开始重新计数。
3. 时基单元
可编程通用定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数器可
以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。 计数器、自动装载寄存器和预分频器寄存器可以由软件读写,在计数器运行时仍可以读写。
时基单元包含:
计数器寄存器(TIMx_CNT) | 向上计数、向下计数或者中心对齐计数 |
---|---|
预分频器寄存器 (TIMx_PSC) | 可将时钟频率按1到65535之间的任意值进行分频,可在运行时改变其设置值; |
自动装载寄存器 (TIMx_ARR) | 如果TIMx_CR1寄存器中的ARPE位为0,ARR寄存器的内容将直接写入影子寄存器;如果ARPE为1,ARR寄存器的那日同将在每次的更新时间UEV发生时,传送到影子寄存器; 如果TIM1_CR1中的UDIS位为0,当计数器产生溢出条件时,产生更新事件。 |
定时器频率=时钟频率/(PSC+1)(ARR+1)
4. 定时器时钟源
1)内部时钟(CK_INT) |
---|
2)外部时钟模式 1:外部输入脚(TIx) |
3)外部时钟模式 2:外部触发输入(ETR) |
4)内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)。 |
二、PWM简介
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用 微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。
三、任务要求
一、使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
二、接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。
三、再接上,采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示。
四、STM32CubeMX配置
1. 选择stm32f03c8t6芯片
编辑
2. 配置RCC
3. 配置sys
4. 配置UART1
5. 配置DMA
6. 配置TIM2&&TIM3
7. 配置时钟
8. 配置中断
9. 工程输出配置
五、程序编写
1. TIM2程序编写
中断函数编写:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)//判断是否为TIM2触发的中断
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);//反转PA1的电平
}
}
主函数添加中断使能:
HAL_TIM_Base_Start_IT(&htim2);
2. TIM3程序编写
修改占空比编写:
while (1)
{
while(duty<=1000)//大于700的效果和700一样,设置为700效果更好
{
duty++;
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
Duty=(float)duty;
Duty/=10;
printf("%s",str1);
printf("%f",Duty);
printf("%s\n",str2);
HAL_Delay(1);
}
while(duty>=300)
{
duty--;
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
Duty=(float)duty;
Duty/=10;
printf("%s",str1);
printf("%f",Duty);
printf("%s\n",str2);
HAL_Delay(1);
}
}
PWM输出使能:
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
mian.c函数:
int main(void)
{
/* USER CODE BEGIN 1 */
int duty=0;
float Duty;
char str1[6]="Duty: ";
char str2[]="%";
/* 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_DMA_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); //??TIM1?PWM Channel1 ??
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
while(duty<=1000)//大于700的效果和700一样,设置为700效果更好
{
duty++;
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
Duty=(float)duty;
Duty/=10;
printf("%s",str1);
printf("%f",Duty);
printf("%s\n",str2);
HAL_Delay(1);
}
while(duty>=300)
{
duty--;
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
Duty=(float)duty;
Duty/=10;
printf("%s",str1);
printf("%f",Duty);
printf("%s\n",str2);
HAL_Delay(1);
}
}
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
六、实物效果和仿真效果
1. 实物效果
串口调试:
效果:
如上图GIF效果所示,具有呼吸灯的效果
2. 仿真效果
环境配置:
可以看出,二者周期都是1s,下面的波形占空比先从大到小,再从小到大,波形十分明显。
七、总结与参考
1. 通过次实验,理解和掌握了定时器的原理,以及如何通过HAL库使用定时器和通过定时器输出PWM。
2. 在进行呼吸灯效果测试时,发现当PWM周期很大时,呼吸灯效果十分不明显,可以从PWM波原理上看,修改的只是高电平的占比,那么如果周期很大,即使占空比怎么修改,人眼中还是会看出来亮灭的过程,当PWM频率提高时,人眼就无法识别出低电平的间隙,从而看出来是从亮到灭的过程