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

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

[复制链接]
攻城狮Melo 发布时间:2023-9-21 14:07
PWM舵机控制( c! I$ b* I* q) ^1 q- X& I8 f

& `# m" F) Y: l' Z硬件清单
  • 180°舵机
  • 270°舵机
  • 360°舵机
  • STM/GD32F103C8T6核心板
  • 杜邦线* s5 t/ W3 A' t8 u( ~
: U- u* s8 r# V2 K9 F, y
硬件接线
6 l1 C/ z! [# p: }5 o3 F
5 o1 |7 P- V# O- @3 F+ |
(KJ87HQKEAR50GMANL~TDZV.png

% z% y% h" f& U" K( C8 Q一、标准/连续旋转舵机! P: m5 b1 R, w7 K4 J
PWM舵机的控制原理基于脉宽调制技术。6 h+ D" l  q4 l4 e3 `
1、标准舵机(180°/270°)
  • 具有固定的角度范围
  • 精确控制角度位置
    , Y2 v: W4 ]( d7 L" I
通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机旋转的角度2、连续旋转舵机(360°)$ g! l% ^0 b2 V4 m
, q* o, J0 R+ H* W
  • 控制旋转速度和方向, i9 A3 D7 A$ \1 R; B
  • 实现无限制的连续旋转
    : M0 d+ r3 p. u9 n

7 Y% n# E7 T6 `' g& ^
" p" U. U" {' R
通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机的速度和方向
4 G' Z) o( h0 q9 Q

+ G4 r+ N+ J) r8 O# X9 n$ t二、舵机控制思路8 p! i3 p  J/ s, c$ B% q
控制信号以固定频率的方波形式发送给舵机;这个方波的周期通常为20ms,即50Hz的频率;
# Z9 e! O' q+ L' }在控制信号中,脉冲的高电平时间决定舵机旋转的角度或旋转速度和方向。
; ]$ G) }" Q7 l$ U; |1 ]9 V1 O- N. a( W' Y0 ]: `1 k1 n' ]" P. T
$ l' I. \/ a  w, S# q) w  o2 t
@E`Y[AZ1G_FO2[ZDGV6E_A3.png
0 {9 ]# c) j  @6 x6 w
  K' X0 X7 C; F# u- C- J' N
三、PWM实现思路
1、时钟使能
  1. //TIM3时钟使能
    * c! s& k" Y, S& F
  2. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    7 B! D4 K7 v8 g9 i8 [+ V& N% `
  3. //使能GPIOB端口时钟和AFIO时钟
    3 h9 V, f, T" r8 {9 n
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
复制代码
$ [+ i) \& D" ?
2、配置GPIO为复用功能及时钟使能
  1. // 配置GPIO为复用功能
    : C# A- Z' [9 M7 u, o  O+ X" ~
  2. GPIO_InitTypeDef GPIO_InitStructure;
    5 t9 p9 {0 ?5 D
  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  // 设置要配置的引脚5 }! Z9 |' v* @  k
  4. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 设置引脚模式为复用推挽模式7 e  M: w2 V6 V  S
  5. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 设置引脚的速度$ Q: W3 E' }( `1 p
  6. GPIO_Init(GPIOB, &GPIO_InitStructure);  // 初始化GPIO配置
    + T9 Z9 W. Y) s: a# c9 C
  7. ( h8 O; E6 |8 u: M8 n
  8. // 禁用JTAG 启用SWD
    9 S5 ^5 Q  B4 Y" q1 N+ W$ z
  9. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);  k- }5 h1 B- W& j( d/ i
  10. // 把TIM3_CH1功能部分映射到PB4引脚上8 G; N1 Z# P  D! ?$ `# w5 g
  11. GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
复制代码
4 j/ q6 K  t* a2 Q
由于使用的是PB4引脚,需要将TIM3_CH1功能部分映射到PB4引脚上
1 ^! S: ?* v% ~
3、配置定时器3为PWM模式
  1. // 配置TIM3为PWM模式
      T( Z) H9 n- E, H% i
  2. TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;4 ~+ \1 O! ?! T
  3. TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // PWM周期,即计数周期20ms,PWM信号频率为50HZ6 e) ~$ ^2 e. Q) B/ J  |5 ^
  4. TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 预分频系数,定时器时钟频率为72MHz/72=1MHz
    3 ^6 j+ W- E9 K/ F
  5. TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分频
    6 R3 l  b9 J- S  H4 {) e# f
  6. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数模式为向上计数
    8 r( _4 T9 A- u2 T1 _
  7. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
复制代码
3 Q5 B! `2 w4 @: @5 X$ ~
4、配置TIM3的通道1为PWM输出
  1. // 配置TIM3的通道1为PWM输出
    # q: k( N; W7 p& T- q* W
  2. TIM_OCInitTypeDef  TIM_OCInitStructure;( i' [/ D2 {8 J: i
  3. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
    " v; e$ w. w% H6 o3 x
  4. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
    ' |! L0 D8 W5 D+ ^* W1 ^
  5. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高电平
    - v# U. E. P! e' c3 D8 |! R7 [9 L3 e
  6. TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比
    : S/ A& ^" x- z
  7. TIM_OC1Init(TIM3, &TIM_OCInitStructure);7 h& Z( x$ o& F" x. [+ n9 k

  8. * e; S- x0 k% K3 e2 p( _
  9. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); // 开启OC1预加载寄存器
    4 ]! c0 w2 B0 J  B+ H$ |; \
  10. TIM_ARRPreloadConfig(TIM3, ENABLE);// 使能自动重装载寄存器2 H3 A3 v: i1 h+ J" b) R
  11. // 使能TIM3定时器0 z$ @# `2 I% O% M- l# s! Z% `! A) F3 |% w
  12. TIM_Cmd(TIM3, ENABLE);
复制代码

, ?9 ~7 H  s  L( d& ^* i
四、主要函数
此处代码以180°舵机演示
1、main.c
  1. if(Data_Flag == 1), t7 y* ]1 j; s# A! O) W7 c
  2. {
    . G* }, `+ H) x/ z. V
  3.    int Servo_Degree = strtol(Data_Buffer, NULL, 10);//将数组中的数据转换成整数
    / B+ J; ]4 s* K
  4.    printf("%s\n",Data_Buffer);//打印数组中的字符串/ n9 ~9 [- V  J. R) c
  5.    printf("舵机目前角度 = %d°\n",Servo_Degree);//打印转化后的数据
    ) L) w2 S! p: ?8 S% d
  6.    Degree_Conv_PWM(Servo_Degree);//控制舵机旋转角度7 m/ }( q/ d2 X: o
  7.    Data_Flag = 0;//标志位重置3 {& x& t' C8 i3 Z. Y
  8.    memset(Data_Buffer, 0, sizeof(Data_Buffer));//清除数组中的数据; d8 g! C; m" U. j
  9. }
复制代码
- i. L) E& R5 w$ @0 v5 U% ]
8 O) U9 f, L1 {# t# \. D
使用轮询的方式判断是否接收到正确的数据,根据串口数据控制舵机运转
- d  l: L5 [. e6 g; f0 L4 F6 z
2、PWM.c
  1. void Degree_Conv_PWM(int Servo_Degree)// 将接收的数据转换成PWM高电平脉宽
    9 d7 W; p% @, `- G) w( x1 j
  2. {
    9 I- J( ?1 p& l
  3.     float PWM_Time;
    . N7 b0 }0 B9 ~) M( c- p
  4.     PWM_Time = (2000.0 * (Servo_Degree / 180.0)) + 500;6 A! k4 y. D$ L- ~7 P, n
  5.     TIM_SetCompare1(TIM3, (int)PWM_Time);//定时器设置比较值函数和通道有关 时间参数单位是us, r5 Y! _8 T7 I
  6. }
复制代码

1 f3 r4 t$ N/ }3 {
9 ~8 ~) [, j! A. H3 E
使用强制类型转换是为了保证精度,最后传递给定时器一个整数比较值
8 [% }7 m/ ]# U* t2 j
3、Usart.c
  1. int fputc(int ch, FILE *f)// printf()函数重定向
    6 g1 \( {# K7 U& Z
  2. {
    " D9 X8 e& J- X4 ]! v1 ]; J% W
  3.     // 发送一个字符到USART1
    - C; _/ e8 E) {) F) k
  4.     USART_SendData(USART1, (uint16_t)ch);& }4 Q5 P% P# {* k3 F! [* `
  5.     // 等待发送完成
    6 V# s: C6 J2 @# G: D3 v5 X: I
  6.     while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    : K$ A, Y! n9 x1 u0 i
  7.     return ch;
    2 y9 f# h' J8 D
  8. }
    / T, N! B1 @- ?9 [5 a

  9. / e! J$ S+ V$ \6 x# g- L
  10. void USART1_IRQHandler(void)//串口中断函数/ M) i' L  u' d5 H  T6 X
  11. {6 }  L. r7 ]* s& m; Y, y$ P
  12.     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    # T5 ~5 |# v2 Z) x; E  }6 I3 G
  13.     {! g* L$ D7 ^( K0 L+ M' d% Q
  14.         Rx_Buffer[Rx_Index] = USART_ReceiveData(USART1);// 从串口接收数据到缓冲区
    3 }8 a& \/ c& h9 W+ E
  15.     if(Rx_Buffer[Rx_Index] == '[/align][b][b][font=Tahoma][size=3][color=#000000][b][b][font=Tahoma][size=3][color=#000000]
    - y& b" {0 w' w& Q
  16. [/color][/size][/font][/b][/b]
    - i9 ~$ N  C6 F" C
  17. Usart1:串口中断接收以“$”开头,“#”结尾的数据[/color][/size][/font][/b][/b]
    , @) B0 T2 D" Y# y
  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 ^4 G8 z2 L& X8 c
  19. {
    : [4 f% ~- h7 H% k$ x( G8 H, P
  20.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器
    9 C; a6 ~, F" a
  21.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间8 R( @. s/ G' c
  22.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零
    2 T4 r  Q6 j1 L' N0 L4 f
  23.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器
    " T* `. ?, F$ e; z# ?! f8 H2 N
  24.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成, D# Y8 G9 [' z8 _8 g) |3 L! h
  25.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器* g3 N8 i# P* b
  26. }
复制代码
使用系统滴答定时器来控制延时
) [. I/ C' Y: k  r, ^
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
微信图片_20230921140518.png
注意:串口、波特率、以及数据格式等" i8 X+ l( C- C! t+ F) ]) r' R
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
5 z4 s0 f4 m6 E4 l) ~  B% ~0 g/ H
转载自: W-ML
如有侵权请联系删除6 D5 a9 i+ l" @  J" G4 \6 T

3 r: }: t/ v) U4 Z7 R

) ?1 O9 F4 }. H' x3 j9 ^+ c# w! s# P! h
)// 如果数据是以$开头则开始存储数据
8 Y( n" ~% x" ?9 {9 b9 _  r    {
7 {0 M7 ^* Y3 }, k5 z+ }; ~        memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区2 u. F* `. J, J: q$ P
        Rx_Buffer[0] = '! C* j) I0 ?9 D3 q, t& Y

1 A, ^: l7 S! K1 d) k, \Usart1:串口中断接收以“$”开头,“#”结尾的数据

0 M) |+ X/ M+ ^7 x; v3 P, x, H- ?* b% y0 X
4、SysTick.c
  1. void Delay_us(uint16_t us)) v# j9 @& j0 M( t$ W; D6 w, a
  2. {+ K4 S9 w9 ]) p2 S- N
  3.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器$ d9 `; A; O% M
  4.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间6 R4 V: E# z! d2 h( e8 U
  5.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零
    . d! v* R, m+ K8 D" }
  6.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器, h$ b& o3 d. K6 e
  7.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成. n" S& ]! Q: {0 h9 y  _( s
  8.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器
    * l3 h/ v0 S: ]5 N: u
  9. }
