STM32F103C8T6最小系统16路舵机驱动代码

一、铺垫:

自己一路走来,关于STM32最小系统驱动舵机遇到了太多技术壁垒,自己攻克这个问题之后成功实现了将STM32F103C8T6四个定时器全部用来驱动舵机且 0错误0警告,在我实际测试过程中完全可以达到预期效果。现在由我整理上传,不需要投币、不需要加微型加群或者关注什么的,完全免费的分享出来,只期望后来者在学习这个技术的时候,可以有所参考和借鉴。

      实物连接如下

在这里插入图片描述

      基础原理截图

在这里插入图片描述

二、配套代码如下:

/******************************************************************************************************************************************
2022/04/18     成功实现四个按键控制舵机转向不同角度
2022/04/19     成功实现四个舵机按键触发,写代码没注意舵机极限角度,貌似烧了一个舵机!
               一定要及时备份!!!!
2022/04/20     1、将LED流水灯集成为函数,
               2、之所以采用低电平触发是因为所有单片机刚上电IO都会有一个瞬间的高电平脉冲,此处为了防止误触发
		?
2022.05.14   让舵机初始在相对0度,左右45度执行,防止超行程损坏;依照此来改定时器1PWM输出


2022.05.16     写好了8路舵机代码,大家可以放心使用。如果有帮到你的话,有时间请给我点个赞,让我更有动力去推进这件事情。拜托啦!!!


2022.07.30    基础知识储备:
							TIM1_ETR     PA12            
							TIM1_CH1     PA8            TIM2_CH1_ETR PA0            TIM3_CH1     PA6            TIM4_CH1     PB6 
							TIM1_CH2     PA9            TIM2_CH2     PA1            TIM3_CH2     PA7            TIM4_CH2     PB7
							TIM1_CH3     PA10           TIM2_CH3     PA2            TIM3_CH3     PB0            TIM4_CH3     PB8 
							TIM1_CH4     PA11           TIM2_CH4     PA3            TIM3_CH4     PB1            TIM4_CH4     PB9  
							
		 SG90舵机控制方法:
                         --高电平时间为T1--                          总周期20ms:
                            —— —— —— ——
                           |           |                              高电平时间T1为 0.5ms     舵机转动0°
						   |           |                              高电平时间T1为   1ms     舵机转动45°
		                   |           |                              高电平时间T1为 1.5ms     舵机转动90°
                           |           |                              高电平时间T1为   2ms     舵机转动135°
										—— —— —— —— —— ——            高电平时间T1为 2.5ms     舵机转动180°
                           --------总周期 T2为20ms--------
												 
			代码思路:1、Ctrl + c  然后  Ctrl + v     哈哈哈哈!	             
								
                
								以180度舵机为例定义:高电平时间T1为 1.5ms     舵机转动90°    相对位置为     0°    参数为1850  
								
								相对而言: 高电平时间T1为 0.5ms     舵机转动0°     相对位置为   -90°    参数为1945  
                                高电平时间T1为   1ms     舵机转动45°    相对位置为   -45°    参数为1900  
							    高电平时间T1为 1.5ms     舵机转动90°    相对位置为     0°    参数为1850  
                                高电平时间T1为   2ms     舵机转动135°   相对位置为   +45°    参数为1800  
								高电平时间T1为 2.5ms     舵机转动180°   相对位置为   +90°    参数为1750  
																		 
																		 
		//-90°
		//TIM_SetCompare1(TIM4,1945);//占空比(2000-1945)/2000*20ms=0.5ms 
		
		//-45°
		//TIM_SetCompare1(TIM4,1900);//占空比(2000-1900)/2000*20ms=1ms
		
		//0°
		//TIM_SetCompare1(TIM4,1850);//占空比(2000-1850)/2000*20ms=1.5ms
		
		//+45°
		//TIM_SetCompare1(TIM4,1800);//占空比(2000-1800)/2000*20ms=2ms
		
		//+90°
		//TIM_SetCompare1(TIM4,1750);//占空比(2000-1750)/2000*20ms=2.5ms




2022.07.31			1、机械狗项目需要用到的引脚有:
                          
											*****************					 TIM2_CH1_ETR PA0             *****************	          *****************	 
											*****************					 TIM2_CH2     PA1             TIM3_CH2     PA7            *****************	
											*****************					 *****************	          TIM3_CH3     PB0            TIM4_CH3     PB8 
											TIM1_CH4     PA11          *****************	          TIM3_CH4     PB1            TIM4_CH4     PB9  
											
								2、测试按键IO为:
								
							        KEY0 PAin(4)   	
										  KEY1 PAin(5)	 
										  KEY2 PCin(15)     
										  KEY3 PCin(14)

    实现思路: 1、按键触发检测,依次从定时器1编写到定时器4    成功实现预期目标,继续推进到所需引脚。
		
2022.07.31     顺利完成舵机驱动代码的编写,验证成功,继续推进和MPU6050融合。 
							
2022.07.31     写好了16路舵机代码,大家可以放心使用。如果有帮到你的话,有时间请给我点个赞,让我更有动力去推进这件事情。拜托啦!!!	

               我是B站“简单快乐的123”UP主, 主要推进语音识别和机器人技术,感兴趣的话期待你的关注。

*****************************************************************************************************************************************************************************/
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "key.h"
#include "pwm.h"
#include "pwm1.h"
#include "pwm2.h"
#include "pwm3.h"



 int main(void)
 {
    
    	
	u8 t=0;	  
	delay_init();	    	 //延时函数初始化	  
	LED_Init();		  	 	//初始化与LED连接的硬件接口
	KEY_Init();          	//初始化与按键连接的硬件接口
	
  TIM1_PWM_Init(1999,719);
  TIM2_PWM_Init(1999,719);
  TIM3_PWM_Init(1999,719); 
  TIM4_PWM_Init(1999,719);   //PWM频率=72000000/(719+1)/(1999+1)=50hz=20ms	 
	 
	LED0=0;					//点亮LED
	while(1)
	{
    
    
		t=KEY_Scan(0);		//得到键值
		switch(t)
		{
    
    				 
			case KEY0_PRES:		        //此处将四个通道分别放在四个按键内,在自己设计时,只需要将相应的引脚和通道注释了即可。
		                            
			     TIM_SetCompare1(TIM1,1800);delay_ms(500);LED_Blink_1();       //TIM1_CH1     PA8  
			     TIM_SetCompare1(TIM1,1900);delay_ms(500);LED_Blink_1();
			
			     TIM_SetCompare1(TIM2,1900);delay_ms(500);LED_Blink_1();       // TIM2_CH1_ETR PA0 
			     TIM_SetCompare1(TIM2,1850);delay_ms(500);LED_Blink_1();
			
			     TIM_SetCompare1(TIM3,1800);delay_ms(500);LED_Blink_1();       // TIM3_CH1     PA6  
			     TIM_SetCompare1(TIM3,1900);delay_ms(500);LED_Blink_1();
			
			     TIM_SetCompare1(TIM4,1800);delay_ms(500);LED_Blink_1();       // TIM4_CH1     PB6 
			     TIM_SetCompare1(TIM4,1900);delay_ms(500);LED_Blink_1();					
			
			     
			     break;
			
case KEY1_PRES:		
			                        
			     TIM_SetCompare2(TIM1,1800);delay_ms(500);LED_Blink_2();       //TIM1_CH2     PA9  
			     TIM_SetCompare2(TIM1,1900);delay_ms(500);LED_Blink_2();
			
			     TIM_SetCompare2(TIM2,1900);delay_ms(500);LED_Blink_2();       // TIM2_CH2     PA1  
			     TIM_SetCompare2(TIM2,1850);delay_ms(500);LED_Blink_2();
			
			     TIM_SetCompare2(TIM3,1900);delay_ms(500);LED_Blink_2();       //TIM3_CH2      PA7   
			     TIM_SetCompare2(TIM3,1850);delay_ms(500);LED_Blink_2();
			
				   TIM_SetCompare2(TIM4,1800);delay_ms(500);LED_Blink_2();       // TIM4_CH2     PB7
			     TIM_SetCompare2(TIM4,1900);delay_ms(500);LED_Blink_2(); 
				
			     
	         break;
			
			case KEY2_PRES:	
                               
			     TIM_SetCompare3(TIM1,1800);delay_ms(500);LED_Blink_3();       //TIM1_CH3     PA10  
			     TIM_SetCompare3(TIM1,1900);delay_ms(500);LED_Blink_3();
			
			     TIM_SetCompare3(TIM2,1800);delay_ms(500);LED_Blink_3();       //TIM2_CH3     PA2 
			     TIM_SetCompare3(TIM2,1900);delay_ms(500);LED_Blink_3();		    			     
			
			     TIM_SetCompare3(TIM3,1900);delay_ms(500);LED_Blink_3();       //TIM3_CH3     PB0
			     TIM_SetCompare3(TIM3,1850);delay_ms(500);LED_Blink_3();
			
           TIM_SetCompare3(TIM4,1900);delay_ms(5000);LED_Blink_3();      //TIM4_CH3     PB8 
			     TIM_SetCompare3(TIM4,1850);delay_ms(5000);LED_Blink_3();
	
			     
			     break;
			
			case KEY3_PRES: 	 
				                       
			     TIM_SetCompare4(TIM1,1900);delay_ms(500);LED_Blink_4();      //TIM1_CH4     PA11 
			     TIM_SetCompare4(TIM1,1850);delay_ms(500);LED_Blink_4();
			
			     TIM_SetCompare4(TIM2,1800);delay_ms(500);LED_Blink_4();      //TIM2_CH4     PA3  
			     TIM_SetCompare4(TIM2,1900);delay_ms(500);LED_Blink_4();
			
			     TIM_SetCompare4(TIM3,1900);delay_ms(500);LED_Blink_4();      //TIM3_CH4     PB1 
			     TIM_SetCompare4(TIM3,1850);delay_ms(500);LED_Blink_4();
			
				   TIM_SetCompare4(TIM4,1900);delay_ms(500);LED_Blink_4();      //TIM4_CH4     PB9  
			     TIM_SetCompare4(TIM4,1850);delay_ms(500);LED_Blink_4(); 
					  
			     
					 break;	
			
			default:delay_ms(10);
		} 
	}		 
}

