STM32F103 定时器输出PWM输出并实现呼吸灯实验分享_hal

PWM简介 : 英文 "Pulse Width Modulation"的缩写, 简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的计数,简单点说,就是对脉冲宽的的控制.

STM32定时器除了TIM6和TIM7以外,都可以用来产生PWM输出,其中TIM1和TIM8可以同时产生多达7路的PWM输出,而通用定时器也能同时产生多达4路PWM输出,STM32可以同时产生30路PWM输出,

我们要想了解PWM输出当然首先是先了解其控制的寄存器,除了定时器控制相关寄存器以外, 要产生PWM还需要哦了解 以下三个寄存器,  这三个寄存器分别是:捕获/比较模式寄存器 (TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。 接下来我们简单介绍一下这三个寄存器。

首先是捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器总共有 2 个,TIMx _CCMR1 和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。该寄存器 的各位描述如图 14.1.1 所示:

该寄存器的有些位在不同模式下,功能不一样,所以在图 14.1.1 中,我们把寄存器分了 2 层,上面一层对应输出而下面的则对应输入。

这里我们需要说明的是模式设置位 OCxM,此部分由 3 位组成。 总共可以配置成 7 种模式,我们使用的是 PWM 模式,所以这 3 位必须设置为 110/111。这两种 PWM 模式的区别就是输出电平的极性相反。 接下来,我们介绍捕获/比较使能寄存器(TIMx_CCER),该寄存器控制着各个输入输出通 道的开关。该寄存器的各位描述如图 14.1.2 所示:该寄存器比较简单,我们这里只用到了 CC2E 位,该位是输入/捕获 2 输出使能位,要想 PWM 从 IO 口输出,这个位必须设置为 1,所以我们需要设置该位为 1。

最后,我们介绍一下捕获/比较寄存器(TIMx_CCR1~4),该寄存器总共有 4 个,对应 4 个 输通道 CH1~4。因为这 4 个寄存器都差不多,我们仅以 TIMx_CCR1 为例介绍,该寄存器的各 位描述如图 14.1.3 所示

在输出模式下,该寄存器的值与 CNT 的值比较,根据比较结果产生相应动作。利用这点, 我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。

        我们使用的是 TIM2 的通道 2,所以我们需要修改 TIM2_CCR2 以实现脉宽控制 DS0 的亮度。 我们要利用 TIM2 的 CH2 输出 PWM 来控制 DS0 的亮度,但是 TIM2_CH2 默认是接在 PA1 上面的.如果需要不是你所需要的口直接将端口配置映射在相应的口上既可,关于端口映射可以关注STM32 端口复用功能相关文章即可.

接下来就该配置了,

这里我们需要配置两方面的内容,

第一就是定时器相关配置,以下部分是关于定时器外设相关配置的函数, 如果是使用Hal

库的话需要定义定时器的句柄,如果使用库函数开发的话,配置相关的结构体成员即可,如下代码是对定时器初始化结构体和PWM相关寄存器的配置, 此函数会在下面的Tim2_Init()中调用,当然这里也可以直接在main函数之前调用,TIM2_PwmConfig()函数,这里是为了方便后续增加更多的功能,方便统一管理, 

TIM_HandleTypeDef 	htim2;      	//定时器句柄 
/**
***********************************************************
* @brief TIM2 PWM部分初始化
* @param arr:自动重装值, psc:时钟预分频数
* @return
* @explain 定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
			Ft=定时器工作频率,单位:Mhz
***********************************************************
*/
void TIM2_PwmConfig(uint16_t arr,uint16_t psc)
{  
	
	TIM_OC_InitTypeDef 	TIM2_CH2Handler;		//定时器2通道2句柄
	
	htim2.Instance=TIM2;                          	//通用定时器3
    htim2.Init.Prescaler=psc;                     	//分频系数
    htim2.Init.CounterMode=TIM_COUNTERMODE_UP;    	//向上计数器
    htim2.Init.Period=arr;                        	//自动装载值
    htim2.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子
    HAL_TIM_PWM_Init(&htim2);
	
    TIM2_CH2Handler.OCMode = TIM_OCMODE_PWM2; //模式选择PWM2
    TIM2_CH2Handler.Pulse = arr / 2;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
    TIM2_CH2Handler.OCPolarity = TIM_OCPOLARITY_LOW; //输出比较极性为低 
    HAL_TIM_PWM_ConfigChannel(&htim2,&TIM2_CH2Handler,TIM_CHANNEL_2);//配置TIM2通道2
	
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);//开启PWM通道2
	 	   
}
/**
***********************************************************
* @brief 通用定时器3初始化函数
* @param arr:自动重装值, psc:时钟预分频数
* @return
* @explain 定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
			Ft=定时器工作频率,单位:Mhz
***********************************************************
*/
void TIM2_Init(uint16_t arr,uint16_t psc)
{  
 
	TIM2_PwmConfig(arr,psc);	//pwm 初始化结构体配置函数
}

第二方面配置, 我们既然使能了定时器2的通道2, 那么自然需要对其相应的GPIO口进行配置 

如下:

/**
***********************************************************
* @brief TIM2 定时器底层驱动,时钟使能,引脚配置
* @param 
* @return
* @explain  此函数会被HAL_TIM_PWM_Init()函数调用
***********************************************************
*/
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	GPIO_InitTypeDef GPIO_Initure;
	
    if(htim->Instance==TIM2)
	{
		__HAL_RCC_TIM2_CLK_ENABLE();			//使能定时器2		
		__HAL_RCC_GPIOA_CLK_ENABLE();			//开启GPIOB时钟
		
		GPIO_Initure.Pin=GPIO_PIN_1;           	//PA1
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;  	//复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
		GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
		HAL_GPIO_Init(GPIOA,&GPIO_Initure); 	
	}
}

以上的配置是为了实现在定时器对应的通道上能够输出我们想要的PWM波形 

配置到这里我们已经可以实现在在PA1口上输出一个占空比为50%的PWM波形了,如下图:

当然看到波形之前别忘记在主函数的While之前先初始化哦,

int main(void)
{
    HAL_Init();                    	 	//初始化HAL库    
    Stm32_Clock_Init(RCC_PLL_MUL9);   	//设置时钟,72M
	
		
    TIM2_Init(100-1,720-1);       	//72M/72=1M的计数频率,自动重装载为500,那么PWM频率为1M/500=2kHZ
  
	printf("TIM Output PWM Test: \r\n");
	while(1)
    {
		
	}
}

我们还可以给他增加一些功能,例如我们平常最常见的呼吸灯 ,这样只需要在main函数中增加如下代码即可

#define  PULSE_MAX_VAL 99
uint16_t pwm_dir = 0;// 用来控制呼吸灯的方向
uint16_t pulse = 0;//用来设置当前比较值
int main(void)
{
    HAL_Init();                    	 	//初始化HAL库    
    Stm32_Clock_Init(RCC_PLL_MUL9);   	//设置时钟,72M
	delay_init(72);               		//初始化延时函数
	uart_init(115200);					//初始化串口
		
    TIM2_Init(100-1,720-1);       	//72M/72=1M的计数频率,自动重装载为500,那么PWM频率为1M/500=2kHZ
  
	printf("TIM Output PWM Test: \r\n");
	while(1)
    {
		
		if(!pwm_dir)
		{
			HAL_Delay(10);
			TIM_SetTIM2Compare2(pulse++);
			pwm_dir=(pulse > PULSE_MAX_VAL) ? 1 : 0;
		}
		else 
		{
			HAL_Delay(10);
			TIM_SetTIM2Compare2(pulse--);
			pwm_dir=(pulse < 1) ? 0 : 1;
		}      
      
    }
}

如上的代码中

TIM_SetTIM2Compare2()函数主要是用来设置一个变化的值来实现PWM输出变化的效果,

这里是为了方便管理,封装的函数,其实就是调用系统中的 __HAL_TIM_SET_COMPARE();

或者是将变量的值直接赋给 TIM2->CCR2=compare;可以实现同样的效果;

代码如下

/**
***********************************************************
* @brief 设置TIM通道2的占空比
* @param compare:比较值 
* @return
* @explain  
***********************************************************
*/
void TIM_SetTIM2Compare2(uint32_t compare)
{
	__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,compare);
//	TIM2->CCR2=compare; 
}

   以上 就可以实现一个 呼吸灯的效果了, 如果各位小伙伴想要试试不同的效果,可以尝试改变 下我们设置的 PULSE_MAX_VAL或者 TIM_Init(arr,psr) 中两个参数的值哦,

如果有不懂的可以留言, 本人很乐意帮助大家解答 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是STM32F103PWM控制代码示例,使用的是CubeMX和HAL库。 首先,在CubeMX中启用TIM2,并配置为PWM模式。选择“TIM2”,在右侧的“Mode”选项卡中选择“PWM Generation CH1”,并设置频率和占空比。生成代码并导入到工程中。 接下来,在需要使用PWM的函数中,添加以下代码: ``` #include "stm32f1xx_hal.h" /* 定义TIM_HandleTypeDef结构体 */ TIM_HandleTypeDef htim2; /* 初始化PWM控制器 */ void PWM_Init(void) { /* 使能TIM2时钟 */ __HAL_RCC_TIM2_CLK_ENABLE(); /* 初始化TIM2结构体 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 0; /* 预分频器 */ htim2.Init.Period = 999; /* 计数器上限值 */ htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.RepetitionCounter = 0; HAL_TIM_PWM_Init(&htim2); /* 初始化PWM配置 */ TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; /* 占空比为50% */ sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1); /* 启动PWM输出 */ HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); } /* 改变PWM占空比 */ void PWM_SetDutyCycle(uint16_t dutyCycle) { TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = dutyCycle; /* 占空比 */ sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); } ``` 以上代码将TIM2配置为PWM输出模式,并启用输出通道1。在PWM_Init()函数中,您可以设置预分频器、计数器上限值和占空比。在PWM_SetDutyCycle()函数中,您可以通过改变占空比来改变PWM输出。注意,每次改变占空比后,需要重新启动PWM输出。 您可以在需要控制PWM的地方调用PWM_Init()函数来初始化PWM控制器,并使用PWM_SetDutyCycle()函数来改变PWM输出的占空比。 希望这

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值