复制代码
使用系统滴答定时器来控制延时
. x6 [+ ?4 y6 E* t
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等4 B1 j8 \% v1 v- n6 n% n5 e
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
4 @: ~6 `/ X# J5 K! ^
转载自: W-ML
如有侵权请联系删除
' D: Q- a7 V& ^3 j2 Z4 [
0 y; }! w. S& O4 z  k9 n
: W! i5 p. [: @. ]. R# X0 ^" b! d
: x7 t# C- T8 l4 _8 U
;
: D7 v7 T  t- x2 N        Rx_Index = 1;
( q% j. a7 z# _8 U, ^/ R    }
$ @  c6 J$ r5 L. v; z    else if(Rx_Buffer[Rx_Index] == '#' && Rx_Buffer[0] == '5 |5 g3 j8 A6 W3 U: H- K+ J
- L8 W) O7 ^' A
Usart1:串口中断接收以“$”开头,“#”结尾的数据

+ V$ ^; N) ^! y4 j( }
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时
+ N& i7 ^9 m# n* v, K
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等
, O+ ?: w  v& {, O
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
' u! t2 k/ [, u) w$ V
转载自: W-ML
如有侵权请联系删除* W" C4 @" v! P  \" N3 X7 }0 ?% A
  N# S2 i# e; W

1 u: t" c" D. n: S1 Q7 H
: S  u8 O' M) D* z. [3 o)// 如果数据是以#结尾则结束数据存储并打印数据信息$ h3 ~! k9 P, Y+ k" u* g
    {
3 b8 o+ j# _8 Y/ z6 u          printf("Received: %sundefined", Rx_Buffer);// 打印接收到的数据7 a! u% P. y' U- ^( p# K
          memcpy(Data_Buffer, Rx_Buffer + 1, 3);// 使用memcpy函数进行数组内容复制1 L8 s2 _$ v, |( {
          memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区
! {  N- B7 Y- T9 Y          Rx_Index = 0;// 重置索引" u0 S" H/ p/ W8 r; g0 u) L
          Data_Flag = 1;// 数据标志位
6 d  W1 N1 u/ }4 H1 s. `    }
* j! G5 U; P. I6 ~& I& i+ x    else* |! O( K0 I  O) E9 [" Q
    {
& s( a* C- \. M3 a          Rx_Index++;// 增加索引,准备接收下一个字符' p' Q3 r6 l$ d! P7 g
    }
/ `" j3 D$ O. `+ A! b: Q" f    }
8 {: m! G" t) L}[/code], [/ ?4 A( E* _- g" M- Q! B7 Z
! I2 s5 l! M6 B& ~; q: M
Usart1:串口中断接收以“$”开头,“#”结尾的数据

( W# L5 Y1 }3 E) d0 S. @
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时
3 Z: C: m7 L& g* ]6 S" ~* C# {- |8 v
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等' Q! ]' ]. R1 v9 d- L7 Z
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。

5 }$ N+ e' A% O/ U9 B5 Y3 `
转载自: W-ML
如有侵权请联系删除
: [  h1 Q% P- f- L: H0 y

5 K- G4 ?2 o+ G- n

8 A/ U" O. v8 B- P. Z5 g% p, c0 V. B2 j! m
6 ?; ?% q  T- f3 ^5 C4 w$ V2 t3 F
收藏 评论0 发布时间:2023-9-21 14:07

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版