STM32F1的PWM端口复用顺序问题

文章讨论了STM32F1中使用TIM4的PWM端口时,传统配置能正常工作,但当使用封装函数进行定时器参数设置时,代码失效。作者怀疑是复用顺序或对封装函数理解不足导致,强调了理解数据手册和深入思考的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32F1的PWM端口复用顺序问题#

#STM32F1的PWM端口复用顺序问题
按照传统的从上到下的顺序配置下来代码能够正常运行,但是在定时器配置哪里使用了封装函数,代码就不能正常运行,寄存器通过debug查看是在重装载的。


正常配置

就是大多数例程中的正常配置

/*************************************************
Function: 		PWM_config
Description: 	tim4定时器通道四 PD12 复用(重映射)输出PWM波
Input: 				 
Output: 			 
Return: 		 
*************************************************/
void PWM_config(u16 arr , u16 psc)
{
		
		GPIO_InitTypeDef GPIO_Motorinit;//配置GPIO结构体初始化
	  TIM_TimeBaseInitTypeDef TIM_Motorinit;//配置定时器结构体初始化
	  TIM_OCInitTypeDef TIMPWM_Motorinit;//配置舵机定时器结构体初始化
	
	  //1.打开时钟
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);//配置GPIO时钟
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//配置定时器时钟
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//配置引脚复用时钟
	
	  GPIO_PinRemapConfig(GPIO_Remap_TIM4,ENABLE);//配置重映射模式为部分重映射
	

	
	  //2.配置GPIO结构
    GPIO_Motorinit.GPIO_Mode  =  GPIO_Mode_AF_PP;//复用推挽输出
	  GPIO_Motorinit.GPIO_Pin   =  GPIO_Pin_12;//pin口配置为5
	  GPIO_Motorinit.GPIO_Speed =  GPIO_Speed_50MHz;//速度配置为50Mhz 
	
	  GPIO_Init(GPIOD,&GPIO_Motorinit);//配置GPIO初始化函数
	
	  //3.配置通用定时器结构体
	  TIM_Motorinit.TIM_ClockDivision  =  TIM_CKD_DIV1;//设置时钟不分频
	  TIM_Motorinit.TIM_CounterMode    =  TIM_CounterMode_Up;//设置计数方式为向上计数
	  TIM_Motorinit.TIM_Period         =  arr-1;//设置在下一个更新事件装入活动的自动重装载值为199
	  TIM_Motorinit.TIM_Prescaler      =  psc-1;//TIM时钟频率预分频值为7199
	  
	  TIM_TimeBaseInit(TIM4,&TIM_Motorinit);	//配置定时器初始化函数
	
	  //4.配置定时器输出PWM结构体
    TIMPWM_Motorinit.TIM_OCMode      = TIM_OCMode_PWM1;//配置PWM定时器模式为1
		TIMPWM_Motorinit.TIM_OutputState = TIM_OutputState_Enable;//使能PWM比较输出
		TIMPWM_Motorinit.TIM_OCPolarity  = TIM_OCNPolarity_Low;//选择有效输出的极性
	  
		TIM_OC1Init(TIM4,&TIMPWM_Motorinit);//配置初始化函数
		TIM_Cmd(TIM4,ENABLE);//使能PWM输出
	  TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);//自动加载的预装载寄存器使能

	
}

不正常配置

采用了封装函数

/*************************************************
Function: 		vTIM_TimeBase_Init
Description: 	定时器参数设置
Input: 				 
Output: 			 
Return: 		 
*************************************************/
void vTIM_TimeBase_Init(TIM_TypeDef* TIMx,u16 Period,u16 Prescaler )
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	TIM_TimeBaseStructure.TIM_Period        = Period-1;//重载值
	TIM_TimeBaseStructure.TIM_Prescaler     = Prescaler-1;//预分频系数
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);
}
/*************************************************
Function: 		vTIM4_Config
Description: 	开启基本定时功能
Input: 				 
Output: 			 
Return: 		 
*************************************************/
void vTIM4_Init(TIM_TypeDef* TIMx,u16 Period,u16 Prescaler )
{
	
	TIM_OCInitTypeDef TIM4PWM_InitStructure;
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	
	GPIO_InitTypeDef GPIO_Motorinit;//配置GPIO结构体初始化
	
	
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//配置引脚复用时钟
	
		  //1.打开时钟
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);//配置GPIO时钟
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//配置定时器时钟

	  GPIO_PinRemapConfig(GPIO_Remap_TIM4,ENABLE);//配置重映射模式为部分重映射
	
	   GPIO_Motorinit.GPIO_Mode  =  GPIO_Mode_AF_PP;//复用推挽输出
	  GPIO_Motorinit.GPIO_Pin   =  GPIO_Pin_12;//pin口配置为5
	  GPIO_Motorinit.GPIO_Speed =  GPIO_Speed_50MHz;//速度配置为50Mhz 
	
	  GPIO_Init(GPIOD,&GPIO_Motorinit);//配置GPIO初始化函数
	

	
		vTIM_TimeBase_Init(TIMx,Period,Prescaler);



			//PWM初始化
	TIM4PWM_InitStructure.TIM_OCMode = TIM_OCMode_PWM1;								//定时器模式1
	TIM4PWM_InitStructure.TIM_OutputState = TIM_OutputState_Enable;		//比较模式输出使能
	TIM4PWM_InitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;				//选择有效输出极性
		
	TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable);
	TIM_OC1Init(TIMx, &TIM4PWM_InitStructure);												//配置PWM通道
	TIM_Cmd(TIMx, ENABLE);

}


