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

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

[复制链接]
攻城狮Melo 发布时间:2023-9-21 14:07
PWM舵机控制  M- }& h# _4 a- @, k
" N% p9 H6 ]" O3 ^4 `
硬件清单
  • 180°舵机
  • 270°舵机
  • 360°舵机
  • STM/GD32F103C8T6核心板
  • 杜邦线5 s9 C% Q" X8 E. n' `! Y; T
* t- q$ I1 ]* Q. E6 D1 T/ Z- m
硬件接线
1 H8 Y. G2 R$ h2 N. d7 m

: F; E9 r6 }6 I& q
(KJ87HQKEAR50GMANL~TDZV.png
  b& x6 `+ ^1 a7 h- a( z
一、标准/连续旋转舵机
, a7 z2 }) D8 q- H% U( l) V, H8 N2 bPWM舵机的控制原理基于脉宽调制技术。
- N* E# k- z- g  f8 w  \4 k1、标准舵机(180°/270°)
  • 具有固定的角度范围
  • 精确控制角度位置

    6 x0 l# w( w$ ?
通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机旋转的角度2、连续旋转舵机(360°)* R: R% W: ?5 p& o  f

' A, C5 X- D  g
  • 控制旋转速度和方向
    1 \- W1 S' x! n
  • 实现无限制的连续旋转' w4 C* ]% q+ z' {
; g8 Y' ]0 Y! ^/ Z7 m- y
1 ^. h" t- d  x) n* b
通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机的速度和方向
' b! D1 {7 \3 |3 m( Y* w: ?: |
4 d+ M7 ]2 S/ m3 v4 h7 ]
二、舵机控制思路4 V+ v- `# F4 [* @
控制信号以固定频率的方波形式发送给舵机;这个方波的周期通常为20ms,即50Hz的频率;, L; Z: m% |3 L: F$ F& q$ t
在控制信号中,脉冲的高电平时间决定舵机旋转的角度或旋转速度和方向。
" S% N" a% \4 y7 n" r2 p0 P; s6 A: ]# ~8 ]

2 D8 z* h: {9 A0 p* P( X7 s# P @E`Y[AZ1G_FO2[ZDGV6E_A3.png : I+ R' L/ U4 o3 e) J* X
2 j! P$ L: b$ u* l5 y2 w
三、PWM实现思路
1、时钟使能
  1. //TIM3时钟使能
      w' p+ m- H! n3 m& U5 p" ^
  2. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    - k$ {. |# ~# F+ v
  3. //使能GPIOB端口时钟和AFIO时钟
    % K6 G7 F7 Y7 ~0 A1 H, m
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
复制代码

# g8 S# J  t: R) e, z9 P) Y
2、配置GPIO为复用功能及时钟使能
  1. // 配置GPIO为复用功能
    ; l. M$ c# f9 G! ~8 \2 ^; z2 Z
  2. GPIO_InitTypeDef GPIO_InitStructure;- w& I8 f6 K' D- E. K
  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  // 设置要配置的引脚
    + R. O# B2 E+ }- [" ]6 S
  4. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 设置引脚模式为复用推挽模式
    3 ^1 e! Z- d( O. o) G  r6 Q  b
  5. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 设置引脚的速度
    : h# r5 [5 O& v
  6. GPIO_Init(GPIOB, &GPIO_InitStructure);  // 初始化GPIO配置3 }. o" Y  g3 }% l. [; Z
  7. 3 N( I7 k! v' t/ c: ^
  8. // 禁用JTAG 启用SWD) a7 X& A  U- \# c
  9. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);; W2 A( k. Z& w: S* R
  10. // 把TIM3_CH1功能部分映射到PB4引脚上8 N* A' {( S; R7 Z
  11. GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
复制代码

0 ?7 O* ]" l0 y
由于使用的是PB4引脚,需要将TIM3_CH1功能部分映射到PB4引脚上

" b8 F6 P5 E9 x! _4 T
3、配置定时器3为PWM模式
  1. // 配置TIM3为PWM模式
    6 O1 }8 m# o% @. H$ }- X
  2. TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    " a+ v9 k# m0 x2 I+ Z
  3. TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // PWM周期,即计数周期20ms,PWM信号频率为50HZ: ^! g; I1 l; U/ z2 k. k
  4. TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 预分频系数,定时器时钟频率为72MHz/72=1MHz
    6 D' q0 r9 A/ X
  5. TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分频
    8 K# U/ o$ ~# v3 r' P9 z/ w& K
  6. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数模式为向上计数* K/ k; }/ Z7 r  S+ ?: I' B8 _% r
  7. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
复制代码
; |% \8 T0 l- ?1 y$ o$ q
4、配置TIM3的通道1为PWM输出
  1. // 配置TIM3的通道1为PWM输出; S0 G2 @8 X( G7 b- \) B3 Q
  2. TIM_OCInitTypeDef  TIM_OCInitStructure;$ B( |) Y  |, q0 I( g; ~( a9 H
  3. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1- J2 T5 _: X' @8 R5 e/ T5 ?1 Y! d
  4. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
    + H, {$ ^, T, s( l/ W7 F3 e
  5. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高电平. f; t( X* i6 V5 i6 z' S* }
  6. TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比! C0 v/ P3 T' V: F$ z
  7. TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    / F4 z+ ], W& G. b  }
  8. / Q2 x0 A! y  n5 ~$ \- {5 u
  9. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); // 开启OC1预加载寄存器" ?! ~) e. x8 P5 t& B! d3 [
  10. TIM_ARRPreloadConfig(TIM3, ENABLE);// 使能自动重装载寄存器  H9 P6 z3 Q: l, L+ \- u  u! ^* i# s: B
  11. // 使能TIM3定时器5 V5 M$ a/ I$ z7 x' ?# S  ]
  12. TIM_Cmd(TIM3, ENABLE);
复制代码
6 Y" Q8 w! g1 x7 |, Y+ [4 Z
四、主要函数
此处代码以180°舵机演示
1、main.c
  1. if(Data_Flag == 1)
    ) x3 w/ h7 _! S% A. w- f! H7 ]) c
  2. {
    ' {: k( v3 Q: n$ n
  3.    int Servo_Degree = strtol(Data_Buffer, NULL, 10);//将数组中的数据转换成整数
    : N+ ?% O4 U: v" j8 d3 D
  4.    printf("%s\n",Data_Buffer);//打印数组中的字符串
    ) |- r# {' r4 k7 X) r7 n, O
  5.    printf("舵机目前角度 = %d°\n",Servo_Degree);//打印转化后的数据; i) |! ~5 E' o7 S# R
  6.    Degree_Conv_PWM(Servo_Degree);//控制舵机旋转角度
    + K4 D* }; z; p& F4 F. ^
  7.    Data_Flag = 0;//标志位重置4 r) u. M# o% v( ~% C) J4 c" ]+ J
  8.    memset(Data_Buffer, 0, sizeof(Data_Buffer));//清除数组中的数据, D$ S, p/ x! i) o
  9. }
