基本&高级定时器

stm32g431rb单片机中,共10个定时器

  • 2个基本定时器(TIM6和TIM7)
  • 3个通用定时器(TIM2~TIM4):全功能定时器
  • 3个通用定时器(TIM15~TIM17):只有1个或者2个通道
  • 2个高级控制寄存器(TIM1和TIM8) 

定时器功能比较

功能:

  • ADC和DAC开始转换触发
  • 输入捕获:脉冲计数、上升沿或下降沿时间检测、PWM输入检测
  • 输出比较:脉冲输出、电机控制
  •  脉冲宽度调节PWM:电压输出控制、直流减速电机控制、直流无刷电机控制
  • 单脉冲模式输出
  • 编码接口、霍尔传感器接口

定时器的计数方式:

 中心对齐模式分为3种子模式:

模式1:下溢事件产生更新事件

模式2:上溢事件产生更新事件

模式3:上溢和下溢都产生更新事件

基本定时器基本原理:

计数过程:

每来一个CK_CNT脉冲,TIMx_CNT值+1,当TIMx_CNT值与TIMx_ARR设定的值相等时就自动生成更新事件(也可以产生DMA请求、中断信号或触发DAC同步电路),并且TIMx_CNT自动清零,然后重新开始计数,不断重复上述过程。因此,我们只要设定TIMx_PSC和TIMx_ARR这两个寄存器的值就可以控制事件生成时间,对应的就是程序中定时器预分频设置和定时周期。

以定时器6为例,用定时器以中断方式控制LED灯1S闪烁

 

 然后就是编程

按照这个方式找到中断回调函数,也就是在main.c里重写虚函数

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM6)
	{
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_All);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	}
//	HAL_TIM_Base_Start_IT(&htim6);
}
/* USER CODE END 0 */

 当然最后还要在main函数里头启动定时器 



高级定时器

也就是要把这张图给看透了

 先从上半部分看起,大致分为3大块(时钟源,控制器,时基单元)

  

Slave controller mode:定时器从模式除了用于接收内部时钟外的信号,该信号用于完成如下控制:

  1. 复位Reset模式:使用内部时钟作为时钟源,TI1/2外部有效信号复位计数器。eg:CH1触发输入上升沿有效时,计数器复位到默认值0 .
  2. 门控enable模式:使用内部时钟作为时钟源,根据TI1/2外部电平情况运行计数。eg:CH1输入为高电平时,定时器正常计数;CH1输入为低电平时,停止计数。
  3. 触发enable模式:使用内部时钟作为触发源,TI1/2外部触发启动定时器。eg:CH1触发输入上升沿时,定时器启动运行。
  4. 外部时钟模式2+触发模式:使用外部ETR作为时钟源,配合其它(1,2,3)的触发启动模式。

外部时钟输入模式1

外部时钟输入模式2

 其它定时器输出的触发信号

作用:

  • 使用一个定时器作为另一个定时器的预分频器
  • 使用一个定时器使能另一个定时器
  • 使用一个定时器去启动另一个定时器
  • 使用一个外部触发同步的启动2个定时器 

下半张图,分为两部分

可以看出有重叠的部分,所以同一时刻,捕获和比较只能进行一个。

输入捕获原理

模式1:普通输入捕获模式

模式2:PWM输入捕获模式

模式1:

输入捕获两大核心功能:

1、捕获定时器的数值

2、产生中断,类似于外中断(上升沿产生中断)

模式2:

 pwm输入模式时序图

1.PWM信号由TI1进入,配置TI1FP1为触发信号,上升沿捕获。

2.当上升沿的时候IC1IC2同时捕获,计数器CNT清零

3.到了下降沿的时候,IC2捕获,此时计数器CNT的值被锁存到捕获寄存器CCR2中。

4.到了下一个上升沿的时候,IC1捕获,计数器CNT的值被锁存到捕获寄存器CCR1中。

5.其中CCR2测量的是脉宽,CCR1测量的是周期。 

输出比较

output control 控制模式输出(由OC1M[3:0]第三位控制  0000 ~ 0111) 

  • 1:(冻结模式)冻结模式。定时器作为普通定时器使用,不使用输出比较功能。
  • 2/3:(比较输出模式1)匹配时输出有效/无效电平模式。如递增计数器,比较寄存器内部数值提前设定好,当计数器相等或者大于比较值时,匹配,产生/不产生有效信号输出。当计数器值小于比较值时,不产生/产生有效信号输出。
  • 4:(比较输出模式2)电平翻转模式。当匹配时,引脚状态翻转。步进电机控制常用的模式。
  • 5/6:(强制输出模式)强置为无效/有效电平模式。不管比较寄存器和计数器数值,强制设置比较寄存器的输出。
  • 7/8:(PWM模式) PWM1和PWM2模式。(重点)

输出模式1~6:

PWM模式:

1、产生参考电平

pwm模式可以产生一个由TIMx_ARR寄存器确定频率(周期)、由TIMx_CRR寄存器确定占空比的pwm信号。

