STM32F407ZGT6控制舵机(采用高级定时器8)

前言

32单片机给舵机供电不足,会出现不稳定的情况(舵机鬼畜);所以要外加电源给舵机供电,利用12v锂电池,通过稳压模块降压到5.5v,提供给舵机。稳压电路的gnd一定要接上32单片机的gnd,不共地虽然能供电但数据线无法传输数据。

stm32的高级定时器8的通道一连接PC6,通道二连接PC7.

ServorCtrlAngle(2,45);	

此主函数的语句,2选择通道2,所以数据线接PC7。

main.c 代码

注意,有相当部分代码是实现其他功能的,无关驱动舵机的。

#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "oled.h"
#include "extizd.h"
#include "BaseTimX.h"
#include "htimx.h"


int int1=10;
int int2=12;

float float1=1.5;
float float2=10.25;

void oledPage0()
{
	 OLED_ShowChar(0,0,'Z');
	 OLED_ShowChar(1*8,0,'P');
	OLED_ShowChar(2*8,0,'0');

	 OLED_ShowChar(4*8,0,'F');
	 OLED_ShowChar(5*8,0,'P');
	 OLED_ShowChar(6*8,0,'0');

	
		OLED_ShowChar(0*8,1,'Z');
		OLED_ShowChar(1*8,1,'S');
		OLED_ShowChar(2*8,1,'1');
		OLED_ShowChar(3*8,1,'0');
		OLED_ShowChar(4*8,1,'0');
		OLED_ShowChar(5*8,1,'0');
	
	  OLED_ShowChar(6*8,1,'F');
		OLED_ShowChar(7*8,1,'S');
	 OLED_ShowChar(8*8,1,'0');
		OLED_ShowChar(9*8,1,'.');
	 OLED_ShowChar(10*8,1,'0');
		OLED_ShowChar(11*8,1,'1');
		
	 OLED_ShowChar(0,2,'k');
	 OLED_ShowChar(1*8,2,'m');
	 OLED_ShowChar(2*8,2,'0');

	 OLED_ShowChar(4*8,2,'a');
	 OLED_ShowChar(5*8,2,'s');
	 OLED_ShowChar(6*8,2,'0');
	 
	 	 OLED_ShowChar(0*8,3,'z');
	 OLED_ShowChar(1*8,3,'s');
	 OLED_ShowChar(2*8,3,'0');
		OLED_ShowChar(3*8,3,'=');
		 
		 
	 OLED_ShowChar(0*8,4,'x');
	 OLED_ShowChar(1*8,4,'s');
	 OLED_ShowChar(2*8,4,'0');
	 OLED_ShowChar(3*8,4,'=');
}



