STM32输出可控数量的pwm波形

在做步进电机驱动程序,想让电机按一定速度运行一定角度,于是采用了

一个主定时器产生pwm,另外一个从定时器负责发送脉冲数量的计数

STM32F103VE 时钟72MHz

实现:输出可控数量与频率的脉冲(pwm)

使用一个(主)定时器作为另一个(从)定时器的预分频器(外部时钟触发源)

本例子通过<df_MAIN_TIM_1_OR_8>修改可以实现TIM1和TIM8主的切换产生PWM信号,TIM2作为从定时器,用于对主定时器的计数,计数到达设定数量,停止pwm输出

TIM8已验证功能-ok;TIM1仿真运行正常,输出未验证

zhcj66@163.com
2022.10.29

#define df_MAIN_TIM_1			0					//主定时器1
#define df_MAIN_TIM_8			1					//主定时器8
#define df_MAIN_TIM_1_OR_8		df_MAIN_TIM_8		//定时器选择

void TIM1_MasterPwmOutInit(void);
void TIM8_MasterPwmOutInit(void);

//TIM1_主pwm输出初始化
void TIM1_MasterPwmOutInit(void){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
//pwm频率=72000000/psc/arr  这里为了测试设置了1Hz用于led观测
unsigned short arr=10000;//周期 
unsigned short psc=7200;//分频 
	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_TIM1 , ENABLE); //时钟使能
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                   //TIM1_CH4 PA11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;             //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
    TIM_TimeBaseStructure.TIM_Period = arr-1;                 //使用Cycle来控制频率(f=72/(71+1)/Cycle)  当Cycle为100时脉冲频率为10KHZ                           
    TIM_TimeBaseStructure.TIM_Prescaler = psc-1;                    //设置用来作为TIMx时钟频率除数的预分频值                                                     
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //设置时钟分割:TDTS= Tck_tim            
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            //重复计数,一定要=0!!!(高级定时器特有)
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);                                       
 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;          		//选择定时器模式:TIM脉冲宽度调制模式1       
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 	//比较输出使能
    TIM_OCInitStructure.TIM_Pulse = psc/2-1;                    	//设置待装入捕获寄存器的脉冲值(占空比:默认50%,这可也可以调节如果需要的话将它作为一个参数传入即可)                                   
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;      	//输出极性       
 
    TIM_OC4Init(TIM1, &TIM_OCInitStructure);        				//使能通道4                                                 
 
    TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);	//设置为主从模式
    TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);			//选择定时器1的触发方式(使用更新事件作为触发输出)
    
 
    TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);               //使能通道4预装载寄存器   
	
    TIM_ARRPreloadConfig(TIM1, ENABLE);                             //使能TIM1在ARR上的预装载寄存器  
	
    //TIM_CtrlPWMOutputs(TIM1, ENABLE);   							//高级定时器一定要加上,主输出使能     
}

//TIM8_pwm输出初始化
void TIM8_MasterPwmOutInit(void){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
//pwm频率=72000000/psc/arr  这里为了测试设置了1Hz用于led观测
unsigned short arr=10000;//周期
unsigned short psc=7200;//分频
	
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟使能
	
	//PC6-CH1
	//PC7-CH2
	//PC8-CH3 cut_pwm
	//PC9-CH4 out_pwm
	//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;//初始化GPIO 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;//初始化GPIO 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  						//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
		
	TIM_TimeBaseStructure.TIM_Period = arr; 								//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 								//设置用来作为TIMx时钟频率除数的预分频值  72MHz/(psc+1)/(arr+1)=频率
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 				//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  			//TIM向上计数模式
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            			//重复计数,一定要=0!!!(高级定时器特有)<<<这里必须设置否则从计数器不正常
	TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); 						//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	 