复制代码

; K8 u6 y4 x5 W# n$ k6 m: f% ?2 _; P( V
# _3 \9 g: J2 w2 q
使用轮询的方式判断是否接收到正确的数据,根据串口数据控制舵机运转

) }( E, M  I% z! n! ~6 p
2、PWM.c
  1. void Degree_Conv_PWM(int Servo_Degree)// 将接收的数据转换成PWM高电平脉宽
      O; W" v* Z+ n$ }( z8 W
  2. {! h% Y& V& d; L7 U6 r# D
  3.     float PWM_Time;0 M* G+ G: s$ D" ]- a
  4.     PWM_Time = (2000.0 * (Servo_Degree / 180.0)) + 500;: M1 D" p4 y* c) n
  5.     TIM_SetCompare1(TIM3, (int)PWM_Time);//定时器设置比较值函数和通道有关 时间参数单位是us
    3 r( @! X' B! W: w+ O
  6. }
复制代码

! L) f! U) h* f% e' t5 T

/ _7 n1 ~: |: q  y' |; D8 Z使用强制类型转换是为了保证精度,最后传递给定时器一个整数比较值

" k% Y2 S8 D2 ?
3、Usart.c
  1. int fputc(int ch, FILE *f)// printf()函数重定向9 A; [% R2 O( w
  2. {
    2 ]! y$ _5 X- J# I5 U- s2 K
  3.     // 发送一个字符到USART10 J8 k0 L4 p; v2 L1 U9 j
  4.     USART_SendData(USART1, (uint16_t)ch);
    4 h& D. O; s0 l- R
  5.     // 等待发送完成8 p9 w6 |7 a$ `3 @, i6 M
  6.     while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    4 I1 L9 N+ D0 [  ?: n: U  |
  7.     return ch;" R4 n  Y/ S% x: u. @% X
  8. }* {/ R3 O* r9 j: U
  9. 0 B# V& K. [; d+ A! ^
  10. void USART1_IRQHandler(void)//串口中断函数! l, ]( ~" D# y8 e0 F& g. L) K
  11. {* e. V# H0 r9 i
  12.     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET), P: f5 e3 i% U. v, d: N% x
  13.     {
    / v( w5 g+ z4 X- }
  14.         Rx_Buffer[Rx_Index] = USART_ReceiveData(USART1);// 从串口接收数据到缓冲区4 z6 G# j/ K6 o" W0 T
  15.     if(Rx_Buffer[Rx_Index] == '[/align][b][b][font=Tahoma][size=3][color=#000000][b][b][font=Tahoma][size=3][color=#000000]
      I' O% V+ P: W  i( B. b
  16. [/color][/size][/font][/b][/b]
    1 b: S$ Z" Q% r( |% o. e
  17. Usart1:串口中断接收以“$”开头,“#”结尾的数据[/color][/size][/font][/b][/b]9 [$ k, o; k6 d# C: ]
  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)
    ) ?% @, ?- H) o  R0 C/ U
  19. {# r) B% M! o6 \1 ]- F6 c1 d9 L
  20.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器
    : g! H. c9 {) ~- t, b" Q" P
  21.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间
    . P0 @" f8 O+ M# P" m/ F
  22.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零
    0 l% I/ Q. Q) |, n( c3 ^
  23.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器
    5 M- j( K4 f9 v- A0 @( e
  24.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成9 I+ w4 _8 a: U3 b
  25.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器
    - u8 i( j6 m1 G7 ]7 J
  26. }
复制代码
使用系统滴答定时器来控制延时( K' B% V4 O% A% J$ L5 ~4 _
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
微信图片_20230921140518.png
注意:串口、波特率、以及数据格式等8 [  [4 S) E+ t# r  f4 U/ n: k
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
+ z+ E3 I9 ]* B: V
转载自: W-ML
如有侵权请联系删除
+ w  c  [. J9 w. A0 g2 \2 p
; ?% @. A' v' x1 m( a$ h/ H

* o% u2 g% e# C1 m
0 f$ O& S, ^4 K0 x% [5 t)// 如果数据是以$开头则开始存储数据
8 F' Z3 U) \' ]5 s    {3 N! @  Z- Z! N/ B, l
        memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区
( ?2 C( k2 ~5 @+ f. G4 z4 x        Rx_Buffer[0] = '
- I. z% b3 [" ?/ x! x$ o3 p" ~
9 ]3 ~+ d4 H- u9 Q2 F, `
Usart1:串口中断接收以“$”开头,“#”结尾的数据
3 S3 Y% m; @8 ~0 S" q- Z
4、SysTick.c
  1. void Delay_us(uint16_t us)! O. `  f- j" r
  2. {( @% g, Q+ N0 `6 ~% l. t
  3.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器3 h6 B2 m* I% U  q0 W
  4.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间
    8 f+ n* m  k! L
  5.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零
    4 X/ D3 B2 h8 ]
  6.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器  s0 @5 D% f/ n- j) R/ O+ _; p* ~" B
  7.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成% O( z1 K4 N' a$ x3 r) V
  8.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器+ d! \9 U; _8 f
  9. }
复制代码
使用系统滴答定时器来控制延时, H  D: U( a- f: }) R, c' v
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等8 A5 c* i2 M  P
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。

' G3 j1 u, Z/ h* o1 n9 G4 C$ l; ~
转载自: W-ML
如有侵权请联系删除
. w1 X, ?, T: C# E* R
. s- |, ?  f8 v5 U. Q0 G. U3 y

0 S  N( P/ g0 x+ i
# Q% V+ {9 L& m0 A( s;
! h( \1 l$ D9 g. y7 t' F        Rx_Index = 1;1 |* K$ A* ~( _' w& \' |1 g8 Q
    }' @+ z  J% M* ]; b6 t" J
    else if(Rx_Buffer[Rx_Index] == '#' && Rx_Buffer[0] == '5 i$ C5 w& T) t5 ?+ {# r" B, I

+ O) E7 Y  ~/ z" b5 a8 g4 LUsart1:串口中断接收以“$”开头,“#”结尾的数据

1 ~" y( l. x6 c; ~5 w- n+ I1 w
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时
! L1 {) U# E4 W( R  l" Q( @
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等
0 ?* A; Z9 r" z% @9 p& U7 }! D4 o
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
1 G$ W4 Y' C7 [7 R% R
转载自: W-ML
如有侵权请联系删除
9 f$ M6 n. G9 j9 l5 |
8 i/ w: e. t* U  L1 a0 D
# ~6 H2 @) ]8 D9 |! t/ ]! `3 j2 m
2 g& E' M8 k: ?9 _% b
)// 如果数据是以#结尾则结束数据存储并打印数据信息+ f: T3 _- [" j7 `1 y1 |
    {
" K% z  S8 w! R$ m          printf("Received: %sundefined", Rx_Buffer);// 打印接收到的数据
5 ?+ J5 J) }4 @4 z, J7 t          memcpy(Data_Buffer, Rx_Buffer + 1, 3);// 使用memcpy函数进行数组内容复制& a" F5 w$ U- ?) p3 K9 S
          memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区
+ y4 A1 h; y7 S, d* y          Rx_Index = 0;// 重置索引
6 u6 ^! h3 u* L( A          Data_Flag = 1;// 数据标志位
; N6 W& J* b, O) S- U! U    }7 o, T1 @" c# n1 S' l: e
    else4 Y! y1 m3 |$ a
    {
1 X9 N* h, _  f+ j6 G          Rx_Index++;// 增加索引,准备接收下一个字符
  u& }: W, R7 I$ _' y* i2 H    }! |: q9 e6 s3 D; K- f1 h
    }
8 t, _; @% k& K. I  ^}[/code]
% Q/ f0 P- d" c! b: e; Z1 D

6 P* Q  }! `5 R! X8 K( v5 fUsart1:串口中断接收以“$”开头,“#”结尾的数据

' _. Y) d" x* d' ]: |5 P; U$ b8 ]
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时
8 p% u! B; N$ N% ?3 K2 q4 V  U4 ~1 Y& k
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等# L1 }- i8 i! _1 W
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。

7 O& y/ J; k/ {- b  P/ ]  j3 B
转载自: W-ML
如有侵权请联系删除) g9 V8 }% j( c" b' v

. c6 Y1 [5 b6 U# }- \; Y' e
6 ~. w- R9 L# G* I

3 Z) o1 G2 W# ~" n% k4 a3 D
0 z) O9 k/ u. a4 T6 W
收藏 评论0 发布时间:2023-9-21 14:07

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版