int main(void)
{
	u8 KeyVal=0;
	
	u32 intnum=0;
	float a=123.456;
	int i=0;

	delay_init(168); 
	LED_Init();
	BEEP_Init();//初始化 	
	
	KEY_Init();
	OLED_Init();
	delay_ms(5);
	OLED_Clear();
	
	KeyModeFlag=0;

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	oledPage0();
	BaseTimx_Init();
	TIM_Cmd(BASIC_TIM6, ENABLE);


	HTim8_Init();//初始化函数中,加一时间是1us,1000---1us===1ms
	
	TIM_Cmd(TIM8, ENABLE);

	HTim8_SetPwmFreq(50);//用定时器8控制舵机,需要频率是50HZ(周期是20ms)

	while(1)
	{
		ServorCtrlAngle(2,0);
		delay_ms(3000);
		ServorCtrlAngle(2,45);		
		delay_ms(1000);
		
		ServorCtrlAngle(2,90);		
		delay_ms(3000);
		ServorCtrlAngle(2,180);		
		delay_ms(3000);
		ServorCtrlAngle(2,270);		
		delay_ms(3000);
//		
//		ServorCtrlAngle(2,0);		
//		LED0=!LED0;
//		delay_ms(300);
//		LED0=!LED0;
//		delay_ms(300);
//		LED0=!LED0;
//		delay_ms(300);
//		LED0=!LED0;
//		delay_ms(300);
//		delay_ms(1000);


//		ServorCtrlAngleNP(1,0);
//		delay_ms(1000);
//		
//		ServorCtrlAngleNP(1,-90);
//		delay_ms(1000);
//		
//		ServorCtrlAngleNP(1,-45);
//		delay_ms(1000);
//		
//		
//		ServorCtrlAngleNP(1,-20);
//		delay_ms(1000);
//		
//		ServorCtrlAngleNP(1,0);
//		delay_ms(1000);
//		
//		ServorCtrlAngleNP(1,20);
//		delay_ms(1000);
//		
//		ServorCtrlAngleNP(1,50);
//		delay_ms(1000);
//		
//		
//		ServorCtrlAngleNP(1,90);
//		delay_ms(2000);
		
//		TIM_SetCompare1(TIM8,100);	//=======修改比较值,修改占空比
//		TIM_SetCompare2(TIM8,0);	//=======修改比较值,修改占空比
//		
//		
//		
//		
//		TIM_SetCompare1(TIM8,0);	//=======修改比较值,修改占空比
//		TIM_SetCompare2(TIM8,1000);	//=======修改比较值,修改占空比
//		
//		delay_ms(10);
		

		
		
		
		
		KeyVal=KeyScan1(KeyModeFlag);
		switch(KeyVal)
		{
			case Key4ShortClickVal: //整数加或者减
				if(FlagKeyAddSub==0)
				{
					switch(FlagIntParIndex)
					{
						case ParInt1:
							int1=int1+StepIntArray[StepIntIndex];
							if(int1>10000)int1=10;
						
							OLED_ShowNum(4*8,3,int1,5,12);

							break;
						
						case ParInt2:
							int2=int2+StepIntArray[StepIntIndex];
							if(int2>10000)int2=10;
							OLED_ShowNum(4*8,3,int2,5,12);

							break;
						
						
					}
				}
				else if(FlagKeyAddSub==1)
				{
					switch(FlagIntParIndex)
					{
						case ParInt1:
						
							if(int1<2)int1=10000;
							int1=int1-StepIntArray[StepIntIndex];
							OLED_ShowNum(4*8,3,int1,5,12);
					
							break;
						
						case ParInt2:
							if(int2<2)int2=10000;
							int2=int2-StepIntArray[StepIntIndex];
							OLED_ShowNum(4*8,3,int2,5,12);

							break;
						
						
					}
				}
				
				break;
			
			case Key4LongClickVal://长按调节整数的步长
				while(KEY4==0){};
				StepIntIndex++;
				if(StepIntIndex>=5)StepIntIndex=0;
				 OLED_ShowChar(2*8,1,' ');
				OLED_ShowChar(3*8,1,' ');
				OLED_ShowChar(4*8,1,' ');
				OLED_ShowChar(5*8,1,' ');	
				OLED_ShowNum(2*8,1,StepIntArray[StepIntIndex],4,12);

				break;
			//---------------------
			case Key5ShortClickVal://浮点数加或者减
					if(FlagKeyAddSub==0)
						{
								switch(FlagFloatParIndex)
								{
									case ParFloat1:
											float1=float1+StepFloatArray[StepFloatIndex];
											if(float1>1000.0f)float1=10.0f;
										
											OLED_ShowFloat(4*8,4,float1,2);
										break;
									
									case ParFloat2:
										float2=float2+StepFloatArray[StepFloatIndex];
										if(float2>1000.0f)float2=10.0f;
										OLED_ShowFloat(4*8,4,float2,2);
										break;
									
									
								}
						}
						else if(FlagKeyAddSub==1)
						{
							switch(FlagFloatParIndex)
								{
									case ParFloat1:
										if(float1<10.0f)float1=1000.0f;
										float1=float1-StepFloatArray[StepFloatIndex];
										OLED_ShowFloat(4*8,4,float1,2);
										break;
									
									case ParFloat2:
										if(float2<10.0f)float2=1000.0f;
										float2=float2-StepFloatArray[StepFloatIndex];
										OLED_ShowFloat(4*8,4,float2,2);
										break;
									
									
								}
						}
			
			
				break;
			
			case Key5LongClickVal://长按调节小数的步长
				while(KEY5==0){};
				StepFloatIndex++;
				if(StepFloatIndex>=5)StepFloatIndex=0;
				OLED_ShowChar(8*8,1,' ');
				OLED_ShowChar(9*8,1,' ');
				OLED_ShowChar(10*8,1,' ');
				OLED_ShowChar(11*8,1,' ');	
				OLED_ShowFloat(8*8,1, StepFloatArray[StepFloatIndex],2);	
					
				break;
			//---------------------
			case Key6ShortClickVal:
				
				break;
			
			case Key6LongClickVal://调节int参数号
				while(KEY6==0){};
				FlagIntParIndex++;
				if(FlagIntParIndex>=2)FlagIntParIndex=0;
				OLED_ShowNum(2*8,0,FlagIntParIndex,1,12);
				OLED_ShowNum(2*8,3,FlagIntParIndex,1,12);
				break;
			
			//--------------------
			case Key7ShortClickVal://启动
				
				break;
			
			case Key7LongClickVal://float 参数号
				while(KEY7==0){};
				FlagFloatParIndex++;
				if(FlagFloatParIndex>=2)FlagFloatParIndex=0;
				OLED_ShowNum(6*8,0,FlagFloatParIndex,1,12);
				OLED_ShowNum(2*8,4,FlagFloatParIndex,1,12);

				break;
			
			//---------------------
			case Key8ShortClickVal://切换连续模式或者是单按长按模式
				while(KEY8==0){};
				if(KeyModeFlag==0)KeyModeFlag=1;
				else if(KeyModeFlag==1)KeyModeFlag=0;
					
				OLED_ShowNum(2*8,2,KeyModeFlag,1,12);
				
				break;
			
			case Key8LongClickVal://保留
				while(KEY8==0){};	
				if(FlagKeyAddSub==0)FlagKeyAddSub=1;
				else if(FlagKeyAddSub==1)FlagKeyAddSub=0;
					
				if(FlagKeyAddSub==0)
					OLED_ShowChar(6*8,2,'A');
				else if(FlagKeyAddSub==1)
					OLED_ShowChar(6*8,2,'S');
				
		//		OLED_ShowNum(6*8,2,FlagKeyAddSub,1,12);
	
				break;
		
		}
		
		
		
	
	}
}