/*****************************************************************************************************************************************************														
基础知识储备:
TIM1_ETR     PA12            
TIM1_CH1     PA8            TIM2_CH1_ETR PA0            TIM3_CH1     PA6            TIM4_CH1     PB6 
TIM1_CH2     PA9            TIM2_CH2     PA1            TIM3_CH2     PA7            TIM4_CH2     PB7
TIM1_CH3     PA10           TIM2_CH3     PA2            TIM3_CH3     PB0            TIM4_CH3     PB8 
TIM1_CH4     PA11           TIM2_CH4     PA3            TIM3_CH4     PB1            TIM4_CH4     PB9  


		 SG90舵机控制方法:
                         --高电平时间为T1--                          总周期20ms:
                           ———————
                           |           |                              高电平时间T1为 0.5ms     舵机转动0°
						   |           |                              高电平时间T1为   1ms     舵机转动45°
						   |           |                              高电平时间T1为 1.5ms     舵机转动90°
						   |           |                              高电平时间T1为   2ms     舵机转动135°
						                —————————             高电平时间T1为 2.5ms     舵机转动180°
                           --------总周期 T2为20ms--------
												 
			代码思路:1、Ctrl + c  然后  Ctrl + v     哈哈哈哈!				

											|                
											|
											|
								--------------
                
								以180度舵机为例定义:高电平时间T1为 1.5ms     舵机转动90°    相对位置为     0°    参数为1850  
								
								           相对而言:高电平时间T1为 0.5ms     舵机转动0°     相对位置为   -90°    参数为1945  
                                                     高电平时间T1为   1ms     舵机转动45°    相对位置为   -45°    参数为1900  
							                         高电平时间T1为 1.5ms     舵机转动90°    相对位置为     0°    参数为1850  
                                                     高电平时间T1为   2ms     舵机转动135°   相对位置为   +45°    参数为1800  
											         高电平时间T1为 2.5ms     舵机转动180°   相对位置为   +90°    参数为1750  
																		 
																		 
																		 
		//-90°
		//TIM_SetCompare1(TIM4,1945);//占空比(2000-1945)/2000*20ms=0.5ms 
		
		//-45°
		//TIM_SetCompare1(TIM4,1900);//占空比(2000-1900)/2000*20ms=1ms
		
		//0°
		//TIM_SetCompare1(TIM4,1850);//占空比(2000-1850)/2000*20ms=1.5ms
		
		//+45°
		//TIM_SetCompare1(TIM4,1800);//占空比(2000-1800)/2000*20ms=2ms
		
		//+90°
		//TIM_SetCompare1(TIM4,1750);//占空比(2000-1750)/2000*20ms=2.5ms
	
	
	A8  A9  A10  A11
*******************************************************************************/

