你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的PWM舵机控制经验分享

[复制链接]
攻城狮Melo 发布时间:2023-9-21 14:07
PWM舵机控制+ R) A; }: S$ _) W7 Y" P4 @8 M
8 {+ r) r! e" @
硬件清单
  • 180°舵机
  • 270°舵机
  • 360°舵机
  • STM/GD32F103C8T6核心板
  • 杜邦线' Z- B: r! I. w. |
: G1 N, `' h1 C- B6 x* `( O
硬件接线

" J3 g: z+ Y& u6 b9 T! ^
: y% V% T0 N% A: k/ e. ]0 g
(KJ87HQKEAR50GMANL~TDZV.png
5 X9 A# |1 p* Q! u
一、标准/连续旋转舵机
2 A% k1 S; Z4 T/ B5 D% APWM舵机的控制原理基于脉宽调制技术。
) N# W! H% F. D1、标准舵机(180°/270°)
  • 具有固定的角度范围
  • 精确控制角度位置
    7 q. U; ~: {" D; _% l- f
通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机旋转的角度2、连续旋转舵机(360°)& D% ^9 Q; f' I! H2 c
6 Y* \5 h& q- m( V
  • 控制旋转速度和方向0 R+ t0 q+ }* ~3 E
  • 实现无限制的连续旋转8 `6 D# t4 v; |6 i9 n

) B5 V' k- I8 E- g. R) A

3 W0 M5 d! p  a' j8 v. h* L通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机的速度和方向
. c  O7 N% E1 d1 z* Z) w, s

# d1 q, L% X  V; e二、舵机控制思路/ w! e* e& ?$ l# Q
控制信号以固定频率的方波形式发送给舵机;这个方波的周期通常为20ms,即50Hz的频率;
4 [* B. _7 d8 e/ z& }在控制信号中,脉冲的高电平时间决定舵机旋转的角度或旋转速度和方向。
- r( Q, f. g- X0 G# z
7 k* G+ l( V/ A+ x4 |5 I

3 K. u2 B: N/ e8 J @E`Y[AZ1G_FO2[ZDGV6E_A3.png
. H9 E# n# Q! ]& u4 l
: R0 J# ^9 {& G# C/ X
三、PWM实现思路
1、时钟使能
  1. //TIM3时钟使能
    8 \4 G' Y+ }% ~( _
  2. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);: A4 M' o3 r- y
  3. //使能GPIOB端口时钟和AFIO时钟6 k, N, T% m( z# J& {
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
复制代码
5 f$ O# L1 O, T* g# L
2、配置GPIO为复用功能及时钟使能
  1. // 配置GPIO为复用功能9 J" d, e1 M+ H, u  r
  2. GPIO_InitTypeDef GPIO_InitStructure;
    " d% d: M: Q) v! C) p
  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  // 设置要配置的引脚8 E1 D3 C( N1 F+ y% i
  4. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 设置引脚模式为复用推挽模式. Y; O/ M; [/ ?' T
  5. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 设置引脚的速度! l  k& _& D' Q5 b# K/ |. N8 u
  6. GPIO_Init(GPIOB, &GPIO_InitStructure);  // 初始化GPIO配置( u( J( y* F/ b2 a+ Q: u  }: J" o. a

  7. " m2 N; g0 `- |& f
  8. // 禁用JTAG 启用SWD
    " \# p5 ], M8 P
  9. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);% ~1 f' }3 j9 r! W! O- O
  10. // 把TIM3_CH1功能部分映射到PB4引脚上" y5 z9 s* t* c' ?
  11. GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
复制代码

+ `  \& @" j+ r9 C
由于使用的是PB4引脚,需要将TIM3_CH1功能部分映射到PB4引脚上

( ]  b0 I- |' @! ?7 _
3、配置定时器3为PWM模式
  1. // 配置TIM3为PWM模式7 a7 u* O  ^1 ]( ~( u
  2. TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;# K  }# \9 p$ ?( ~5 J) T1 T: S
  3. TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // PWM周期,即计数周期20ms,PWM信号频率为50HZ
    ( N; y. G# E# U( h- A) C7 ?6 {0 G) F
  4. TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 预分频系数,定时器时钟频率为72MHz/72=1MHz. I# B  J, f1 N8 B* ^7 K
  5. TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分频/ J/ v/ e& B7 Q! q
  6. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数模式为向上计数% t6 H7 R) d+ k; X- w
  7. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
复制代码

2 N5 }7 h: p  X. m* y2 \2 g9 D
4、配置TIM3的通道1为PWM输出
  1. // 配置TIM3的通道1为PWM输出
    ! ^) G* |5 G0 j% z1 q0 l
  2. TIM_OCInitTypeDef  TIM_OCInitStructure;
    . l$ ]% L3 t( M  q9 H
  3. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
    1 ]1 X: [' @. R" W& \1 {( v
  4. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
    7 C$ D# ?' q) K1 k/ M# C% U7 W) L7 v1 I
  5. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高电平; e* m' ]- g+ u
  6. TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比' i0 X3 e, A; w# }
  7. TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    & ^+ `) L, V" L1 b# v/ B

  8. 0 m6 Y- l% _1 Y/ v
  9. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); // 开启OC1预加载寄存器
    6 [# [- u& u1 X/ z& Z! h* H0 u' I( e
  10. TIM_ARRPreloadConfig(TIM3, ENABLE);// 使能自动重装载寄存器
    & S% y( P* g% Y# N2 f) {
  11. // 使能TIM3定时器
    2 R4 {9 h9 a8 X+ o3 g
  12. TIM_Cmd(TIM3, ENABLE);
复制代码
6 y4 q4 ]& B( P! y, \3 Y, s" k
四、主要函数
此处代码以180°舵机演示
1、main.c
  1. if(Data_Flag == 1)( _* ?/ X, x7 R$ i8 m: \1 j
  2. {( S" S/ u6 K5 A0 C" M
  3.    int Servo_Degree = strtol(Data_Buffer, NULL, 10);//将数组中的数据转换成整数  x7 ?7 G% R9 k# k0 F/ l
  4.    printf("%s\n",Data_Buffer);//打印数组中的字符串
    6 O6 s/ E: o/ j4 D7 y( ]9 V$ H
  5.    printf("舵机目前角度 = %d°\n",Servo_Degree);//打印转化后的数据
    # k% \7 k& f( l# L1 X0 F5 x
  6.    Degree_Conv_PWM(Servo_Degree);//控制舵机旋转角度
    9 c7 D6 i# y* g" B' O
  7.    Data_Flag = 0;//标志位重置8 n0 w* i! ]0 ]0 l5 g/ e
  8.    memset(Data_Buffer, 0, sizeof(Data_Buffer));//清除数组中的数据
    # q, x* ~( Y9 x/ j2 M
  9. }
复制代码
$ E5 c+ Y) C. \9 a; U' T" O6 j( D6 a

6 J7 n/ E3 \) k使用轮询的方式判断是否接收到正确的数据,根据串口数据控制舵机运转
1 m, T  x: K- v4 E* }
2、PWM.c
  1. void Degree_Conv_PWM(int Servo_Degree)// 将接收的数据转换成PWM高电平脉宽3 y# q& Q+ r( `( T; E' V
  2. {
    . G+ G  R1 ~' w2 d& N
  3.     float PWM_Time;
    & O, H: h* |8 s: o* I
  4.     PWM_Time = (2000.0 * (Servo_Degree / 180.0)) + 500;6 w% Q# F6 _/ p8 _' t. g2 {
  5.     TIM_SetCompare1(TIM3, (int)PWM_Time);//定时器设置比较值函数和通道有关 时间参数单位是us
    ) k/ q+ S6 M# o- S+ `5 ]  P7 M
  6. }
复制代码

2 A8 {1 a4 B5 x% V  g+ l, z1 W

4 U% h5 _9 w1 L/ y, I! Y使用强制类型转换是为了保证精度,最后传递给定时器一个整数比较值
1 v& V, d% S. p0 X7 u1 S$ [
3、Usart.c
  1. int fputc(int ch, FILE *f)// printf()函数重定向" x1 t/ i8 Z2 x
  2. {* P9 t* \7 a1 k# F1 J0 s
  3.     // 发送一个字符到USART1( d5 N0 l  V. o8 b/ e7 l- Y  s
  4.     USART_SendData(USART1, (uint16_t)ch);
    ' d3 [* l6 B. h/ T: l" `" f
  5.     // 等待发送完成1 I. {3 i) j3 E) ^/ O
  6.     while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);8 }, a, P; _$ g' t- J  H+ X
  7.     return ch;+ O  r/ v+ b; g+ }5 J7 e( D2 V
  8. }( ^3 ]. x( E; F, o

  9. . w1 C, L& R  G* s" s4 {) q
  10. void USART1_IRQHandler(void)//串口中断函数
    2 t2 }0 Y  {, s* {+ b  I; ]
  11. {4 D. F  v# d7 h; g' U2 L- A+ d
  12.     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)4 C* x. N" a# g* S. W
  13.     {& D9 J4 U. O: [, T: o, s% V. J
  14.         Rx_Buffer[Rx_Index] = USART_ReceiveData(USART1);// 从串口接收数据到缓冲区( b! ], R8 q5 T1 Y" Z( B
  15.     if(Rx_Buffer[Rx_Index] == '[/align][b][b][font=Tahoma][size=3][color=#000000][b][b][font=Tahoma][size=3][color=#000000], b+ J% P3 {4 X
  16. [/color][/size][/font][/b][/b]
    ( X! @- K2 C0 M
  17. Usart1:串口中断接收以“$”开头,“#”结尾的数据[/color][/size][/font][/b][/b]
    7 Q2 x# B, l" m4 q: u2 k
  18. [align=left][b][b][b][b][font=Tahoma][size=3][color=#ff8c00]4、SysTick.c[/color][/size][/font][/b][/b][/b][/b][/align][align=left][code]void Delay_us(uint16_t us)6 O- S/ s& @" l9 Y3 L0 n! f
  19. {. W' j& a# d7 M% s6 e" Y' x
  20.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器
    " v% b  M2 _1 \0 y( v
  21.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间) x" E8 P4 O! f, O0 r+ {3 a
  22.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零
    ! @/ z: j1 F$ J# `! u3 E
  23.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器  {6 l' y' @8 `6 h5 e
  24.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成
    & D0 H2 J( n, O3 V% ~
  25.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器
    ( C+ o7 G" K5 b' m; |
  26. }
复制代码
使用系统滴答定时器来控制延时
% G: W% g" U& W2 B& E1 }& ]
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
微信图片_20230921140518.png
注意:串口、波特率、以及数据格式等
7 Y+ p0 \8 R. u
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
$ x# D$ L0 x/ ]7 g' _/ o
转载自: W-ML
如有侵权请联系删除0 b  W6 j  R/ |/ P
1 Y4 ?# y7 }. }  t3 `( M
' i0 S" Q! }2 k5 m0 k
7 _$ u. U+ d& V/ Y1 E
)// 如果数据是以$开头则开始存储数据
1 ?/ A- h! }8 E8 \    {* Y, z$ D# h$ F, {# D
        memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区
- j- r3 B8 I5 w* _4 u" v' D3 l        Rx_Buffer[0] = '7 M8 f0 n9 s- b& c9 f6 D2 v1 k5 N
& y5 O7 O) E3 s
Usart1:串口中断接收以“$”开头,“#”结尾的数据
. }9 |+ M4 q2 {- S1 E3 _
4、SysTick.c
  1. void Delay_us(uint16_t us)
    ( j) ?8 K$ \4 P9 y# q
  2. {
    3 S. r" y0 V: R
  3.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器
    , m  \( M4 v! v/ P
  4.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间
    5 J7 H) [  l0 w
  5.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零
    ! _) b# S& B. m- X+ h) B0 w9 Y3 ^
  6.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器) x3 f8 m* g! x& x
  7.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成1 Q3 A! g; T8 M: H  e1 B( R
  8.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器
    8 H6 f, m3 w1 C+ l+ j
  9. }
复制代码
使用系统滴答定时器来控制延时  O. d+ P$ ]( z$ v
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等3 a5 s: j" i; d9 s( ]/ D! c
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。

. J+ u1 N% I1 |3 P1 G
转载自: W-ML
如有侵权请联系删除- }5 s) y  M% y, k5 \7 R
* e  S. [1 J( V/ F: ~7 B; L

, k5 ^1 _# ]3 [
9 V1 u8 i% `# m; h6 P. B;
2 [. ]. f( R7 J4 D' y        Rx_Index = 1;
) m2 P( F; G1 C+ l% m6 {- g    }: s/ a; o7 d( h& H5 \; M
    else if(Rx_Buffer[Rx_Index] == '#' && Rx_Buffer[0] == ', I& M6 ?! I: a2 y+ x; ]! o

9 X1 r) }: }) CUsart1:串口中断接收以“$”开头,“#”结尾的数据

+ ]: x: a7 v6 J
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时) ^$ `& }0 q8 M' v* O9 Z
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等0 e6 ]  {" c! `/ g! Y  b
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
; ^& r- s2 l6 X# {$ d  v
转载自: W-ML
如有侵权请联系删除/ _) `3 U' L- B- L' A  y) M9 ?
- O8 X2 p; y: o( o* s) J( Q& _" P

6 e  u: K: v" u) n, |$ g
7 ^2 D8 h5 y: Z' H- q% ~)// 如果数据是以#结尾则结束数据存储并打印数据信息
# q. }: V5 p+ i    {% P& E* x0 R; z2 e1 w
          printf("Received: %sundefined", Rx_Buffer);// 打印接收到的数据$ n( x2 K+ x1 n" U
          memcpy(Data_Buffer, Rx_Buffer + 1, 3);// 使用memcpy函数进行数组内容复制
+ \/ f8 G# K) y1 {* P* W: L          memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区
( l7 l1 x5 f' y8 @7 R" W) m& p/ a          Rx_Index = 0;// 重置索引2 [, T" m2 `7 I  L0 \
          Data_Flag = 1;// 数据标志位" ~* I; I  i+ C
    }
( Q3 X9 D; w) _$ {% j9 b1 F    else
! N7 E( p" W* `$ e    {% R: Q4 L. z6 u, o" g  n
          Rx_Index++;// 增加索引,准备接收下一个字符) d  a( o& H/ T* z
    }
" w& z  N$ t4 d% d    }
6 }1 f' n8 y) \% C1 p}[/code]
; V( f( W/ l1 |2 k2 t1 u5 R
) \" N: g1 Q# g. p. x: S
Usart1:串口中断接收以“$”开头,“#”结尾的数据
# U& w$ k0 d: e3 j/ e6 y
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时
2 U, t, F( F; C; \( C
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等
* l' w5 ?( b; Z6 E  t* ?) y
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。

0 {& Q% |$ n& ~; c" c& u' c* A" R
转载自: W-ML
如有侵权请联系删除1 M& c- D1 o. p% s
; k' l1 l2 Q. }) Z0 d$ Q: ^

; G3 _2 s5 {* g
8 B6 `% `2 i, c1 B  C( d
+ M- e% \. e0 [3 _8 K/ Y' j
赞 收藏 评论0 发布时间:2023-9-21 14:07

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版