基于STM32f103rct6标准库配置定时器中断

         本届实验是基于江科协的定时器中断配置实验改编而来。中断定时器与外部中断的最大的区别在于定时器中断是可以在设定的时间内进行一次中断而外部中断是需要去触发一个外部中断触发条件如对应的EXTI0需要低电平触发,那么要触发它就需要将它对应的引脚置于低电平才能触发。

具体如下图所示:

特别提醒:

        只有在定时器用于基础的计时的功能单纯到时间去执行中断事件的时候才不需要使能引脚,而如果需要该定时器中断具有输出比较与输入捕获的功能的话,才需要使能对应的定时器通道引脚。

一、配置步骤:

(1)定时器的初始化函数

(这里以TIM2为例)

备注:STM32F103系列的默认的系统时钟为72MHZ,挂载在APB1上的TIM2的定时器时钟源的默认频率为72MHZ

开启时钟;

配置时钟源;

时基单元初始化;

从上往下的参数依次是

系统时钟分频、计数模式、PSC预分频系数的值、ARR自动重装载值

中断输出配置;

开启定时器的更新中断;

中断优先级NVIC分组NVIC配置;;

定时器使能;

(2)在主函数里面编写定时器中断服务函数:

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		//事件//										
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}

二、示例: 

Timer.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:定时中断初始化
  * 参    数:无
  * 返 回 值:无
  */
void Timer_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;				//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	
	
	/*中断输出配置*/
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位
																//TIM_TimeBaseInit函数末尾,手动产生了更新事件
																//若不清除此标志位,则开启中断后,会立刻进入一次中断
																//如果不介意此问题,则不清除此标志位也可
	
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}

Timer.h

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num;			//定义在定时器中断里自增的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Timer_Init();		//定时中断初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Num:");			//1行1列显示字符串Num:
	
	while (1)
	{
		OLED_ShowNum(1, 5, Num, 5);			//不断刷新显示Num变量
	}
}

/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		Num ++;												//Num变量自增,用于测试定时中断
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}

解决: 复位后从1开始计数

        原因是,中断函数在初始化之后立刻就执行了,原因就出在定时器配置函数

跳转到定义到最后可以看到

此处含义为: 生成一个“更新事件”以重新加载 Prescaler 和 Repetition 计数器值,立刻。说明从这里开始就进入了一次中断(原因:预分频器是有一个缓冲寄存器的,写值件只有在更新事件时,才会起作用,为了让值立刻起作用,就在这里用上述的语句实现手动生成一个更新事件,这样预分频器的值就有效了,但同时,它的副作用就是,更新事件和更新中断是同时发生的,更新中断会置更新中断标志位,当初始化完后,更新中断就会立刻进入),所以在复位后开始计数的变量num的值是从1开始的。

解决办法为:在开启定时器前初始化之后加上下面这段就可以了

### 使用STM32CubeMX配置STM32F103RCT6定时器 #### 配置环境准备 为了成功配置STM32F103RCT6定时器,在始之前需确保已安装好STM32CubeMX软件,并下载对应于目标芯片的数据包。 #### 定时器基本设置 打STM32CubeMX,创建新项目并选择对应的MCU型号即STM32F103RCT6。进入Clock Configuration页面调整系统时钟频率至所需值[^2]。 #### TIM6定时器用于DAC输出 对于使用TIM6配合DAC通道2输出正弦波的情况,首先应在Pinout & Configuration界面找到TIM6定时器,将其模式设为Timer Output Compare。接着设定Prescaler预分频系数以及Period自动重装载周期数值来决定计数频率与溢出间隔。此案例中,这些参数的选择应能使得定时器每达到一次满量程就触发DMA传输下一个样本给DAC模块[^1]。 ```c __HAL_TIM_SET_COUNTER(&htim6, 0); // CNT清零 HAL_TIM_Base_Start(&htim6); // 启动定时器6 ``` 上述代码片段展示了如何初始化和启动TIM6定时器以便它能够按照预定的时间间隔工作。 #### 中断服务程序定义 当涉及到更复杂的操作比如响应特定事件或执行周期性的任务时,则可能需要用到中断机制。可以在工程文件`tim.c`里添加自定义的中断回调函数来进行处理: ```c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == htim2.Instance) { static int16_t tim_delay; if (++tim_delay >= 500) { // 延迟计算逻辑 tim_delay = 0; HAL_GPIO_TogglePin(LED_1_GPIO_Port, LED_1_Pin); } } if (htim->Instance == htim6.Instance) { static int16_t tim2_delay; if (++tim2_delay >= 200) { tim2_delay = 0; HAL_GPIO_TogglePin(LED_2_GPIO_Port, LED_2_Pin); } } } ``` 这段代码实现了两个不同实例下的延时切换LED状态的功能,同时也说明了如何区分多个定时器共享同一个ISR入口点的方法[^3]。 #### PWM功能实现 如果目的是生成PWM信号,那么可以参照如下做法:在Main Loop部分编写循环改变比较寄存器中的占空比从而形成连续变化的脉宽调制波形[^4]。 ```c while (PluseWidch < 999) { PluseWidch++; __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, PluseWidch); HAL_Delay(1); } while (PluseWidth) { PluseWidth--; __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, PluseWidth); HAL_Delay(1); } ``` 以上就是关于如何利用STM32CubeMX工具对STM32F103RCT6微控制器上的定时器进行配置的一些指导信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值