前言
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