//	{//CH1
//		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 						//选择定时器模式:TIM脉冲宽度调制模式1
//		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;			//使能/失能OCx管脚
//		TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 		//使能/失能OCxN管脚(使用OCxN必须使能TIM_OutputState)
//		TIM_OCInitStructure.TIM_Pulse = arr+1; 									//设置待装入捕获比较寄存器的脉冲值
//		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 				//输出极性:TIM输出比较极性高
//		TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;				//输出极性
//		TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;				//BDTR寄存器的MOE为0时对应管脚状态
//		TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;			//BDTR寄存器的MOE为0时对应管脚状态
//		TIM_OC1Init(TIM8, &TIM_OCInitStructure);  								//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
//		
//		TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);  						//使能TIMx在CCR2上的预装载寄存器
//	} 
//	{//CH2
//		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 						//选择定时器模式:TIM脉冲宽度调制模式1
//		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;			//使能/失能OCx管脚
//		TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 		//使能/失能OCxN管脚(使用OCxN必须使能TIM_OutputState)
//		TIM_OCInitStructure.TIM_Pulse = arr+1; 									//设置待装入捕获比较寄存器的脉冲值
//		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 				//输出极性:TIM输出比较极性高
//		TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;				//输出极性
//		TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;				//BDTR寄存器的MOE为0时对应管脚状态
//		TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;			//BDTR寄存器的MOE为0时对应管脚状态
//		TIM_OC2Init(TIM8, &TIM_OCInitStructure);  								//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
//		
//		TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);  						//使能TIMx在CCR2上的预装载寄存器
//	}
	{//CH3
		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 						//选择定时器模式:TIM脉冲宽度调制模式1
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;			//使能/失能OCx管脚
		TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 		//使能/失能OCxN管脚(使用OCxN必须使能TIM_OutputState)
		TIM_OCInitStructure.TIM_Pulse = arr/2-1; 								//设置待装入捕获比较寄存器的脉冲值 占空比
		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 				//输出极性:TIM输出比较极性高
		TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;				//输出极性
		TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;				//BDTR寄存器的MOE为0时对应管脚状态
		TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;			//BDTR寄存器的MOE为0时对应管脚状态
		TIM_OC3Init(TIM8, &TIM_OCInitStructure);  								//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
		
		TIM_OC3PreloadConfig(TIM8, TIM_OCPreload_Enable);  						//使能TIMx在CCR2上的预装载寄存器
	}
	{//CH4
		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 						//选择定时器模式:TIM脉冲宽度调制模式1
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;			//使能/失能OCx管脚
		TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 		//使能/失能OCxN管脚(使用OCxN必须使能TIM_OutputState)
		TIM_OCInitStructure.TIM_Pulse = arr/2-1; 								//设置待装入捕获比较寄存器的脉冲值 占空比
		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 				//输出极性:TIM输出比较极性高
		TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;				//输出极性
		TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;			//BDTR寄存器的MOE为0时对应管脚状态
		TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;			//BDTR寄存器的MOE为0时对应管脚状态
		TIM_OC4Init(TIM8, &TIM_OCInitStructure);  								//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
		
		TIM_OC4PreloadConfig(TIM8, TIM_OCPreload_Enable);  						//使能TIMx在CCR2上的预装载寄存器
	}
	
	TIM_ARRPreloadConfig(TIM8, ENABLE); 										//使能TIMx在ARR上的预装载寄存器
	
	
//	TIM_CtrlPWMOutputs(TIM8, ENABLE);										//TIM8->BDTR|=1<<15; 主输出MOE
	
//	TIM_Cmd(TIM8, ENABLE);  												//使能TIMx外设
	TIM_SetCompare3(TIM8,arr/2-1);											//TIM8->CCR2 = x;更改占空比(设置范围0~arr)
	TIM_SetCompare3(TIM8,arr/2-1);											//TIM8->CCR2 = x;更改占空比(设置范围0~arr)
	
}		
	{//设置为主从模式
		TIM_SelectMasterSlaveMode(TIM8, TIM_MasterSlaveMode_Enable);	//设置为主从模式
		TIM_SelectOutputTrigger(TIM8, TIM_TRGOSource_Update);			//选择定时器1的触发方式(使用更新事件作为触发输出)        
	}	
		      
}