#include "pwm1.h"

//TIM4 PWM部分初始?
//PWM输出初始化
//arr:自动重装载值        psc:时钟预分频数



/******************************************************************************
* 模块描述
* 项目代号或名称 :  8路PWM输出
* 创建日期       :  2022/05/14
* 创建人         :  志城
* 模块功能       :  
* 修改日期       :
* 参考文档       :  精通STM32F4库函数版
* 项目运行平台   :  STM32F103C8T6
* 其它           :  PWM的一般步骤
										 实例要求:TIM4来产生PWM输出,并使能TIM4的通道1、2、3、4,逐个重映射到PB6\PB7\PB8\PB9,产生PWM来控制舵机

											1、使能定时器和相关IO时钟,调用函数:RCC_APB1PeriphClockCmd();RCC_APB2PeriphClockCmd();
											2、初始化IO为复用功能输出,调用函数:GPIO_Init();这里我们把PB6\PB7\PB8\PB9用作定时器的PWM输出引脚,要重映射配置即GPIO_Mode_AF_PP;
											   复用推挽输出;所以需要开启AFIO时钟。
												 
											3、初始化定时器,调用函数:TIM_TimeBaseInit();
											4、初始化输出比较参数,调用函数:TIM_OCInitStructure();
											5、使能预装载寄存器,调用函数:TIM_OC1PreloadConfig();
											6、使能定时器,调用函数:TIM_Cmd();											
											7、设置舵机初始角度,调用函数:TIM_SetCompare1(TIM4,1945);
											
高级定时器1:	TIM_CtrlPWMOutputs(TIM1,ENABLE);//TIM1输出使能   高级定时器绝对得加上因为这句话我搞了一个晚上,后人戒之慎之
											
											
     设置定时器的PWM输出时需配置	TIM_OCInitTypeDef结构体参数,输入捕获是用TIM_ICInitTypeDef结构体										
typedef struct
{
  uint16_t TIM_OCMode;        

  uint16_t TIM_OutputState;    输出状态
  uint16_t TIM_OutputNState;   互补通道的输出状态
  uint16_t TIM_Pulse;          占空比
  uint16_t TIM_OCPolarity;     输出极性
  uint16_t TIM_OCNPolarity;    互补通道的输出极性
  uint16_t TIM_OCIdleState;    空闲状态
  uint16_t TIM_OCNIdleState;   互补通道的输出状态
} TIM_OCInitTypeDef;

   

*******************************************************************************/
void TIM1_PWM_Init(u16 arr,u16 psc)
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;   					 				//初始化TIM1设置ARR,PSC控制输出PWM的周期
	TIM_OCInitTypeDef  TIM_OCInitStructure;                         //PWM通道设置
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);     			  //使能定时器4
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);      				//AFIO复用功能时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  ,ENABLE);   				//GPIOA使能
	
	
	//设置该引脚为复用输出功能    GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;                                       //此处只用PA11引脚,即TIM1_CH4 通道
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;                                     //复用推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);                                               //初始化GPIO
	
	
	//初始化TIM1,设置TIM4的ARR和PSC
	TIM_TimeBaseStruct.TIM_Period = arr;                   					 //设置自动重装载周期值   //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 
	TIM_TimeBaseStruct.TIM_Prescaler = psc;                					 //设置预分频值           //设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStruct.TIM_ClockDivision = 0;               				 //设置时钟分割TDTS = Tck_tim	
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;         //TIM向上计数模式
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStruct);                      //根据指定参数初始化TIMx  //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	


	
	//初始化出输出比较参数
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                  //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;      //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;          //输出极性:TIM输出比较极性高
	
  TIM_OC1Init(TIM1,&TIM_OCInitStructure);                          //根据TIMX的参数设定初始化外设 TIM1 ch1 ch2 ch3 ch4	
  TIM_OC2Init(TIM1,&TIM_OCInitStructure);
  TIM_OC3Init(TIM1,&TIM_OCInitStructure);
  TIM_OC4Init(TIM1,&TIM_OCInitStructure);
	
	TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);                 //使能预装载寄存器
  TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable);
	TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable);
	TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM1, ENABLE);                                //使能TIMx在ARR上的预装载寄存器	
	
	TIM_CtrlPWMOutputs(TIM1,ENABLE);                                   //TIM1输出使能   高级定时器绝对得加上因为这句话我搞了一个晚上,后人戒之慎之
	
	TIM_Cmd(TIM1,ENABLE);     //使能TIM1
	
	
	//参数设置函数
	//作用:在四个通道中选择一个,设置比较值。通常在初始化函数中已经设置了比较值,此函数用于除初始化之外的修改
  //TIM_SetCompare1(TIM1,1850);
	//TIM_SetCompare2(TIM1,1850);
	//TIM_SetCompare3(TIM1,1850);
	//TIM_SetCompare4(TIM1,1850);
	
	

}




