当前位置: 首页 > article >正文

STM32的HAL库开发---高级定时器---输出比较模式实验

一、高级定时器输出比较模式实验原理

定时器的输出比较模式总共有8种,本文使用其中的翻转模式,当TIMXCCR1=TIMXCNT时,翻转OC1REF的电平,OC1REF为输出参考信号,高电平有效,OC1REF信号连接到0C1上面,然后控制CH1输出,CH1通过IO口复用功能,连接到IO口上面,最后输出到外部。

计时器工作在递增模式:

当CNT的值不断递增,递增到于输出比较寄存器CCR1的值相同时,IO电平翻转,然后CNT值继续递增,递增到ARR时,产生计数器溢出事件,计数器值从0开始重新递增,通过这种方式产生方波或者称为PWM波。

周期:IO口输出高电平和低电平总和为一个方波周期,从图上可以看出,一个方波周期为两次计数器溢出的事件,也就是2*(ARR + 1)*t,t为计时器计一个数所需时间。

占空比:再翻转模式下,占空比固定为50%,不可以改变。

总结:PWM波周期或频率由ARR决定,占空比固定50%,相位由CCRX决定。

二、高级定时器输出比较模式实验配置步骤

1、HAL_TIM_OC_Init()函数,配置定时器基础工作参数。

2、HAL_TIM_OC_Msplnit()函数,配置NVIC、CLOCK、GPIO等

3、HAL_TIM_OC_Configchannel()函数,配置输出比较模式。

4、__HAL_TIM_ENABLE_OCxPRELOAD()宏定义,使能通道预装载。

5、HAL_TIM_OC_Start()函数,使能输出、主输出、计数器。

6、__HAL_TIM_SET_COMPARE()宏定义,修改捕获/比较寄存器的值。

三、高级定时器输出比较模式实验

实验:通过定时器8通道1/2/3/4输出相位分别为25%50%75%100%PWM

1、寄存器版本

#include "./BSP/TIMER/atim.h"

//配置定时器8通道1 PC6、PC7、PC8、PC9为翻转模式输出
void Advanced_TIM_Init(void)
{
	//开启TIM8时钟
	RCC->APB2ENR |= (1 << 13);
	
	//开启ARR寄存器缓冲功能
	TIM8->CR1 |= (1 << 7);
	
	//设置PSC预分频系数
	TIM8->PSC = 71;
	
	//设置重装载寄存器值 配置PWM方波为500HZ
	//在翻转模式下 两个ARR溢出时间为PWM一个周期
	TIM8->ARR = (1000000 / (500 * 2)) - 1;
	
	/**************TIM8_CH1*****************/
	//CC1S 设置捕获比较为输出模式
	TIM8->CCMR1 &= ~(0x03 << 0);
	
	//OC1PE 开启输出比较寄存器预装载功能
	TIM8->CCMR1 |= (1 << 3);
	
	//OC1M 设置为翻转模式
	TIM8->CCMR1 |= (0X03 << 4);
	TIM8->CCMR1 &= ~(1 << 6);
		
	//设置CCR1捕获/比较寄存器值 25%相位
	TIM8->CCR1 = 0.25 * (1000000 / (500 * 2)) - 1;
	//TIM8->CCR1 =1;
	
	//设置输出极性为高电平有效 CC1P
	TIM8->CCER &= ~(1 << 1);
	
	//使能输出比较 CC1E
	TIM8->CCER |= (1 << 0);
	
	/**************TIM8_CH2*****************/
	//CC2S 设置捕获比较为输出模式
	TIM8->CCMR1 &= ~(0x03 << 8);
	
	//OC2PE 开启输出比较寄存器预装载功能
	TIM8->CCMR1 |= (1 << 11);
	
	//OC2M 设置为翻转模式
	TIM8->CCMR1 |= (0X03 << 12);
	TIM8->CCMR1 &= ~(1 << 14);		
	
	//设置CCR2捕获/比较寄存器值 50%相位
	TIM8->CCR2 = 0.50 * (1000000 / (500 * 2)) - 1;
	
	//设置输出极性为高电平有效 CC2P
	TIM8->CCER &= ~(1 << 5);
	
	//使能输出比较 CC2E
	TIM8->CCER |= (1 << 4);
	
	/**************TIM8_CH3*****************/
	//CC3S 设置捕获比较为输出模式
	TIM8->CCMR2 &= ~(0x03 << 0);
	
	//OC3PE 开启输出比较寄存器预装载功能
	TIM8->CCMR2 |= (1 << 3);
	
	//OC3M 设置为翻转模式
	TIM8->CCMR2 |= (0X03 << 4);
	TIM8->CCMR2 &= ~(1 << 6);
		
	//设置CCR3捕获/比较寄存器值 75%相位
	TIM8->CCR3 = 0.75 * (1000000 / (500 * 2)) - 1;
	
	//设置输出极性为高电平有效 CC3P
	TIM8->CCER &= ~(1 << 9);
	
	//使能输出比较 CC3E
	TIM8->CCER |= (1 << 8);
	
	/**************TIM8_CH4*****************/
	//CC4S 设置捕获比较为输出模式
	TIM8->CCMR2 &= ~(0x03 << 8);
	
	//OC4PE 开启输出比较寄存器预装载功能
	TIM8->CCMR2 |= (1 << 11);
	
	//OC4M 设置为翻转模式
	TIM8->CCMR2 |= (0X03 << 12);
	TIM8->CCMR2 &= ~(1 << 14);	
	
	//设置CCR4捕获/比较寄存器值 100%相位
	TIM8->CCR4 = 1 * (1000000 / (500 * 2)) - 1;
	
	//设置输出极性为高电平有效 CC4P
	TIM8->CCER &= ~(1 << 13);
	
	//使能输出比较 CC4E
	TIM8->CCER |= (1 << 12);
	
	//软件更新事件  主要为将PSC的值转移到影子寄存器里边
	TIM8->EGR |= (1 << 0);
		
	//MOE 开启主输出
	TIM8->BDTR |= (1 << 15);

	//开启GPIOC时钟
	RCC->APB2ENR |= (1 << 4);
	
	//设置PC6为复用推挽输出
	GPIOC->CRL |= (0X03 << 24);
	GPIOC->CRL |= (1 << 27);
	GPIOC->CRL &= ~(1 << 26);
	
	//设置PC7为复用推挽输出
	GPIOC->CRL |= (0X03 << 28);
	GPIOC->CRL |= (1 << 31);
	GPIOC->CRL &= ~(1 << 30);
	
	//设置PC8为复用推挽输出
	GPIOC->CRH |= (0X03 << 0);
	GPIOC->CRH |= (1 << 3);
	GPIOC->CRH &= ~(1 << 2);
	
	//设置PC9为复用推挽输出
	GPIOC->CRH |= (0X03 << 4);
	GPIOC->CRH |= (1 << 7);
	GPIOC->CRH &= ~(1 << 6);
	
	//使能计数器
	TIM8->CR1 |= (1 << 0);	
	
}




