学习stm32 pwm 多路舵机的控制(PWM 的频率的理解)

这篇具有很好参考价值的文章主要介绍了学习stm32 pwm 多路舵机的控制(PWM 的频率的理解)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

接着上一节,pwm 的使用,控制多路舵机进行角度旋转和设置。

参考stm32f103x中文说明时钟树如下图
stm32的pwm频率,pwm,stm32,单片机,学习
1.当HSI被用于作为PLL时钟的输入时,系统时钟能得到的最大频率是64MHz。
2.对于内部和外部时钟源的特性,请参考相应产品数据手册中“电气特性”章节。
用户可通过多个预分频器配置AHB、高速APB(APB2)和低速APB(APB1)域的频率。AHB和
APB2域的最大频率是72MHz。APB1域的最大允许频率是36MHz。SDIO接口的时钟频率固定
为HCLK/2。
RCC通过AHB时钟(HCLK)8分频后作为Cortex系统定时器(SysTick)的外部时钟。通过对SysTick
控制与状态寄存器的设置,可选择上述时钟或Cortex(HCLK)时钟作为SysTick时钟。ADC时钟
由高速APB2时钟经2、4、6或8分频后获得。
定时器时钟频率分配由硬件按以下2种情况自动设置:

  1. 如果相应的APB预分频系数是1,定时器的时钟频率与所在APB总线频率一致。
  2. 否则,定时器的时钟频率被设为与其相连的APB总线频率的2倍。

科普小知识下面会用

1Hz代表每秒周期震动1次
1MHZ=1,000,000HZ
1hz是一秒1次,即1mhz是一百万秒
1s = 1000ms = 1,000,000us
秒 毫秒 微妙

定时器PWM 的频率
stm32的pwm频率,pwm,stm32,单片机,学习
根据STM32的定时器时钟的频率,比如时钟的频率是72MHZ,可以理解为一秒钟STM32会自己数72M次,
预分频系数就是将频率分割,比如分频系数是72,则该时钟的频率会变成72MHZ/72=1MHZ,
但是在设置的时候要注意,数值应该是72-1。
假定分频系数是72-1,那么频率变成1MHZ,也就意味着STM32在一秒钟会数1M次,即1us数一次。1/1000 000 =0.000 001s = 1us
₣apb = 72MHZ;

理解转化:分频把时钟的频率分割开来达到需要的频率

预分频 频率为
72MHZ 72(分频系数0~72) 1MHZ(1mhz是一百万秒)
72MHZ 7200 -1 1/10 000 = 0.0001 s = 100us
72MHZ 7200 -1 1/10 000 = 0.0001 s = 100us

如此类推,在预分频系数确定的情况下,定时的时长就由预装载值确定了

不同舵机设置的预分频系数和频率

PWM的频率: 是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);
也就是说一秒钟PWM有多少个周期
单位: Hz
表示方式: 50Hz 100Hz
PWM的周期:
T=1/f
周期=1/频率
50Hz = 20ms 一个周期
按照公式 如下

				72x1,000,000HZ
Fpwm =   ---------------------------------- = 50HZ
				(PSC-1)x(ARR-1)	            
 PWM周期为20ms = (2000*720)/72000000 = 0.2,通过程序设置的TIM_Period = 719,TIM_Prescaler = 1999(本文程序)

多路舵机的控制只需要要定时器初始化多个通道连接舵机的时钟线即可。

代码出处来与博客 (部分修改)
版权声明:本代码出处为CSDN博主「菜菜Chicken」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37957854/article/details/105666609

timx.c

#include "timx.h"
#include "system.h"

/**
	定时器3,可产生四路的PWM输出,四个通道分别对应的引脚情况如下
	TIM3_CH1,TIM3_CH2,TIM3_CH3,TIM3_CH4
	没有重映像的对应情况:
	PA6,PA7,PB0,PB1
	部分重映像:
	PB4,PB5,PB0,PB1
	完全重映像:
	PC6,PC7,PC8,PC9	

	当我们的IO口不仅仅是做普通的输入输出使用的时候,作为别的外设(AD,串口,定时器等)的特定功能引脚,就需要开启外设.
	这里我们还需要开启APB2外设上的复用时钟AFIO,同时IO口采用的是复用输出!

	我们这里是没有使用重映射功能.
*/
// 宏定义
//判断当前是处于哪一种模式,以便于我们初始化IO口
#define NO_REAMP   0
#define PART_REAMP 1
#define FULL_REAMP 2

// ---> 这里是需要制定的参数

//指定这里的 当前的模式,我们给她默认指定是 没有重映射
#define CURRENT_MODE PART_REAMP 

