赞
踩
自己一路走来,关于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. 凭良心发布,如果对你有所帮助的话,也希望你能点个赞,我们各取所需,你的鼓励是我持续推进的动力。
2.自己需要几路PWM输出,只需要注释相关引脚和通道即可,在使用过程中注意看好按键低电平触发引脚是哪四个;另注意舵机的供电得是平稳的5V直流电压,期待你的丝滑移植。
2、CSDN免费下载:
免费分享、良心发布、赞后启用
3、Gitee免费下载:
https://gitee.com/ha-city/STM32F103C8T6.git
1、2022/07/31 完成基础框架搭建。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。