TIM简介
TIM外设,是用来产生定时事件的。在内部构造上 如下图。
但关键部件只有 [输入时钟脉冲]->[计数器CNT]->[捕获比较寄存器]
常用的寄存器
- Prescaler(PSC)预分频寄存器:对输入到TIM外设时钟频率进行分频,比如该TIM挂在在APB2上,APB2的时钟频率为72MHz,如果设置PSC寄存器值为72-1,那么那么进入TIM外设的内部的时钟频率为1MHz,CNT寄存器也就是对1这1MHz的脉冲进行计数。该寄存器可通过
__HAL_TIM_SET_PRESCALER(__HANDLE__, __PRESC__)
进行修改 - Counter(CNT)寄存器: 用来计数当前收到的脉冲数。使用
__HAL_TIM_SET_COUNTER(__HANDLE__, __COUNTER__)
修改 - CCR寄存器(capture/compare register):在输入捕获,和输出比较中有不同的作用。以PWM波生成为例,该寄存器可用来设置PWM波的占空比。使用
__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
来进行设置 - ARR寄存器(AutoReload Register): 在本例中,当CNT寄存器中的值达到ARR中的值时,自动将CNT值清零。也就是用来限制CNT的计数范围。使用
__HAL_TIM_SET_AUTORELOAD(__HANDLE__, __AUTORELOAD__)
进行设置。
从下图可以看出TIM生成PWM的工作过程。TIM最核心的就是CNT和ARR了,CNT不断的计数,计的是进入TIM的脉冲数,也就是经过PSC分频后的时钟脉冲数;CNT一旦到达ARR的值就会归零,再次开始计数。这就是基本TIM的作用了。如果TIM的某个通道还启用PWM功能,那么就会有CCR寄存器被派上用场,时刻监视着CNT值,根据CNT值和CCR值的比较,更改通道的对应引脚的电平状态。
STM32CubeMX配置
对于本次例题。我们直接将CCR值设置为ARR的一半,也就是PWM的占空比50%
将LED灯所在引脚的模式设置为TIM。
配置该TIM 通道为PWM波输出方式。只需要启动Activated即可(左侧TIM16图标变成绿色),主要的参数可以在程序中通过上述的代码设置。
代码编写
double LED_freq=1;//全局变量,用于保存当前LED闪烁频率值
void LED_blink(double freq)
{
uint16_t freq_arr=10e3/freq;
__HAL_TIM_SET_PRESCALER(&htim1, 7200 - 1) //将进入TIM的频率设为10KHz
__HAL_TIM_SET_AUTORELOAD(&htim1,freq_arr);
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,freq_arr/2);
htim1.Instance->EGR=TIM_EGR_UG; //立即使配置生效
}
#define KEY_UP 1
#define KEY_DOWN 2
#define KEY_NONE 0
uint8_t read_button()
{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==0||HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
{
HAL_Delay(20);//延时消抖
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
{
HAL_Delay(500);
return KEY_UP;
}
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==0)
{
HAL_Delay(500);
return KEY_DOWN;
}
}
else
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==1&&HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==1)
return KEY_NONE;
return KEY_NONE;
}
主循环
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//启用TIM定时器
LED_blink(1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
switch(read_button())
{
case KEY_UP:
++LED_freq;
LED_blink(LED_freq);
printf("Freq=%.2f\r\n",LED_freq);
break;
case KEY_DOWN:
--LED_freq;
LED_blink(LED_freq);
printf("Freq=%.2f\r\n",LED_freq);
break;
default:
break;
}
项目文件下载地址