#include "key.h"
#include "delay.h"

    
//按键初始化函数 
//PA15和PC5 设置成输入
void KEY_Init(void)
{
    
    
	
	GPIO_InitTypeDef GPIO_InitStructure;

 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC时钟

	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4;       //PA4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    //设置成上拉输入,平时为高,按下时低电平拉低
 	GPIO_Init(GPIOA, &GPIO_InitStructure);           //初始化GPIOA4
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;        //PA5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     //设置成上拉输入
 	GPIO_Init(GPIOA, &GPIO_InitStructure);             //初始化GPIOA5
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_15;       //PC15
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    //设置成上拉输入,平时为高,按下时低电平拉低
 	GPIO_Init(GPIOC, &GPIO_InitStructure);           //初始化GPIOC15
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_14;        //PC14
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     //设置成上拉输入
 	GPIO_Init(GPIOC, &GPIO_InitStructure);             //初始化GPIOC14
	
	
} 
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//返回值:
//0,没有任何按键按下
//KEY0_PRES,KEY0按下
//KEY1_PRES,KEY1按下
//KEY2_PRES,KEY2按下
//KEY3_PRES,KEY3按下
//注意此函数有响应优先级,KEY0>KEY1>WK_UP!!
u8 KEY_Scan(u8 mode)
{
    
    	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		     
	if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==0))
	{
    
    
		delay_ms(10);//去抖动 
		key_up=0;
		if(KEY0==0)return KEY0_PRES;
		else if(KEY1==0)return KEY1_PRES;
		else if(KEY2==0)return KEY2_PRES;
		else if(KEY3==0)return KEY3_PRES;
		
	}else if(KEY0==1&&KEY1==1&&KEY2==1&&KEY3==1)key_up=1; 	     
	return 0;// 无按键按下
}