//TIM2从计数定时器初始化
//设定脉冲数量后面可以通过TIM_SetAutoreload(TIM2,X);修改,这里预设了一个数值
void TIM2_SlaveCountInit(void){
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure; 
unsigned short PulseNum = 65535;							//预设脉冲数
	
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);		//使能定时器2的时钟
	
    TIM_TimeBaseStructure.TIM_Period = PulseNum-1;   			//脉冲数
    TIM_TimeBaseStructure.TIM_Prescaler =0;    
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  

#if (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_1)
    TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0);					//选择定时器2的输入触发源(内部触发(TIM1))
#elif (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_8)
	TIM_SelectInputTrigger(TIM2, TIM_TS_ITR1);					//选择定时器2的输入触发源(内部触发(TIM8))
#endif //df_MAIN_TIM_1_OR_8
                                 
	TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_External1);     		//TIM2->SMCR|=0x07;设置从模式寄存器(SMS[2:0]:111 外部时钟模式1) 
 
    TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);					//更新中断失能
 
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;        
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure);								//定时器2中断初始化
}

//定时器_主从_pwm计数_初始化
void TIM_MasterSlave_PWMCount_Init(void){	
    TIM2_SlaveCountInit();						//初始化 (从定时器)
    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);	//清除中断标志位
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);	//使能更新中断
	
#if (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_1)	
    TIM1_MasterPwmOutInit();						//使能定时器1(主定时器)    
#elif (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_8)
	TIM8_MasterPwmOutInit();						//使能定时器1(主定时器)
#endif //df_MAIN_TIM_1_OR_8
}

//定时器_主从_pwm计数_开始
//PulseNum :用于设定输出脉冲的数量
void TIM_MasterSlave_PWMCount_Start(unsigned short PulseNum){
	PulseNum = (PulseNum>1?PulseNum-1:PulseNum); //这里的数值不能为0,为0后TIM2将失效; 设置数-1为需要的脉冲数
    TIM_Cmd(TIM2, ENABLE);						//使能TIM2 (从定时器)
	TIM_SetAutoreload(TIM2,PulseNum);			//设置脉冲数量
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);	//使能更新中断
	
#if (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_1)	    
    TIM_Cmd(TIM1, ENABLE);						//使能定时器1
	TIM_CtrlPWMOutputs(TIM1, ENABLE);   		//高级定时器一定要加上,主输出使能
#elif (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_8)
    TIM_Cmd(TIM8, ENABLE);						//使能定时器8
	TIM_CtrlPWMOutputs(TIM8, ENABLE);   		//高级定时器一定要加上,主输出使能
#endif //df_MAIN_TIM_1_OR_8
}

//当TIM的CNT寄存器的值到达设定的Update值会触发更新中断,此时设定的脉冲数已输出完毕,关闭TIM1和TIM2
void TIM2_IRQHandler(void){ 
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){ 	//TIM_IT_Update
     
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); 	// 清除中断标志位 
#if (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_1)	
        TIM_CtrlPWMOutputs(TIM1, DISABLE);  			//主输出失能
        TIM_Cmd(TIM1, DISABLE); 						//关闭定时器 
#elif (df_MAIN_TIM_1_OR_8 == df_MAIN_TIM_8)		
        TIM_CtrlPWMOutputs(TIM8, DISABLE);  			//主输出失能
        TIM_Cmd(TIM8, DISABLE); 						//关闭定时器 
#endif //df_MAIN_TIM_1_OR_8
        TIM_Cmd(TIM2, DISABLE); 						//关闭定时器 
        TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); 	//关闭TIM2更新中断
    } 
} 


