STM32---TIM

一.定时器简介

定时器功能:定时,输出比较,输入捕获,互补输出

定时器分类:基本定时器,通用定时器,高级定时器

二.基本定时器

1.基本定时器16位,向上计数,只有TIM6和TIM7,没有外部GPIO,只能用来定时。2~7定时器在APB1上。

 预分频器和自动重装载寄存器都有影子寄存器。影子寄存器起到一个缓冲的作用。用户值-》寄存器-》影子寄存器-》起作用。一般不需要使用。数据直接写到寄存器之后起作用。

2.定时时间的计算:

如何实现5ms的定时?(200hz)

如果使用高级定时器,挂载在APB2上,预分频为1,时钟为72MHz。设置为向上计数,初值为0。一个中断周期为5ms。

ARR寄存器值0-65535,预分频值0-65535

PSC决定每一次计数多少时间

ARR一个周期计数多少次

(ARR+1)*(PSC+1)/72M=一个周期的时间

那么,5*72000=360000,ARR=PSC=600-1=599;

3.初始化时基结构体

  • Prescaler  预分频
  • counterMode计数模式,在基本计时器只能向上计数。
  • Period:ARR值
  • ClockDivision:外部输入时钟分频因子。由于基本定时器没有外部GPIO,所以没有此项.高级定时器需要设置此项,与死区时间相关。
  • RepetitionCounter:重复计数器。当计数到ARR值时,不产生中断,清零重新计数,RepetitionCounter值+1直到它的值等于预先配置好的值后产生中断。这种做法会延长计时时间。
void TIM1_Config(uint16_t Period,uint16_t Prescaler)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	NVIC_InitTypeDef        NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);	
	
	TIM_TimeBaseStructure.TIM_Prescaler = Prescaler; 			//时钟预分频
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseStructure.TIM_Period = Period;			        //自动重装值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;	    //时钟分频1
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;			
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
	TIM_ClearFlag(TIM1,TIM_FLAG_Update);
	TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);  					
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;	
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占优先级2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  	    //响应优先级1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	            
	NVIC_Init(&NVIC_InitStructure);	
}

三.高级定时器TIM1,TIM8

1.高级定时器:16位,可以上下两个方向计数。有一个重复计数器RCR。有4个GPIO,其中通道1~3还有互补输出GPIO。时钟来自APB2(72M)。

定时器的GPIO选用时尽量不要选择复用接口,防止干扰。

2.时钟源

内部时钟源;

外部时钟模式1:来自外部GPIO。

外部时钟模式2:  来自ETR引脚。

内部触发输入:实现定时器同步或者级联。高级定时器和通用定时器的内部连接在一起。

3.输入捕获

输入捕获可以对输入信号的上升沿,下降沿或者双边沿进行捕获,常用于测量输入信号的脉宽和PWM输入信号的频率和占空比。

输入通道TIx用来输入信号。捕获通道ICx是用来捕获输入信号的通道。TIx经过滤波和边沿检测之后的TIFP1和TIFP2可以进入捕获通道IC1和IC2。这其实就是PWM输入捕获。只有一路TIx却占用了两个IC。当需要测量输入信号的脉宽时,只需要用一个捕获通道就行了。

4.输出比较

CCR决定占空比,ARR决定周期。当CNT计数到CCR值时,电平跳变;当CNT计数到ARR值时,计数器清零,电平翻转。

带死区插入的半桥驱动电路将PWM电信号放大后才能驱动电机。为什么要加入死区呢?MOS管导通时,电机正转;截至时,电机反转。由于MOS工艺原因,转换时,无法顺畅承接。因此设置死区时间来承接过渡这段时间。死区时间的设置要看控制的元件,比如电机。可以通过示波器,看输出的方波的死区时间,然后设置死区时间。

5.输出比较模式--PWM输出模式

PWM输出模式,对外输出脉宽可调的方波信号。有PWM1和PWM2两种模式。常用PWM1的递增模式。

四.写代码

1.PWM互补输出(带死区时间和刹车控制)

互补输出需要2个GPIO(一个为正定时器通道,一个是互补TIM通道),刹车控制需要1个GPIO。死区时间可以通过软件设置,不需要设置GPIO。STM32上I/O上太多引脚有复用,PWM的输出使用专用的小板子比较好。一般情况下,驱动小型电机用10KHz。

初始化GPIO,TimeBaseStructure,TIM_OC输出比较,TIM_BDTR死区和刹车结构体。

GPIO有三个,设置为复用推挽输出,BKIN,正通道和互补通道。BKIN拉低。在刹车功能启用之后,BKIN接高电平会触发刹车(刹车设置为高电平触发),输出信号被禁止,输出通道和互补通道输出空闲电平。

可以看出,控制PWM输出信号控制电机转速,是控制这两个GPIO的电平。但是电机不需要互补通道的电平,所以1个电机控制只要一个正通道输出PWM就足够了。

 时基结构体初始化(省略);

 

 输出四路PWM,怎么写代码?看野火四路输出的程序,可参考。

2.输入捕获,测量脉宽

TIM_IC输入捕获结构体,设置捕获通道,捕获边沿,输入通道和捕获通道的映射关系,分频,滤波。开启更新和捕获中断。写中断服务函数,NVIC。在中断服务函数里判断是哪种中断,再具体执行对应的任务。

当设置的捕获时间大于CNT的计数范围时,CNT会先产生更新中断,因此在触发中断时,要判断是否是更新中断,是更新中断的话,要计数更新中断次数。

定时器设置成上升沿捕获,产生中断,CNT计数清零,中断触发改为下降沿,第一次下降沿中断。第二次捕获到下降沿,获取CCR的值。

如果CCR的值等于1,则判断是否CNT有溢出,计算高电平时间的计数器值

3.输入捕获,测量PWM信号的频率和占空比

捕获用高级定时器T1的通道1,输出信号用通用定时器的T3的通道1.同一个定时器不能同时用于输入和输出。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 STM32-HAL 库读取编码器时,如果出现读取到负数的情况,可能会导致程序卡死的问题。这是因为 HAL 库默认使用的是 32 位定时器计数器,而编码器的计数器是一个 16 位的有符号整型,当计数器值达到 32767(0x7FFF)时,会变为负数,这会导致 HAL 库出现异常。 为了解决这个问题,可以使用以下两种方法之一: 1. 使用 16 位定时器计数器 可以通过修改定时器的初始化配置,将其设置为 16 位计数器模式。这样可以保证计数器值始终为 16 位有符号整型,不会出现负数的情况。例如,对于 TIM2 定时器,可以使用以下代码进行初始化: ```c TIM_HandleTypeDef htim2; // ... htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 65535; // 设置为 16 位计数器模式 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { // 初始化失败 } if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) { // 启动失败 } ``` 2. 处理负数值 如果无法使用 16 位定时器计数器,可以在程序中对读取到的负数值进行处理。例如,可以将计数器值加上一个足够大的值,使其变为正数。具体的处理方法可以根据实际情况进行调整。以下是一个示例代码: ```c int16_t count = 0; uint32_t offset = 0x10000; // 偏移量为 65536 while (1) { count = __HAL_TIM_GET_COUNTER(&htim2); if (count < 0) { count += offset; } // ... } ``` 以上两种方法都可以解决读取编码器时出现负数导致程序卡死的问题,具体选择哪种方法应根据实际情况进行判断。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值