//*************根据当前模式初始化IO口 函数
void MY_TIM3_GPIO_Init(void){
	
	GPIO_InitTypeDef 	GPIO_InitStructure;
	
	//1.开启AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	//2. 根据当前的重映像的模式 配置时钟 和 初始化相关引脚
	switch(CURRENT_MODE){
		
		//2.1 如果没有重映射
		case NO_REAMP:{
			
			// 时钟分配
			RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
			// 初始化IO口
			GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
			GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
			GPIO_Init(GPIOA,&GPIO_InitStructure);
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
			GPIO_Init(GPIOB,&GPIO_InitStructure);
			
			break;
		}
		//2.2 部分重映射
		case PART_REAMP:{
			
			// 时钟分配
			RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
			// 初始化IO口
			GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
			GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5;
			GPIO_Init(GPIOB,&GPIO_InitStructure);
			
			GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//改变指定管脚的映射	
			break;
		}
		//2.3 全映射
		case FULL_REAMP:{
			
			// 时钟分配
			RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
			// 初始化IO口
			GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
			GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
			GPIO_Init(GPIOC,&GPIO_InitStructure);
			
			GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//改变指定管脚的映射	
			break;
		}
		default:break;
	}	
}
/*
	* 初始化定时器的时候指定我们分频系数psc,这里是将我们的系统时钟(72MHz)进行分频
	* 然后指定重装载值arr,这个重装载值的意思就是当 我们的定时器的计数值 达到这个arr时,定时器就会重新装载其他值.
		例如当我们设置定时器为向上计数时,定时器计数的值等于arr之后就会被清0重新计数
	* 定时器计数的值被重装载一次被就是一个更新(Update)
	* 计算Update时间公式
	Tout = ((arr+1)*(psc+1))/Tclk
	公式推导详解:
		Tclk是定时器时钟源,在这里就是72Mhz 
		我们将分配的时钟进行分频,指定分频值为psc,就将我们的Tclk分了psc+1,我们定时器的最终频率就是Tclk/(psc+1) MHz
		这里的频率的意思就是1s中记 Tclk/(psc+1)M个数 (1M=10的6次方) ,每记一个数的时间为(psc+1)/Tclk ,很好理解频率的倒数是周期,这里每一个数的周期就是(psc+1)/Tclk 秒
		然后我们从0记到arr 就是 (arr+1)*(psc+1)/Tclk
	举例:比如我们设置arr=7199,psc=9999
	我们将72MHz (1M等于10的6次方) 分成了(9999+1)等于 7200Hz
	就是一秒钟记录9000数,每记录一个数就是1/7200秒
	我们这里记录9000个数进入定时器更新(7199+1)*(1/7200)=1s,也就是1s进入一次更新Update
*/
//简单进行定时器初始化,设置 预装载值 和 分频系数
void MY_TIM3_Init(u16 arr,u16 psc){
	
	//初始化结构体
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	//1.分配时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	//2.初始化定时器相关配置
	TIM_TimeBaseStructure.TIM_Period = arr;
	TIM_TimeBaseStructure.TIM_Prescaler = psc;
	
	/*在这里说一下这个TIM_ClockDivision 是设置与进行输入捕获相关的分频
		设置的这个值不会影响定时器的时钟频率,我们一般设置为TIM_CKD_DIV1,也就是不分频*/
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
	
	//3.打开定时器
	TIM_Cmd(TIM3,ENABLE);
}


//***************** 定时器PWM输出初始化函数
void MY_TIM3_PWM_Init(u16 arr,u16 psc){
	
	//初始化结构体
	TIM_OCInitTypeDef TIM_OCInitstrcuture;
	
	//1.初始化定时器 和 相关的IO口
	MY_TIM3_Init(arr,psc); 
	MY_TIM3_GPIO_Init();
	
	//2.初始化PWM的模式
	
	/**
	选择PWM模式:
		PWM1模式:
			向上计数时,当我们 当前的 计数值 小于我们的设置阈值为有效电平,否则为无效电平,向下计数时与向上计数时相反
		PWM2模式:
			与PWM1模式向上向下计数时完全相反
	*/
	TIM_OCInitstrcuture.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitstrcuture.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitstrcuture.TIM_OCPolarity = TIM_OCPolarity_High;   //输出电平为高,也就是有效电平为高
	TIM_OC1Init(TIM3,&TIM_OCInitstrcuture);						//这里是设置利用通道1输出
	
	//这里初始化通道1、2、3、4,我们可以根据自己需求初始化其它通道
	
	TIM_OC2Init(TIM3,&TIM_OCInitstrcuture);
	TIM_OC3Init(TIM3,&TIM_OCInitstrcuture);
	TIM_OC4Init(TIM3,&TIM_OCInitstrcuture);

	TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能预装载寄存器
	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
	TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);
	TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);
	
}