u8 ksw=0;
void tim_test_co(void){
	TIM_MasterSlave_PWMCount_Init();//初始化
	while(1)
	{
		if(ksw){
			ksw = 0;
			TIM_MasterSlave_PWMCount_Start(3);//启动3个pwm
		}
	}
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32F4系列微控制器中的高级定时器,可以用来产生PWM(脉宽调制)信号。PWM信号常用于电机驱动、LED灯控制、音频信号生成等应用。 首先,我们需要选择一个高级定时器来作为PWM输出源。STM32F4系列微控制器有多个高级定时器可供选择,如定时器1(TIM1)、定时器2(TIM2)、定时器3(TIM3)等。我们可以根据具体需求选择一个合适的定时器。 然后,在初始化定时器之前,需要先对GPIO端口进行配置。设置GPIO引脚的模式为复用模式,并选择合适的引脚复用功能,以使其连接到定时器的输出通道。 接下来,我们需要初始化选定的高级定时器。通过配置定时器的时钟源、分频系数和计数模式等参数,来设置定时器的工作频率和计数范围。同时,还需要配置定时器的模式为PWM输出模式,并选择合适的通道模式和极性。 在初始化完成后,我们可以通过修改定时器的自动重载寄存器(ARR)和占空比调整寄存器(CCR)来控制PWM信号的周期和占空比。自动重载寄存器用于设置PWM信号的周期,占空比调整寄存器则用于设置PWM信号的占空比。 最后,启动定时器即可开始输出PWM信号。通过设置定时器的使能位,我们可以启动定时器开始计数,并将生成的PWM信号输出到相应的GPIO引脚。 需要注意的是,通过高级定时器输出PWM信号时,需要仔细计算和设置定时器的参数,确保生成的PWM信号满足具体应用要求。 以上就是使用STM32F4高级定时器输出PWM的基本步骤。当然,具体的实现还需要根据具体芯片型号和使用的开发环境来进行细致调整和配置。 ### 回答2: STM32F4高级定时器是一种功能强大的定时器模块,可用于输出PWM信号。以下是使用STM32F4高级定时器输出PWM的步骤: 第一步,配置定时器: 首先,选择要使用的定时器,如TIM1、TIM2等。然后,根据需要配置周期、分频系数和计数模式等参数。可通过寄存器设置或使用STM32CubeMX进行配置。 第二步,配置PWM模式: 选择PWM输出模式,例如选择PWM模式1或2。配置输出通道的极性、周期和占空比等参数。此外,还可以设置多通道的自动更新和互补输出功能。 第三步,配置GPIO引脚: 选定用于输出PWM信号的GPIO引脚,并配置为复用功能。确保GPIO引脚与定时器通道相匹配。 第四步,编程实现PWM输出: 使用适当的编程语言,例如C或汇编语言,编写程序以初始化和启动定时器。在程序中,设置PWM的周期和占空比,然后启动定时器。 第五步,输出PWM信号: 定时器开始计数后,会自动输出PWM信号。根据配置的周期和占空比参数,定时器会生成相应的PWM波形信号。 除了上述步骤外,还可以根据需要使用中断来处理定时器事件。通过配置中断服务例程,可以在定时器溢出、计数匹配等事件发生时执行特定的操作,以实现更精确的控制。 总之,STM32F4高级定时器提供了强大的PWM输出功能,通过适当的配置和编程,可以实现高精度的PWM信号输出。 ### 回答3: STM32F4系列微控制器中的高级定时器(advanced timer)可以用于输出PWM信号。以下是使用STM32CubeIDE配置高级定时器输出PWM的步骤: 1. 在STM32CubeIDE中创建一个新的工程,并选择适合的STM32F4系列微控制器型号。 2. 打开RCC配置工具,在高级定时器的时钟源中选择合适的时钟源,例如内部时钟。 3. 打开GPIO配置工具,选择需要使用的IO引脚,并将其配置为复用功能。 4. 打开定时器配置工具,选择需要使用的高级定时器(如TIM1、TIM2等)。根据需要,配置定时器的计数模式、计数频率、自动重装载值等。 5. 配置定时器通道,选择需要用于PWM输出的通道,并设置通道的输出模式为PWM模式。 6. 根据具体需求设置PWM的周期和占空比。可以通过调整自动重装载值和通道的比较值来实现。 7. 配置定时器的时钟分频系数,使其与所需的PWM频率相匹配。 8. 生成代码,并将生成的代码添加到工程中。 9. 在生成的代码中,根据需要调用HAL库提供的函数来启动和停止定时器。 通过上述步骤,就可以使用STM32F4的高级定时器输出PWM信号了。在实际应用中,还可以根据需要调整PWM的周期、占空比以及使用中断等功能来实现更复杂的PWM输出

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值