最后

简单记录一下在项目中的玄学的问题,可能是经验太少 ,自己也尝试过修改代码顺序,发现第一种顺序就可以正常 运行,第二种就不可以。但是两种配置的情况通过debug的情况来看都是能进入寄存器的。以前以为只要进入了寄存器就可以了,现在看来还是要多看数据手册和多思考理解问题和记录问题。

以后可以会再次遇到这样的问题,所以会记录一下。当下没有解决,以后可能会有思路。

### STM32F1 PWM 配置及使用教程 #### 一、PWM 基本概念 PWM(Pulse Width Modulation,脉宽调制)是一种常见的信号处理技术,在嵌入式系统中广泛应用。它通过对一系列脉冲的宽度进行调整,可以等效地实现所需的波形或模拟参数变化[^3]。 #### 二、STM32F1PWM 实现机制 STM32F1 系列微控制器支持通过定时器模块生成 PWM 波形。其核心思想在于配置 GPIO 和定时器外设协同工作,具体流程如下: 1. **启用时钟源** 使用 RCC 外设时钟控制寄存器启动相关功能单元的时钟供应。这一步骤对于确保后续硬件操作正常至关重要[^1]。 2. **设置 GPIO 引脚模式** 将目标引脚初始化为 `GPIO_Mode_AF_PP` 模式,即复用推挽输出模式。这种模式允许该引脚作为其他外设的功能端口使用,例如 TIMx_CHy 输入/输出通道。 3. **配置定时器 (Timer)** 定义计数方向、频率预分频系数以及自动重装载值等关键参数。这些设定决定了最终输出波形的具体特性,比如周期 T = (ARR + 1) × (PSC + 1) / f<sub>CLK</sub>。 4. **配置输出比较单元 (Output Compare Unit)** 调整 CCR 寄存器中的数值以改变占空比 D = CCR / ARR * 100% 。此比例直接影响到高电平持续时间相对于整个周期的比例关系。 5. **使能并运行定时器实例** 当上述准备工作完成后即可激活对应定时器资源开始运作,并由此产生期望形式的 PWM 输出信号。 #### 三、实际应用案例分析 —— LED 呼吸灯效果演示程序设计思路说明 为了更直观理解如何利用 STM32 平台下的 PWM 功能完成特定任务需求下面给出一个简单例子:制作基于 PWM 技术驱动单颗发光二极管呈现渐亮渐暗循环过渡现象也就是常说的“呼吸灯”。 ##### 主要步骤概述: - 初始化系统环境; - 设置好与之关联的通用输入输出接口状态; - 构建适当规则下工作的高级别中断服务子例程框架结构以便动态更新比较匹配值从而形成连续可变幅度正弦曲线样式的亮度变换过程; 以下是简化版代码片段供参考学习: ```c #include "stm32f1xx_hal.h" TIM_HandleTypeDef htim; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM3_Init(void); int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); // Initialize GPIOs MX_TIM3_Init(); // Configure Timer while(1){}; } // Initialization function for timer peripheral used to generate PWM signal. static void MX_TIM3_Init(void){ __HAL_RCC_TIM3_CLK_ENABLE(); htim.Instance = TIM3; htim.Init.Prescaler = 83; // Set prescaler value according to your clock speed and desired frequency htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 999; // Define period of the waveform, here set as 1kHz -> Period=Prescaler*(ARR+1)/SysClkFreq htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if(HAL_TIM_PWM_Init(&htim)!= HAL_OK){ Error_Handler(); } TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; // Initial duty cycle is half-period sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if(HAL_TIM_PWM_ConfigChannel(&htim,&sConfigOC,TIM_CHANNEL_1)!= HAL_OK){ Error_Handler(); } HAL_TIM_PWM_Start(&htim,TIM_CHANNEL_1); // Start generating PWM on channel 1 } ``` 以上仅展示部分基础构建逻辑,请依据实际情况补充完善错误检测等功能模块。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值