htim.c code

#include "htimx.h"

u32 Global_Timer8_Arr=100;

void HTIM8_GPIO_Config(void)
{
	/* 定义一个 GPIO_InitTypeDef 类型的结构体 */
 GPIO_InitTypeDef GPIO_InitStructure;
/* 开启定时器相关的 GPIO 外设时钟 */
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//?? GPIOC ??	/* 指定引脚复用功能 */
	
 GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8);
 GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8);
	
	
	/* 定时器功能引脚初始化 */
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	
 GPIO_Init(GPIOC, &GPIO_InitStructure);
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
 
 GPIO_Init(GPIOC, &GPIO_InitStructure);

}

void HTim8Mode_Init(void)//初始化
{
	TIM_TimeBaseInitTypeDef 	TIM_TimeBaseStructure;
	TIM_OCInitTypeDef 				TIM_OCInitStructure;
	// 开启 TIMx_CLK
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
	
	/* 累计 TIM_Period 个后产生一个更新或者中断 */
	//当定时器从 0 计数到 4999,即为 5000 次,为一个定时周期
	Global_Timer8_Arr=1000;
	TIM_TimeBaseStructure.TIM_Period = Global_Timer8_Arr-1;
//定时器时钟源 TIMxCLK =168MHz
 // 设定定时器频率为 =TIMxCLK/(TIM_Prescaler+1)=168/(168-1+1)=1MHz
	TIM_TimeBaseStructure.TIM_Prescaler = 168-1;//1us加一次
	
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
	// 初始化定时器 TIMx
	TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
	
	
	
	/* ================== 输出结构体初始化 =================== */
 // 配置为 PWM 模式 1,先输出高电平,达到比较值的时候再改变电平
 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
 // 主输出使能
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
 // 互补输出使能
 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
 // 配置比较值
 TIM_OCInitStructure.TIM_Pulse = 500;
 // 主输出高电平有效
 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
 // 互补输出高电平有效
 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
 // 主输出在被禁止时为高电平
 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
 // 互补输出在被禁止时为低电平
 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
 // 通道初始化
 
	TIM_OC1Init(TIM8, &TIM_OCInitStructure);
	// 使能通道重装载
   TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);
	 
	//定时8第二通道的设置和第一通道CH1一样;
	TIM_OC2Init(TIM8, &TIM_OCInitStructure);
	// 使能通道重装载
   TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);
	 

//	/* ================ 断路和死区结构体初始化 ================ */
// // 自动输出使能,断路、死区时间和锁定配置
// TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
// TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
// TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
// // 配置死区时间
// TIM_BDTRInitStructure.TIM_DeadTime = 11;
// TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
// // 配置刹车引脚电平,当引脚为配置的电平时,主和互补输出都被禁止
// TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;
// TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
// TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);

	
	// 使能定时器
	TIM_Cmd(TIM8, ENABLE);
	
	// 主动输出使能
	TIM_CtrlPWMOutputs(TIM8, ENABLE);
 
}

void HTim8_Init(void)
{
	HTIM8_GPIO_Config();
	HTim8Mode_Init();
	TIM_Cmd(TIM8, ENABLE);
}