//TIM4 PWM初始化
void TIM4_CH1_PWM_Init(u16 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
	TIM_OCInitTypeDef TIM_OCInitTypeStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	
	//要开启复用功能的时钟才能重映射
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  ,ENABLE); 
	
	//TIM3部分重映射
	/*
	*查看数据手册,引脚的定时器通道是完全映射,还是部分映射
	*二者调用参数不相同
	*完全映射 :GPIO_FullRemap_TIM4
	*部分映射 :GPIO_PartialRemap_TIM4
	*/
//	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM4,ENABLE);
	
	//设置该引脚为复用输出功能
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	//初始化TIM4
	TIM_TimeBaseStruct.TIM_Period = arr;//重装载值 
	TIM_TimeBaseStruct.TIM_Prescaler = psc;//预分频值 
	TIM_TimeBaseStruct.TIM_ClockDivision = 0; //时钟分频1、2、4分频	
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;//设置计数模式
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStruct);
	
	//初始化输出比较参数
	TIM_OCInitTypeStruct.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式
	TIM_OCInitTypeStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
	TIM_OCInitTypeStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性
	TIM_OC1Init(TIM4,&TIM_OCInitTypeStruct); //根据TIMX的参数设定初始化外设 TIMX OC2,TIMX OC3....
	
	//使能预装载寄存器
	TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);
	
	//使能定时器
	TIM_Cmd(TIM4,ENABLE);
}

timx.h

#ifndef _timx_H
#define _timx_H

#include "system.h"


void MY_TIM3_PWM_Init(u16 arr,u16 psc);
void TIM4_CH1_PWM_Init(u16 arr,u16 psc);
#endif

主函数文章来源地址https://www.toymoban.com/news/detail-646011.html


int main(){
		u16 i=0;
		u8 fx=0;
		SysTick_Init(72);	    	 //延时函数初始化	  
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
		USART1_Init(115200);	 	//串口初始化为115200
		LED_Init();		  		//初始化与LED连接的硬件接口
		TFTLCD_Init();	
		FRONT_COLOR=RED;//设置字体为红色 
		LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,"PRECHIN STM32F1");	
		LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,"PWM CARD TEST");	


	
	
	//例如:STM32F103的主频为 72M
	//按如上设置可知
	//ARR = 100 -1
	//PSC = 72-1
	//所以 Fpwm = 72M/(100*72)= 10kHz 也就是 1/100k S = 100us
	//Fpwm = 主频 / ((ARR+1)*(PSC+1))(单位:Hz)
	//MY_TIM3_PWM_Init(1999,719);//PWM频率=72000000/(719+1)/(1999+1)=50hz=20m
	MY_TIM3_PWM_Init(500,72-1); //频率是2Kh
	
//	TIM_SetCompare4(TIM3,50);
	while(1)
		{
			

			
			//-90度
	//	TIM_SetCompare2(TIM3,1750);//占空比(2000-1750)/2000*20ms=2.5ms
 
//		//45度
//		TIM_SetCompare1(TIM3,1800);//占空比(2000-1800)/2000*20ms=2ms
// 
//		//0度
//		TIM_SetCompare1(TIM3,1850);//占空比(2000-1850)/2000*20ms=1.5ms
// 
//		//-45度
//		TIM_SetCompare1(TIM3,1900);//占空比(2000-1900)/2000*20ms=1ms
// 
//		//-90度
//		TIM_SetCompare1(TIM3,1945);//占空比(2000-1945)/2000*20ms=0.5ms

		if(fx==0)
		{
			i++;
			if(i==300)
			{
				fx=1;
			}
		}
		else
		{
			i--;
			if(i==0)
			{
				fx=0;
			}
		}
		TIM_SetCompare2(TIM3,i);  //i值最大可以取499,因为ARR最大值是499.
		delay_ms(10);	
	};
}