2、库函数版本

 atim.h头文件程序

#ifndef __ATIM_H
#define __ATIM_H

#include "stm32f1xx.h"
void Advanced_TIM_Init(void);

#endif

atim.c

#include "./BSP/TIMER/atim.h"

//配置定时器8通道1 PC6为翻转模式输出
TIM_HandleTypeDef htim;
void Advanced_TIM_Init(void)
{
	htim.Instance = TIM8;
	htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
	htim.Init.CounterMode = TIM_COUNTERMODE_UP;
	htim.Init.Period = 1000000/(500 * 2) - 1;
	htim.Init.Prescaler = 71;
	
	HAL_TIM_OC_Init(&htim);
	
	TIM_OC_InitTypeDef sConfig = {0};
	
	sConfig.OCMode = TIM_OCMODE_TOGGLE;
	sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
	sConfig.Pulse =  0.25 * (TIM8->ARR + 1) - 1;
	
	//配置TIM8 CH1为翻转输出模式
	HAL_TIM_OC_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_1);
	
	//配置TIM8 CH2为翻转输出模式
	sConfig.Pulse = 0.50 * (TIM8->ARR + 1) - 1;
	HAL_TIM_OC_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_2);
	
	//配置TIM8 CH3为翻转输出模式
	sConfig.Pulse = 0.75 * (TIM8->ARR + 1) - 1;
	HAL_TIM_OC_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_3);
	
	//配置TIM8 CH4为翻转输出模式
	sConfig.Pulse = 1 * TIM8->ARR;
	HAL_TIM_OC_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_4);
	
	//使能捕获/比较寄存器通道1预装载
	__HAL_TIM_ENABLE_OCxPRELOAD(&htim,TIM_CHANNEL_1);
	
	//使能捕获/比较寄存器通道2预装载
	__HAL_TIM_ENABLE_OCxPRELOAD(&htim,TIM_CHANNEL_2);
	
	//使能捕获/比较寄存器通道3预装载
	__HAL_TIM_ENABLE_OCxPRELOAD(&htim,TIM_CHANNEL_3);
	
	//使能捕获/比较寄存器通道4预装载
	__HAL_TIM_ENABLE_OCxPRELOAD(&htim,TIM_CHANNEL_4);
	
	TIM8->EGR |= (1 << 0);
	
	//启动TIM8 CH1计数器 主输出 输出比较
	HAL_TIM_OC_Start(&htim, TIM_CHANNEL_1);
	
	//启动TIM8 CH2计数器 主输出 输出比较
	HAL_TIM_OC_Start(&htim, TIM_CHANNEL_2);
	
	//启动TIM8 CH3计数器 主输出 输出比较
	HAL_TIM_OC_Start(&htim, TIM_CHANNEL_3);
	
	//启动TIM8 CH4计数器 主输出 输出比较
	HAL_TIM_OC_Start(&htim, TIM_CHANNEL_4);
}