//
//
void HTim8_SetPwmFreq(u32 FreqTemp)
{
	TIM_TimeBaseInitTypeDef 	TIM_TimeBaseStructure;
	Global_Timer8_Arr=1000000/FreqTemp;
	TIM_TimeBaseStructure.TIM_Period = Global_Timer8_Arr-1;
//定时器时钟源 TIMxCLK =168MHz
 // 设定定时器频率为 =TIMxCLK/(TIM_Prescaler+1)=168/(168-1+1)=1MHz
	TIM_TimeBaseStructure.TIM_Prescaler = 168-1;//1us加一次
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
	// 初始化定时器 TIMx
	TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);

	
}


void HTim8_SetPwmDuty(u8 PwmChannelTemp,float DutyTemp)
{
	if(PwmChannelTemp==1)
	{
		TIM_SetCompare1(TIM8,DutyTemp*Global_Timer8_Arr);
	}
	else 	if(PwmChannelTemp==2)
	{
		TIM_SetCompare2(TIM8,DutyTemp*Global_Timer8_Arr);
	}
}


void ServorCtrlAngle(u8 ServoNumTemp, float AngleTemp)
{
	float dutytemp=0;
  float timecal=0;
	u32 cntX=0;
	
	timecal=AngleTemp*Servo1_Delta_TimeMax/Servo1_Delta_AngleMax+0.5;
	cntX=timecal*1000/HTim8AddTimeTick;//乘以1000是因为ms和微秒
	if(ServoNumTemp==1)//连C6
	{
		TIM_SetCompare1(TIM8,cntX);
	}
	else 	if(ServoNumTemp==2)//连C7
	{
		TIM_SetCompare2(TIM8,cntX);
	}
}





void ServorCtrlAngleNP(u8 ServoNumTemp, float AngleTemp)
{
	float dutytemp=0;
  float timecal=0;
	u32 cntX=0;
	AngleTemp=AngleTemp+90;//取中间为0度
	timecal=AngleTemp*Servo1_Delta_TimeMax/Servo1_Delta_AngleMax+0.5;
	cntX=timecal*1000/HTim8AddTimeTick;//乘以1000是因为ms和微秒
	if(ServoNumTemp==1)
	{
		TIM_SetCompare1(TIM8,cntX);
	}
	else 	if(ServoNumTemp==2)
	{
		TIM_SetCompare2(TIM8,cntX);
	}
}

htim.h code

#ifndef __HTIMX_H 
#define __HIMX_H 

#include "sys.h" 

#define H_TIM8							  				TIM8
#define H_TIM8_CLK 					  				RCC_APB2Periph_TIM8 //RCC_APB2Periph_TIM8
#define H_TIM8_UP_TIM13_IRQn					TIM8_UP_TIM13_IRQn
#define H_TIM8_UP_TIM13_IRQHandler 		TIM8_UP_TIM13_IRQHandler

extern u32 Global_Timer8_Arr;


#define Servo1_Delta_AngleMax 270  //0-270度
#define Servo1_Delta_TimeMax 	2

#define HTim8AddTimeTick 	1  //这里是微s单位,1us,因为高级定时器8是168Mhz总线,采用168分频,就是1Mhz,1微妙频率,


void HTim8Mode_Init(void);//初始化 	
void HTIM8_GPIO_Config(void);
void HTim8_Init(void);//初始化 	

void HTim8_SetPwmFreq(u32 FreqTemp);//
//PwmChannelTemp=1是通道1,=2是通道2
//DutyTemp===0-1,,0.1;
void HTim8_SetPwmDuty(u8 PwmChannelTemp,float DutyTemp);//

//说明设置中,高级定时器8是168Mhz总线,采用168分频,就是1Mhz,1微妙频率,
//舵机计算次数是加一时间是1us一次,加到20ms周期,就是20000次。

//注意:如果设置是20us计算一次,那么分频系数是3360----168Mhz/3360=0.05Mhz=20us
void ServorCtrlAngle(u8 ServoNumTemp, float AngleTemp);//0-180度
//这个函数是以ServorCtrlAngle为基础的,主要是以中间为0度,左边为负90度,右边为正90的,就是-90到+90之间,范围
void ServorCtrlAngleNP(u8 ServoNumTemp, float AngleTemp);//取中间为0度,一遍-90,另外一边+90


//*****************一下是定时器器1的设置,用定时器1产生PWM,控制直流电机
//设置的说明:设置定时器的计时滴答是1us,由于是控制直流电机,所以可以设置PWM频率是10K左右;
//PWM2模式
#endif  
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值