#include "led.h"
#include "delay.h"
  

//使能时钟		    
//LED IO初始化
void LED_Init(void)
{
    
    
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	 
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);	 //使能PC端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;				       //PC13 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		   //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		   //IO口速度为50MHz
 GPIO_Init(GPIOC, &GPIO_InitStructure);					         //根据设定参数初始化GPIOPC13
 GPIO_SetBits(GPIOC,GPIO_Pin_13);						             //PC13输出高

}
 

/**************************************************************************
功能描述:等间隔亮灭1次     亮 -- 灭 
入口参数:无
返回值:无
 *************************************************************************/
void LED_Blink_1()
{
    
       
	  GPIO_SetBits(GPIOC,GPIO_Pin_13);     //LED输出高
		delay_ms(100);
		GPIO_ResetBits(GPIOC,GPIO_Pin_13);   //LED输出低
		delay_ms(100);	
	  
	
}


/**************************************************************************
功能描述:等间隔亮灭2次    亮 -- 灭 -- 亮 --灭
入口参数:无
返回值:无
 *************************************************************************/
void LED_Blink_2()
{
    
       
	  GPIO_SetBits(GPIOC,GPIO_Pin_13);     //LED输出高
		delay_ms(200);
		GPIO_ResetBits(GPIOC,GPIO_Pin_13);   //LED输出低
		delay_ms(100);	
	  GPIO_SetBits(GPIOC,GPIO_Pin_13);     //LED输出高
		delay_ms(200);
		GPIO_ResetBits(GPIOC,GPIO_Pin_13);   //LED输出低
		delay_ms(100);
	 
	
}

/**************************************************************************
功能描述:等间隔亮灭3次   亮 -- 灭 -- 亮 --灭
入口参数:无
返回值:无
 *************************************************************************/
void LED_Blink_3()
{
    
       
	  GPIO_SetBits(GPIOC,GPIO_Pin_13);     //LED输出高
		delay_ms(300);
		GPIO_ResetBits(GPIOC,GPIO_Pin_13);   //LED输出低
		delay_ms(100);	
	  GPIO_SetBits(GPIOC,GPIO_Pin_13);     //LED输出高
		delay_ms(300);
		GPIO_ResetBits(GPIOC,GPIO_Pin_13);   //LED输出低
		delay_ms(100);
	  GPIO_SetBits(GPIOC,GPIO_Pin_13);     //LED输出高
		delay_ms(300);
		GPIO_ResetBits(GPIOC,GPIO_Pin_13);   //LED输出低
		delay_ms(100);
	
}

/**************************************************************************
功能描述:等间隔亮灭3次   亮 -- 灭 -- 亮 --灭-- 亮 --灭
入口参数:无
返回值:无
 *************************************************************************/
void LED_Blink_4()
{
    
       
	  LED_Blink_2();
	  LED_Blink_2();
	
}

void LED_Blink_5()
{
    
       
	  LED_Blink_2();
	  LED_Blink_3();
	
}
/*********************************END FILE********************************************/	

#include "pwm2.h"

//TIM4 PWM部分初始?
//PWM输出初始化
//arr:自动重装载值        psc:时钟预分频数