void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
	//开启定时器8时钟
	__HAL_RCC_TIM8_CLK_ENABLE();
	
	//开启GPIOC时钟
	__HAL_RCC_GPIOC_CLK_ENABLE();
	
	GPIO_InitTypeDef GPIO_Init = {0};
	
	GPIO_Init.Mode = GPIO_MODE_AF_PP;
	GPIO_Init.Pin = GPIO_PIN_6;
	//设置为输出模式时 这个没有用 可以不写 
	GPIO_Init.Pull = GPIO_NOPULL;
	GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
	
	//设置PC6为复用推挽输出
	HAL_GPIO_Init(GPIOC, &GPIO_Init);
	
	GPIO_Init.Pin = GPIO_PIN_7;
	//设置PC7为复用推挽输出
	HAL_GPIO_Init(GPIOC, &GPIO_Init);
	
	GPIO_Init.Pin = GPIO_PIN_8;
	//设置PC8为复用推挽输出
	HAL_GPIO_Init(GPIOC, &GPIO_Init);
	
	GPIO_Init.Pin = GPIO_PIN_9;
	//设置PC9为复用推挽输出
	HAL_GPIO_Init(GPIOC, &GPIO_Init);
	
}

 main.c主函数程序

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/atim.h"

extern TIM_HandleTypeDef htim;
int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
	sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    led_Init();                         /* LED初始化 */
	Advanced_TIM_Init();				//高级定时器初始化
//	__HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, 0);
//    __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_2, 500 - 1);
//    __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_3, 750 - 1);
//    __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_4, 1000 - 1);
    while(1)
    { 
		LED0(1);
		LED1(0);
		delay_ms(500);
		
		LED0(0);
		LED1(1);
		delay_ms(500);
    }
}

在配置过程中发现,如果捕获比较寄存器的值在初始化的时候设置成0,会导致相位错误,设置成1就不会。但是在初始化之后再将比较寄存器的值设置成0,相位正确。这个问题具体原因还没找到,如果有人有思路,可以私信我。 


http://www.kler.cn/a/536963.html

相关文章:

  • MySQL 递归查询:with recursive
  • 使用java代码操作rabbitMQ收发消息
  • UNI-MOL: A UNIVERSAL 3D MOLECULAR REPRESENTATION LEARNING FRAMEWORK
  • 基于SpringBoot养老院平台系统功能实现六
  • Rsyslog omhttp(HTTP输出模块)
  • C32.【C++ Cont】静态实现双向链表及STL库的list
  • Java 多线程、线程同步、线程池
  • C# LiteDB 使用教程
  • Qt实现简易音乐播放器
  • 脚手架开发【实战教程】prompts + fs-extra
  • MySQL视图索引操作
  • 【Linux】Ubuntu Linux 系统 ——Android开发环境
  • linux进程通讯-信号处理介绍
  • [开源/教程]使用Ollama+ESP32实现本地对话助手(可接入deepseek等模型)
  • 基于微信平台的报刊订阅小程序的设计与实现ssm+论文源码调试讲解
  • 新注册的域名无法访问,是怎么回事?
  • “AI隐患识别系统,安全多了道“智能护盾”
  • 鸿蒙UI(ArkUI-方舟UI框架)- 设置组件导航和页面路由
  • 青少年编程与数学 02-008 Pyhon语言编程基础 24课题、正则表达式
  • MES系统对于中小型制造企业有什么价值?
  • verilog练习:8bit移位寄存器
  • 防火墙与Squid代理服务器
  • FastReport 加载Load(Stream) 模板内包含换行符不能展示
  • 【网络】应用层协议http
  • 避免样式冲突:掌握CSS选择器优先级与层叠规则的终极指南
  • Itext pdf reader解析