实验介绍
定时器毫不夸张地说就是单片机的灵魂,因此关于定时器的相关知识是必须掌握的。定时器就是用来计数的,当配置好定时器的频率后,以该频率进行计数,我们一般还要配合中断来进行操作,当定时器计数到我们想要的值时,进入中断函数,执行我们写好的操作。具体关于定时器的介绍有很多厉害的博主写的非常的好,在这里不再叙述,本篇只是介绍怎么用而已。本次实验为使用定时器中断实现每100ms八个led以不同的方向来回依次点亮并且。
附:定时器周期计算公式:
T =(arr+1) * (PSC+1) / Tck
其中TCK为时钟频率,PSC为时钟预分频系数,arr为自动重装载值。
例:Tck = 80MHz,PSC = 80 - 1,arr = 10000 - 1,则定时器周期 = 80 * 10000 / 80000000 = 10ms,如果开启中断就是每10ms进入一次中断函数。
STM32CubeMX配置
时钟,时钟树配置不再叙述。
定时器配置:
GPIO配置:
生成工程即可。
代码
执行前的初始代码:
/* USER CODE BEGIN 2 */
// 打开锁存器,并且让8个led熄灭
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
GPIOC->ODR = 0xFFFF;
HAL_TIM_Base_Start_IT(&htim1); // 开启TIM1中断
/* USER CODE END 2 */
中断回调函数(位置在main函数下面):
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// static关键字意思是只在第一次定义这个值,如:0,后续再进入中断不会再重新定义
static uint8_t counter = 0 , i = 0 , dir = 0;
static uint16_t led = 0x0001;
if(htim->Instance == TIM1) // 判断是哪个定时器产生的中断
{
// 当count计为10时,即计够100ms,进入执行操作
counter++;
if(counter == 10)
{
counter = 0; // counter清零,重新计数
GPIOC->ODR = ~(led << (8 + i)); // 寄存器控制led的亮灭
// 每次i的值对应某个led亮,dir为led依次亮的方向
if(dir == 0) // ld1 -> ld8
{
i++;
if(i == 7)
{
dir = 1;
}
}
else // dir = 1 , ld8 -> ld1
{
i--;
if(i == 0)
{
dir = 0;
}
}
}
HAL_TIM_Base_Start_IT(&htim1); // 执行完中断程序后要再次开启中断
}
}
/* USER CODE END 4 */
注:关于中断的函数我们都是写在中断回调函数里,就和原来写串口中断一样。