/******************************************************************************
* 模块描述
* 项目代号或名称 :  8路PWM输出
* 创建日期       :  2022/05/14
* 创建人         :  志城
* 模块功能       :  
* 修改日期       :
* 参考文档       :  精通STM32F4库函数版
* 项目运行平台   :  STM32F103C8T6
* 其它           :  PWM的一般步骤
										 实例要求:TIM4来产生PWM输出,并使能TIM4的通道1、2、3、4,逐个重映射到PB6\PB7\PB8\PB9,产生PWM来控制舵机

											1、使能定时器和相关IO时钟,调用函数:RCC_APB1PeriphClockCmd();RCC_APB2PeriphClockCmd();
											2、初始化IO为复用功能输出,调用函数:GPIO_Init();这里我们把PB6\PB7\PB8\PB9用作定时器的PWM输出引脚,要重映射配置即GPIO_Mode_AF_PP;
											   复用推挽输出;所以需要开启AFIO时钟。
												 
											3、初始化定时器,调用函数:TIM_TimeBaseInit();
											4、初始化输出比较参数,调用函数:TIM_OCInitStructure();
											5、使能预装载寄存器,调用函数:TIM_OC1PreloadConfig();
											6、使能定时器,调用函数:TIM_Cmd();											
											7、设置舵机初始角度,调用函数:TIM_SetCompare1(TIM4,1945);
											
高级定时器1:	TIM_CtrlPWMOutputs(TIM1,ENABLE);//TIM1输出使能   高级定时器绝对得加上因为这句话我搞了一个晚上,后人戒之慎之
											
											
     设置定时器的PWM输出时需配置	TIM_OCInitTypeDef结构体参数,输入捕获是用TIM_ICInitTypeDef结构体										
typedef struct
{
  uint16_t TIM_OCMode;        

  uint16_t TIM_OutputState;    输出状态
  uint16_t TIM_OutputNState;   互补通道的输出状态
  uint16_t TIM_Pulse;          占空比
  uint16_t TIM_OCPolarity;     输出极性
  uint16_t TIM_OCNPolarity;    互补通道的输出极性
  uint16_t TIM_OCIdleState;    空闲状态
  uint16_t TIM_OCNIdleState;   互补通道的输出状态
} TIM_OCInitTypeDef;

   
基础知识储备:
TIM1_ETR     PA12            
TIM1_CH1     PA8            TIM2_CH1_ETR PA0            TIM3_CH1     PA6            TIM4_CH1     PB6 
TIM1_CH2     PA9            TIM2_CH2     PA1            TIM3_CH2     PA7            TIM4_CH2     PB7
TIM1_CH3     PA10           TIM2_CH3     PA2            TIM3_CH3     PB0            TIM4_CH3     PB8 
TIM1_CH4     PA11           TIM2_CH4     PA3            TIM3_CH4     PB1            TIM4_CH4     PB9  
*******************************************************************************/
void TIM2_PWM_Init(u16 arr,u16 psc)
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;   					 				//初始化TIM1设置ARR,PSC控制输出PWM的周期
	TIM_OCInitTypeDef  TIM_OCInitStructure;                         //PWM通道设置
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);     			  //使能定时器4
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);      				//AFIO复用功能时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  ,ENABLE);   				//GPIOA使能
	
	
	//设置该引脚为复用输出功能
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;	       //TIM2_CH1/CH2/CH3/CH4
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;                                     //复用推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);                                               //初始化GPIO
	
	
	//初始化TIM1,设置TIM4的ARR和PSC
	TIM_TimeBaseStruct.TIM_Period = arr;                   					 //设置自动重装载周期值   //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 
	TIM_TimeBaseStruct.TIM_Prescaler = psc;                					 //设置预分频值           //设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStruct.TIM_ClockDivision = 0;               				 //设置时钟分割TDTS = Tck_tim	
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;         //TIM向上计数模式
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStruct);                      //根据指定参数初始化TIMx  //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	


	
	//初始化出输出比较参数
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                  //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;      //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;          //输出极性:TIM输出比较极性高
	
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);                            //根据TIMX的参数设定初始化外设 TIM2 ch1 ch2 ch3 ch4	
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);
  TIM_OC4Init(TIM2,&TIM_OCInitStructure);
	
	TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);                   //使能预装载寄存器
  TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);
	TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable);
	TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM2, ENABLE);                                //使能TIMx在ARR上的预装载寄存器	
	
	TIM_CtrlPWMOutputs(TIM2,ENABLE);                                   //TIM1输出使能   高级定时器绝对得加上因为这句话我搞了一个晚上,后人戒之慎之
	
	TIM_Cmd(TIM2,ENABLE);                                              //使能TIM2
	
	
	//参数设置函数
	//作用:在四个通道中选择一个,设置比较值。通常在初始化函数中已经设置了比较值,此函数用于除初始化之外的修改
  //TIM_SetCompare1(TIM2,1850);
	//TIM_SetCompare2(TIM2,1850);
	//TIM_SetCompare3(TIM2,1850);
	//TIM_SetCompare4(TIM2,1850);
	
	

}







#include "pwm3.h"

