- ✨本文将通过2个工程配置案例分别实现:TIM16通用定时器作PWM输出和延时使用。
STM32CubeMX
工具,选择一款M0内核的芯片,配置一个所需功能的工程,然后从所生成的工程中将所需的目标驱动文件拷贝到Air001工程中使用,这样就快速部署完成了一个所需功能的工程框架。可以避免自己手写配置出bug的可能,通用性还是非常高,甚至PWM输出映射引脚都不需要做修改,当然也不排除STM32CubeMX
生成的代码有bug问题。通过现有的SDK资源,所能提供的公开资料里面,只有定时器1和定时器3的相关内容,结合数据手册上看,定时器16/17作为通用定时器,还是有一些差异。
这里以STM32F030R8T6
为例。
找到工程生成文件目录,驱动文件分别在src
和inc
文件夹内,拷贝对应的tim.c
和tim.h
文件到,Air001工程项目中使用。
回到Air001工程,将tim.c
添加进来,将头文件路径包含进来,需要修改的地方,主要是调整主时钟频率,对应PWM频率和占空比根据个人需求修改即可。
- 这样一个基本的工程框架就搭建好了。
int main(void)
{
uint16_t plusewidth = 5000;//脉冲宽度;f=1000 000/5000=200Hz
uint16_t plusedelay = 500;//脉宽
/* 初始化所有外设,Flash接口,SysTick */
HAL_Init();
/* 系统时钟配置 */
APP_SystemClockConfig();
MX_GPIO_Init();
MX_TIM16_Init();
__HAL_TIM_SET_AUTORELOAD(&htim16, plusewidth - 1); //调整分频系数,可以改变arr以改变频率
__HAL_TIM_SET_COMPARE(&htim16, TIM_CHANNEL_1, plusedelay); //PWM脉冲宽度,修改占空比比较值
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);
// if(HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1) != HAL_OK)
// {
// Error_Handler();
// }
while(1)
{
}
}
链接:https://pan.baidu.com/s/1FboUjQMLb1pQu2coVDlh3Q
提取码:xqpn
STM32CubeMX
工具,配置定时器相关参数:tim.c
中添加如下延时函数内容,并将函数名拷贝到tim.h
中。/* USER CODE BEGIN 1 */
//us级延时函数
//us需要延时的us数
void delay_us(uint16_t us)
{
uint16_t n;
n = us/100;//修正误差值
//设置定时器预分频系数,TIM16时钟为8MHz,分频后时钟为1MHz即1us
//不同CPU的时钟可能不一样,PSC的值=定时器时钟/1MHz -1
//8M的定时器设置PSC为8-1
TIM16->PSC = (8 -1);
//设置自动重装载值,定时器计数器的值自增到ARR时,会产生更新事件,ARR的值就是需要延时的时间
TIM16->ARR = us - 2*n;
//重新初始化定时器计数器并生成寄存器更新事件,确保预分频值被采用,此时定时器将采用刚刚写入的预分频值,如果此处不更新,那么定时器需要等待下次更新事件的到来才会重新加载预分频值
TIM16->EGR |= (1<<0);
//清除更新标志位,该位在发生更新事件时通过硬件置 1,但需要通过软件清零
TIM16->SR = 0;
//CR1的bit3(OPM)置一,计数器在发生下一更新事件时停止计数,单脉冲模式
TIM16->CR1 |= (1<<3);
//CR1的bit0(CEN)置一,启动定时器开始计数
TIM16->CR1 |= (1<<0);
//等待更新事件到来,计数器的值自增到自动重装载寄存器的时候,会产生更新事件,此时延时时间已到
while((TIM16->SR & 0x01)==0);
//清除更新标志位,该位在发生更新事件时通过硬件置 1,但需要通过软件清零
TIM16->SR &= ~(1<<0);
}
//ms级延时函数
//最大延时时间 65535ms
void delay_ms(uint16_t ms)
{
//设置定时器预分频系数,TIM16时钟为8MHz,分频后时钟为1KHz即1ms
//不同CPU的时钟可能不一样
TIM16->PSC = (8000-1);//8000 000/8000=1KHz
//设置自动重装载值,定时器计数器的值自增到ARR时,会产生更新事件,ARR的值就是需要延时的时间的一半
TIM16->ARR = ms;
//重新初始化定时器计数器并生成寄存器更新事件,确保预分频值被采用,此时定时器将采用刚刚写入的预分频值,如果此处不更新,那么定时器需要等待下次更新事件的到来才会重新加载预分频值
TIM16->EGR |= (1<<0);
//清除更新标志位,该位在发生更新事件时通过硬件置 1,但需要通过软件清零
TIM16->SR = 0;
//CR1的bit3(OPM)置一,计数器在发生下一更新事件时停止计数,单脉冲模式
TIM16->CR1 |= (1<<3);
//CR1的bit0(CEN)置一,启动定时器开始计数
TIM16->CR1 |= (1<<0);
//等待更新事件到来,计数器的值自增到自动重装载寄存器的时候,会产生更新事件,此时延时时间已到
while((TIM16->SR & 0x01)==0);
//清除更新标志位,该位在发生更新事件时通过硬件置 1,但需要通过软件清零
TIM16->SR &= ~(1<<0);
}
/* USER CODE END 1 */
int main(void)
{
/* 初始化所有外设,Flash接口,SysTick */
HAL_Init();
/* 初始化GPIO */
MX_GPIO_Init();
/* 系统时钟配置 */
APP_SystemClockConfig();
MX_TIM16_Init();
while(1)
{
/* LED翻转 */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
delay_us(500);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
delay_ms(250); /* 延时250ms */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
delay_ms(250); /* 延时250ms */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
delay_us(500);
}
}
链接:https://pan.baidu.com/s/132W6L3jC1196mrcDzrC3qg
提取码:onsu
✨按照上述方法和实现原理,对于Air001 定时器17,配置相同功能的方法一样,这里不再赘述。