到了这里,关于学习stm32 pwm 多路舵机的控制(PWM 的频率的理解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 12.[STM32]PWM脉宽调制-舵机控制(一篇足以)

    🍌 🍌🍌 作者简介:大家好啊,我叫DW,每天分享一些我新学到的知识,期待和大家一起进步 🍋 🍋🍋 系列专栏: STM32 🍎 🍎🍎 🍎🍎🍎 🌞小实验目标:控制舵机旋转🌞 🍊如有写得不好的地方欢迎大家指正🍊 创作时间:🍊🍊🍊2022年5月2日🍊🍊🍊 在机器人机电控

    2023年04月15日
    浏览(40)
  • 蓝桥杯STM32 G431 hal库开发速成——按键+PWM综合案例——按键控制PWM驱动舵机

    适用于学习了TIM输出比较(PWM)跟GPIO输入(按键)的新手作为练习的综合项目! PWM(Pulse Width Modulation,脉冲宽度调制)是一种常用的技术,用于通过调节电信号的脉冲宽度(即脉冲的持续时间)来控制模拟系统的电源。在数字电子系统中,由于只能输出固定的高(通常为

    2024年01月21日
    浏览(60)
  • 【STM32单片机】STM32控制SG90舵机的PWM部分参数的设置解答

    我们要知道,SG90舵机接收的PWM信号的参数:f=50Hz,T=1/f,所以周期为20ms。 当高电平的脉宽在0.5ms-2.5ms之间时舵机就可以对应旋转到不同的角度。 换句话说,我们要用单片机产生一个 周期(20ms) 的PWM波,然后获得对应这些时长(分别是 0.5ms 、 1ms 、 1.5ms 、 2ms 、 2.5ms )的 高电

    2024年02月13日
    浏览(57)
  • 基于HAL库的STM32单定时器多路输入捕获测量PWM的频率和占空比实现(状态机方式实现)

    目录  写在前面 先回顾下定时器的单路捕获PWM 多路捕获PWM的频率和占空比(状态机实现) 我的思路: 状态图 配置 给出示例代码 测试效果         先有了这篇文章实现了单定时器的多通道测量频率,以外部时钟的方式可测量任意频率的方波),奈何不能多路测试PWM波的频率,

    2024年02月12日
    浏览(51)
  • stm32HAL库学习笔记----pwm驱动舵机

    目录 一、目标 二、准备 三、原理 四、cubemx 五、程序 实现stm32驱动舵机旋转0°,45°,90°,135°,180°等角度。 stm32f103(c8t6),舵机(SG90 9g),杜邦线 接线:舵机红线-----------5V(mcu)            舵机棕线-----------GND(mcu)            舵机黄线-----------PA1(视情况而定

    2023年04月26日
    浏览(38)
  • STM32CubeIDE学习笔记——使用HAL库PWM输出驱动舵机

    目录 PWM驱动简介 工程配置 代码编写 这里我采用的是STM32F103C8T6最小系统板,SG-90舵机实现功能。 舵机驱动角度和PWM占空比有关系,具体对应为50--0度  150--90度  250--180度,通过STM32的定时器功能输出PWM波来控制舵机进行转动。  时钟选择外部高速时钟 系统映射配置 时钟树设

    2024年02月13日
    浏览(43)
  • STM32 CubeMX学习实验13:定时器输入捕获获取PWM频率

    使用定时器5作为输入捕获定时器,将通道1(PA0)设置为输入捕获,设置预分频器和计数值,这里设置为1us计数一次,最大可以捕获周期为0xFFFFFFFFus的PWM,所以一般不需要考虑溢出的问题,使能自动重装载。 使能定时器中断,选择合适的优先级,   将引脚设置下拉,保证没

    2024年03月14日
    浏览(66)
  • 10、江科大stm32视频学习笔记——PWM驱动led呼吸灯、驱动舵机、驱动直流机

    目录 一、PWM驱动LED呼吸灯(灯接在PA0) 1、PWM波和GPIO的对应关系参考引脚定义表 2、计数器的计算 3、TIM输出PWM波使用步骤​编辑 4、代码 (1)输出化比较单元 (2) PWM.c (3)main.c 5、重映射更换成PA15亮灯 二、PWM驱动舵机(舵机接在PA1、按键在PB1)  1、电路图 2、参数计算

    2024年02月14日
    浏览(41)
  • 【STM32学习】——定时器输出比较功能&PWM脉宽调制&通用/高级定时器输出比较通道&舵机/直流电机简介&PWM驱动呼吸灯/舵机/直流电机代码实操

    声明:学习笔记根据b站江科大自化协stm32入门教程编辑,仅供学习交流使用!

    2024年02月03日
    浏览(58)
  • 【概念理解】单片机控制舵机之PWM波参数的设置

    我们要知道,SG90舵机接收的PWM信号的参数:f=50Hz,T=1/f,所以周期为20ms。 当高电平的脉宽在0.5ms-2.5ms之间时舵机就可以对应旋转到不同的角度。 换句话说,我们要用单片机产生一个 周期(20ms) 的PWM波,然后获得对应这些时长(分别是 0.5ms 、 1ms 、 1.5ms 、 2ms 、 2.5ms )的 高电

    2024年02月10日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包