//TIM4 PWM部分初始?
//PWM输出初始化
//arr:自动重装载值        psc:时钟预分频数
/******************************************************************************
* 模块描述
* 项目代号或名称 :  8路PWM输出
* 创建日期       :  2022/05/14
* 创建人         :  志城
* 模块功能       :  
* 修改日期       :
* 参考文档       :  精通STM32F4库函数版
* 项目运行平台   :  STM32F103C8T6
* 其它           :  PWM的一般步骤
										 实例要求:TIM4来产生PWM输出,并使能TIM4的通道1、2、3、4,逐个重映射到PB6\PB7\PB8\PB9,产生PWM来控制舵机

											1、使能定时器和相关IO时钟,调用函数:RCC_APB1PeriphClockCmd();RCC_APB2PeriphClockCmd();
											2、初始化IO为复用功能输出,调用函数:GPIO_Init();这里我们把PB6\PB7\PB8\PB9用作定时器的PWM输出引脚,要重映射配置即GPIO_Mode_AF_PP;
											   复用推挽输出;所以需要开启AFIO时钟。
												 
											3、初始化定时器,调用函数:TIM_TimeBaseInit();
											4、初始化输出比较参数,调用函数:TIM_OCInitStructure();
											5、使能预装载寄存器,调用函数:TIM_OC1PreloadConfig();
											6、使能定时器,调用函数:TIM_Cmd();											
											7、设置舵机初始角度,调用函数:TIM_SetCompare1(TIM4,1945);
											
高级定时器1:	TIM_CtrlPWMOutputs(TIM1,ENABLE);//TIM1输出使能   高级定时器绝对得加上因为这句话我搞了一个晚上,后人戒之慎之
											
											
     设置定时器的PWM输出时需配置	TIM_OCInitTypeDef结构体参数,输入捕获是用TIM_ICInitTypeDef结构体										
typedef struct
{
  uint16_t TIM_OCMode;        

  uint16_t TIM_OutputState;    输出状态
  uint16_t TIM_OutputNState;   互补通道的输出状态
  uint16_t TIM_Pulse;          占空比
  uint16_t TIM_OCPolarity;     输出极性
  uint16_t TIM_OCNPolarity;    互补通道的输出极性
  uint16_t TIM_OCIdleState;    空闲状态
  uint16_t TIM_OCNIdleState;   互补通道的输出状态
} TIM_OCInitTypeDef;

   
基础知识储备:
TIM1_ETR     PA12            
TIM1_CH1     PA8            TIM2_CH1_ETR PA0            TIM3_CH1     PA6            TIM4_CH1     PB6 
TIM1_CH2     PA9            TIM2_CH2     PA1            TIM3_CH2     PA7            TIM4_CH2     PB7
TIM1_CH3     PA10           TIM2_CH3     PA2            TIM3_CH3     PB0            TIM4_CH3     PB8 
TIM1_CH4     PA11           TIM2_CH4     PA3            TIM3_CH4     PB1            TIM4_CH4     PB9  

*******************************************************************************/
void TIM3_PWM_Init(u16 arr,u16 psc)
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;   					 				//初始化TIM1设置ARR,PSC控制输出PWM的周期
	TIM_OCInitTypeDef  TIM_OCInitStructure;                         //PWM通道设置
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);     			  //使能定时器4
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);      				//AFIO复用功能时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB ,ENABLE);   				//GPIOA、B使能
	
	
	//设置该引脚为复用输出功能
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	       //TIM1_CH1/CH2
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;                                     //复用推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);                                               //初始化GPIO
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	       //TIM3_CH3/CH4
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;                                     //复用推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);                                               //初始化GPIO
	
	
	//初始化TIM1,设置TIM4的ARR和PSC
	TIM_TimeBaseStruct.TIM_Period = arr;                   					 //设置自动重装载周期值   //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 
	TIM_TimeBaseStruct.TIM_Prescaler = psc;                					 //设置预分频值           //设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStruct.TIM_ClockDivision = 0;               				 //设置时钟分割TDTS = Tck_tim	
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;         //TIM向上计数模式
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);                      //根据指定参数初始化TIMx  //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	


	
	//初始化出输出比较参数
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                  //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;      //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;          //输出极性:TIM输出比较极性高
	
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);                            //根据TIMX的参数设定初始化外设 TIM1 ch1 ch2 ch3 ch4	
	TIM_OC2Init(TIM3,&TIM_OCInitStructure);
	TIM_OC3Init(TIM3,&TIM_OCInitStructure);
  TIM_OC4Init(TIM3,&TIM_OCInitStructure);
	
	TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);                   //使能预装载寄存器
  TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
	TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);
	TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM3, ENABLE);                                 //使能TIMx在ARR上的预装载寄存器	
	
	TIM_CtrlPWMOutputs(TIM3,ENABLE);//TIM1输出使能   高级定时器绝对得加上因为这句话我搞了一个晚上,后人戒之慎之
	
	TIM_Cmd(TIM3,ENABLE);     //使能TIM1
	
	
	//参数设置函数
	//作用:在四个通道中选择一个,设置比较值。通常在初始化函数中已经设置了比较值,此函数用于除初始化之外的修改
  //TIM_SetCompare1(TIM3,1850);
	//TIM_SetCompare2(TIM3,1850);
	//TIM_SetCompare3(TIM3,1850);
	//TIM_SetCompare4(TIM3,1850);
	
	

}




#include "pwm.h"

//TIM4 PWM部分初始?
//PWM输出初始化
//arr:自动重装载值        psc:时钟预分频数