stm32的pwm模式有两种,根据TIMx_CRR寄存器中的OCxM位来确定

  • 110:PWM模式1,在递增计数时,TIMx_CNT<TIMx_CCRxOCxREF为有效电平,否则为无效电平;在递减计数时,TIMx_CNT>TIMx_CCRxOCxREF为无效电平,否则为有效电平。
  • 111:PWM模式2,在递增计数时,TIMx_CNT<TIMx_CCRxOCxREF为无效电平,否则为有效电平; 在递减计数时,TIMx_CNT>TIMx_CCRxOCxREF为有效电平,否则为无效电平。

2、产生死区和最终输出

实际应用:电机调速,使用数字信号达到一个模拟信号的效果。

每个桥的上半桥臂和下半桥臂是是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制极时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有及时关断,造成功率元件烧毁。死区就是在上半桥关断后,延迟一段时间再打开下半桥或在下半桥关断后,延迟一段时间再打开上半桥,从而避免功率元件烧毁。这段延迟时间就是死区。

带死区的互补输出


开始敲代码

然后咱们板子上有两个pwm输入通道 

在手册上找到这两个引脚所对应的定时器功能

编程实现测量这两路的PWM频率和占空比 

cubemx关于定时器的配置

然后打开MDK开始敲代码了

首先还是得找到定时器输入捕获的中断回显函数,然后在main.c里面重写

参考代码:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM3)  //PB4
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			pwm1_period = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1)+1;
			pwm1_duty = (float)pwm1_high/pwm1_period;
		}
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			pwm1_high = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_2)+1;
		}
	}
	if(htim->Instance == TIM2)  //PA15
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			pwm2_period = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1)+1;
			pwm2_duty = (float)pwm2_high/pwm2_period;
		}
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			pwm2_high = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2)+1;
		}
	}
}

void LCD_Proc()
{
	if(uwTick - lcd_uwTick < 100)
		return;
	lcd_uwTick = uwTick;
	LCD_DisplayStringLine(Line0,(uint8_t *)"--------------------");
	LCD_DisplayStringLine(Line1,(uint8_t *)"---test pwm_duty----");
	sprintf((char *)lcd_string,"pwm1_freq: %06d",1000000/pwm1_period);
	LCD_DisplayStringLine(Line2,lcd_string);
	sprintf((char *)lcd_string,"pwm2_freq: %06d",1000000/pwm2_period);
	LCD_DisplayStringLine(Line3,lcd_string);
	sprintf((char *)lcd_string,"pwm1_period: %06d",pwm1_period);
	LCD_DisplayStringLine(Line4,lcd_string);
	sprintf((char *)lcd_string,"pwm2_period: %06d",pwm2_period);
	LCD_DisplayStringLine(Line5,lcd_string);
	sprintf((char *)lcd_string,"pwm1_high: %06d",pwm1_high);
	LCD_DisplayStringLine(Line6,lcd_string);
	sprintf((char *)lcd_string,"pwm2_high: %06d",pwm2_high);
	LCD_DisplayStringLine(Line7,lcd_string);
	sprintf((char *)lcd_string,"pwm1_duty: %4.2f%%",pwm1_duty*100);
	LCD_DisplayStringLine(Line8,lcd_string);
	sprintf((char *)lcd_string,"pwm2_duty: %4.2f%%",pwm2_duty*100);
	LCD_DisplayStringLine(Line9,lcd_string);
}
/* USER CODE END 0 */

 写完之后肯定要打开定时器(在main()里面启动相关定时器和定时器通道输入捕获通道)

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	/* 启动定时器*/
	HAL_TIM_Base_Start_IT(&htim3);
	/* 启动定时器通道输入捕获并开启中断*/
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
	/* 启动定时器*/
	HAL_TIM_Base_Start_IT(&htim2);
	/* 启动定时器通道输入捕获并开启中断*/
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
	
	LCD_Init();
	LCD_Clear(Blue);
	LCD_SetBackColor(Blue);
	LCD_SetTextColor(White);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		LCD_Proc();
  }
  /* USER CODE END 3 */
}

这些函数在.h文件中找比较方便

然后就是输出比较了

编程用一个定时器生成两路占空比不等方波或PWM波

 

输出方波

cubemx配置

中断给打开

这里的输出速度让它高一点

咱这也要注意一下引脚的配置,不要忽略了。。

然后就可以生成代码了。

找到中断回显函数,在main.c里重写

//方波输出中断
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM4)
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			__HAL_TIM_SET_COMPARE(htim,TIM_CHANNEL_1,(__HAL_TIM_GetCounter(htim) + 100));  //5kHZ
		}
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			__HAL_TIM_SET_COMPARE(htim,TIM_CHANNEL_2,(__HAL_TIM_GetCounter(htim) + 500));  //1kHZ
		}
	}
}

 然后还要在main函数里头启动比较

/* 启动CH1比较输出 */
	HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_1);
	HAL_TIM_OC_Start_IT(&htim4,TIM_CHANNEL_2);

pwm波

这里生成代码,pwm配置好初始化他就可以直接输出了 

/* PWM输出两路占空比不相等的PWM波*/
	HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_2);
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wu小燕呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值