/******************************************************************************
* 模块描述
* 项目代号或名称 :  8路PWM输出
* 创建日期       :  2022/05/14
* 创建人         :  志城
* 模块功能       :  
* 修改日期       :
* 参考文档       :  精通STM32F4库函数版
* 项目运行平台   :  STM32F103C8T6
* 其它           :  PWM的一般步骤
										 实例要求:TIM4来产生PWM输出,并使能TIM4的通道1、2、3、4,逐个重映射到PB6\PB7\PB8\PB9,产生PWM来控制舵机

											1、使能定时器和相关IO时钟,调用函数:RCC_APB1PeriphClockCmd();RCC_APB2PeriphClockCmd();
											2、初始化IO为复用功能输出,调用函数:GPIO_Init();这里我们把PB6\PB7\PB8\PB9用作定时器的PWM输出引脚,要重映射配置即GPIO_Mode_AF_PP;
											   复用推挽输出;所以需要开启AFIO时钟。
												 
											3、初始化定时器,调用函数:TIM_TimeBaseInit();
											4、初始化输出比较参数,调用函数:TIM_OCInitStructure();
											5、使能预装载寄存器,调用函数:TIM_OC1PreloadConfig();
											6、使能定时器,调用函数:TIM_Cmd();											
											7、设置舵机初始角度,调用函数:TIM_SetCompare1(TIM4,1945);
															
基础知识储备:
TIM1_ETR     PA12            
TIM1_CH1     PA8            TIM2_CH1_ETR PA0            TIM3_CH1     PA6            TIM4_CH1     PB6 
TIM1_CH2     PA9            TIM2_CH2     PA1            TIM3_CH2     PA7            TIM4_CH2     PB7
TIM1_CH3     PA10           TIM2_CH3     PA2            TIM3_CH3     PB0            TIM4_CH3     PB8 
TIM1_CH4     PA11           TIM2_CH4     PA3            TIM3_CH4     PB1            TIM4_CH4     PB9  

					
//TIM3部分重映射
	
	*查看数据手册,引脚的定时器通道是完全映射,还是部分映射
	*二者调用参数不相同
	*完全映射 :GPIO_FullRemap_TIM4
	*部分映射 :GPIO_PartialRemap_TIM4
	*
   
	//设置TIM4_CH1重映射到PB6上
  //GPIO_PinRemapConfig(GPIO_PartialRemap_TIM4,ENABLE);
*******************************************************************************/


void TIM4_PWM_Init(u16 arr,u16 psc)
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;   					 				//初始化TIM4设置ARR,PSC控制输出PWM的周期
	TIM_OCInitTypeDef  TIM_OCInitStructure;                         //PWM通道设置
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);     			  //使能定时器4
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);      				//AFIO复用功能时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  ,ENABLE);   				//GPIOB使能
	
	
	//设置该引脚为复用输出功能
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;	       //TIM4_CH1/CH2/CH3/CH4
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;                                   //复用推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);                                             //初始化GPIO
	
	
	//初始化TIM4,设置TIM4的ARR和PSC
	TIM_TimeBaseStruct.TIM_Period = arr;                   					 //设置自动重装载周期值   //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 
	TIM_TimeBaseStruct.TIM_Prescaler = psc;                					 //设置预分频值           //设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStruct.TIM_ClockDivision = 0;               				 //设置时钟分割TDTS = Tck_tim	
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;         //TIM向上计数模式
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStruct);                      //根据指定参数初始化TIMx  //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	
	
	
	//输出初始化函数,选择四个通道,初始化PWM输出模式、比较输出极性、 比较输出使能、 比较值CCRx的值
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                  //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;      //比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;                                 //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;          //输出极性:TIM输出比较极性高
	
	TIM_OC1Init(TIM4,&TIM_OCInitStructure);                            //根据TIMX的参数设定初始化外设 TIM1 ch1 ch2 ch3 ch4	
	TIM_OC2Init(TIM4,&TIM_OCInitStructure);
	TIM_OC3Init(TIM4,&TIM_OCInitStructure);
  TIM_OC4Init(TIM4,&TIM_OCInitStructure);

	
	TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);  //使能预装载寄存器
  TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable);
	TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable);
	TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM4, ENABLE); //使能TIMx在ARR上的预装载寄存器	
	
	TIM_Cmd(TIM4,ENABLE);     //使能TIM4
	
	
	//参数设置函数
	//作用:在四个通道中选择一个,设置比较值。通常在初始化函数中已经设置了比较值,此函数用于除初始化之外的修改
	//TIM_SetCompare1(TIM4,1850);
	//TIM_SetCompare2(TIM4,1850);
	//TIM_SetCompare3(TIM4,1850);
	//TIM_SetCompare4(TIM4,1850);
	
	

}









三、常见问题:

1、舵机没反应:
1. 电压不是5V直流稳压。
2. 按键引脚选择不对,注意是低电平触发。
3. 舵机接线引脚和代码输出引脚不匹配,或舵机坏了。

2、舵机抽搐或发抖:
1.电源不稳。
2. 多个舵机同时工作导致电压不稳。

3、舵机只动了一下就没反应了:

  1. 超行程损毁,

四、下载链接:

1、使用寄语:
1. 凭良心发布,如果对你有所帮助的话,也希望你能点个赞,我们各取所需,你的鼓励是我持续推进的动力。

2.自己需要几路PWM输出,只需要注释相关引脚和通道即可,在使用过程中注意看好按键低电平触发引脚是哪四个;另注意舵机的供电得是平稳的5V直流电压,期待你的丝滑移植。

2、CSDN免费下载:
免费分享、良心发布、赞后启用

3、Gitee免费下载:
https://gitee.com/ha-city/STM32F103C8T6.git

五、更新日志:

1、2022/07/31 完成基础框架搭建。

猜你喜欢

转载自blog.csdn.net/weixin_44503286/article/details/126085084