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

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

[复制链接]
攻城狮Melo 发布时间:2023-9-21 14:07
PWM舵机控制) q, ~+ t5 N( w5 D& G  W  L' C. x
1 V" y% |# W! D3 N! S: g
硬件清单
  • 180°舵机
  • 270°舵机
  • 360°舵机
  • STM/GD32F103C8T6核心板
  • 杜邦线
    ; i/ @; k( r1 g5 L4 l

1 i; n% z( f9 E, Z
硬件接线
  W4 h7 H* R' E& p, _+ O

" P/ N0 J) [. R" m2 z+ z
(KJ87HQKEAR50GMANL~TDZV.png
- Z9 ~+ g% Y/ B3 x
一、标准/连续旋转舵机
! z% Q6 o5 R1 U7 u. x6 ePWM舵机的控制原理基于脉宽调制技术。
9 o8 H, m& t+ |; I: b1、标准舵机(180°/270°)
  • 具有固定的角度范围
  • 精确控制角度位置
    8 g4 F# X+ V3 O0 ]
通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机旋转的角度2、连续旋转舵机(360°)
7 V" @- x7 r; o% ^% B2 B7 Y$ m3 a: f, U4 \9 ]
  • 控制旋转速度和方向! o" e8 G0 v, z  i
  • 实现无限制的连续旋转/ p* f$ O$ @& {6 I, P; n2 Y
; |/ J' ?9 w$ S. |" c1 i

0 w2 }( l. p3 V. O5 A3 f通过改变PWM信号来控制脉冲的高电平时间,从而来控制舵机的速度和方向
; Y# Y1 A  o; w6 e
/ Z2 D9 r% B& f3 L2 |
二、舵机控制思路
7 V- h$ l: u  @" A, G+ @, p
控制信号以固定频率的方波形式发送给舵机;这个方波的周期通常为20ms,即50Hz的频率;
0 m: g1 T; W# ^' A. V# M在控制信号中,脉冲的高电平时间决定舵机旋转的角度或旋转速度和方向。7 @$ x7 K0 @4 M- w$ M" Q* |. H* ^' M
- e5 o, V# E6 Z0 R7 D- G/ |
- R; _2 x* G/ c
@E`Y[AZ1G_FO2[ZDGV6E_A3.png : r8 z; C5 h1 I8 ?. G: a
  v- p$ Z0 }- Y6 _& S) E9 |+ _, s
三、PWM实现思路
1、时钟使能
  1. //TIM3时钟使能' R& V7 {! u2 ]: x
  2. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);7 }: t1 r9 M( q# k! C4 E
  3. //使能GPIOB端口时钟和AFIO时钟
    4 m% G) G5 R: x( p0 _; ~8 l
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
复制代码

1 v' w: x' O7 \) J* w; r
2、配置GPIO为复用功能及时钟使能
  1. // 配置GPIO为复用功能0 ^% A) j, V* \( M
  2. GPIO_InitTypeDef GPIO_InitStructure;
    & B. g, `/ u6 C; m5 `+ V" Q
  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  // 设置要配置的引脚
    3 d0 j; R$ @7 O$ D, [! P- D  b, S2 n
  4. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 设置引脚模式为复用推挽模式9 N9 U  p6 Y1 X/ s7 w+ s
  5. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 设置引脚的速度
    + Q% W$ N% F: m( M. u. p
  6. GPIO_Init(GPIOB, &GPIO_InitStructure);  // 初始化GPIO配置. W& J; b5 o6 b) e' l) n/ c+ K& H

  7. 4 T$ U2 U: i) A1 n. _6 W
  8. // 禁用JTAG 启用SWD& |) N3 L0 I/ n7 V9 D
  9. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);! d) ?4 o; z/ g
  10. // 把TIM3_CH1功能部分映射到PB4引脚上, T1 V3 \- T) p9 E! }
  11. GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
复制代码
( a  P. o9 {$ f, p& P4 D
由于使用的是PB4引脚,需要将TIM3_CH1功能部分映射到PB4引脚上
% O# C( U% S. C# I  E4 T. h
3、配置定时器3为PWM模式
  1. // 配置TIM3为PWM模式2 F3 u( \" N  f4 o/ \
  2. TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    0 [/ ~4 O$ I* r1 y
  3. TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // PWM周期,即计数周期20ms,PWM信号频率为50HZ
    6 k+ l& R1 R- O$ m# k2 {+ s4 q
  4. TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 预分频系数,定时器时钟频率为72MHz/72=1MHz
    * F" Q+ X* O/ F1 m. e* q+ }& u
  5. TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分频
    - W: R& l+ g" R0 O# G
  6. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数模式为向上计数/ b8 R2 p" L$ \8 {
  7. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
复制代码

4 h  B& R! l9 `  d
4、配置TIM3的通道1为PWM输出
  1. // 配置TIM3的通道1为PWM输出
    9 |7 U' s: f9 p6 [0 a$ H
  2. TIM_OCInitTypeDef  TIM_OCInitStructure;" Z6 s+ H( D. B! Z4 C: D! }
  3. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1! n; f6 p/ c- V( X, M
  4. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能0 U/ S5 @" ~& ~6 g, e
  5. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高电平
    * P* h7 E5 a: E3 \. L. g' `
  6. TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比9 D* x" l; Z3 }* X/ O" y2 D
  7. TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    : ~9 I6 b/ @, J' r! U" _, T
  8. ' ~$ B) x6 V; b, k& T' u* {
  9. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); // 开启OC1预加载寄存器& Q) E5 x% R3 b1 u0 g" f9 b* d. J
  10. TIM_ARRPreloadConfig(TIM3, ENABLE);// 使能自动重装载寄存器: e' h* s) D# C# y2 ]* X" M
  11. // 使能TIM3定时器
    " m  ~& t' @& [; M9 g/ V- e3 v4 v9 G
  12. TIM_Cmd(TIM3, ENABLE);
复制代码
  B( x& B- R" [( J3 l/ l# [
四、主要函数
此处代码以180°舵机演示
1、main.c
  1. if(Data_Flag == 1)
    # c) Y: [: l+ h! n* J$ v: _5 ]+ P
  2. {& j( |( N9 N, E2 z& E. y( R
  3.    int Servo_Degree = strtol(Data_Buffer, NULL, 10);//将数组中的数据转换成整数
    5 k- T  `3 P* k
  4.    printf("%s\n",Data_Buffer);//打印数组中的字符串. X, W) t5 @; a. L2 p! ]8 [2 p
  5.    printf("舵机目前角度 = %d°\n",Servo_Degree);//打印转化后的数据
    - z7 M* T2 v* v" Z# B
  6.    Degree_Conv_PWM(Servo_Degree);//控制舵机旋转角度
    . j2 V& ]& G; f8 r5 ^# v/ h
  7.    Data_Flag = 0;//标志位重置
    : Z) A1 _! M3 s/ u+ R# N
  8.    memset(Data_Buffer, 0, sizeof(Data_Buffer));//清除数组中的数据
    # o/ ~' @$ t; T
  9. }
复制代码

+ o8 m0 ]9 R( ^  L* e! J
7 ^: |# C3 Z( n) \# u
使用轮询的方式判断是否接收到正确的数据,根据串口数据控制舵机运转

  q/ R- V4 G+ R
2、PWM.c
  1. void Degree_Conv_PWM(int Servo_Degree)// 将接收的数据转换成PWM高电平脉宽
    3 \: [4 N0 t/ H: x' K5 o% h* \1 C4 R0 k
  2. {
    ( l& }9 ]- x# B# N8 f8 L6 N
  3.     float PWM_Time;
    8 V. ~. m+ C/ G/ |  q
  4.     PWM_Time = (2000.0 * (Servo_Degree / 180.0)) + 500;3 I) I1 }& T3 K$ z* _# q
  5.     TIM_SetCompare1(TIM3, (int)PWM_Time);//定时器设置比较值函数和通道有关 时间参数单位是us& O3 _. F( d0 P# a# J/ m
  6. }
复制代码
2 \. b5 L" g" I6 b

$ X3 w( O& S% o  k3 e9 V& ?使用强制类型转换是为了保证精度,最后传递给定时器一个整数比较值
1 R" N' `: Y# s4 s" n2 C
3、Usart.c
  1. int fputc(int ch, FILE *f)// printf()函数重定向
    ' \0 I! m5 P7 G/ V. ?
  2. {+ p7 w) t2 Y, {
  3.     // 发送一个字符到USART1
    4 x0 z* g& h# \% C% x# h
  4.     USART_SendData(USART1, (uint16_t)ch);
    / p1 E: Y! y# X' T" X
  5.     // 等待发送完成& V2 n7 J/ c: {1 L/ Q
  6.     while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    0 x& {. N6 S& a- P
  7.     return ch;
    3 \! e& F# t# @4 ^/ w; L3 l
  8. }
      x! v' `, I2 [8 g. R0 q; F1 P

  9. ! _, x. S( @8 O; f8 w3 C' }
  10. void USART1_IRQHandler(void)//串口中断函数/ e' T7 {1 v1 c( `$ z; d
  11. {0 Z+ q! W# B9 Z( D4 o9 ^+ a: {
  12.     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    ( j9 M1 s& c. a/ v8 \
  13.     {
    : ^! K  V  o* r, Y( j* w
  14.         Rx_Buffer[Rx_Index] = USART_ReceiveData(USART1);// 从串口接收数据到缓冲区& t4 b- y* C4 C! m5 ]
  15.     if(Rx_Buffer[Rx_Index] == '[/align][b][b][font=Tahoma][size=3][color=#000000][b][b][font=Tahoma][size=3][color=#000000]
    6 ^: w3 O, d% q+ J
  16. [/color][/size][/font][/b][/b]8 t% U  C/ U; }7 w% z2 Q
  17. Usart1:串口中断接收以“$”开头,“#”结尾的数据[/color][/size][/font][/b][/b]
    ! V) }- W, `. x, R9 g0 l
  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, b$ y- u% C$ U0 i
  19. {7 ?9 d# f+ Q# q0 [9 e
  20.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器" l% o& R0 U1 M1 Z
  21.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间
    , c* g+ n1 @- ]  D
  22.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零
    9 Q) ^. B5 ]: C- y% [* \0 ?
  23.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器
    5 N- F4 ~* s2 ^: x; d
  24.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成
    + u; N3 A5 a& ^2 K: r' x* j
  25.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器$ o/ h: R1 A# z# i  T
  26. }
复制代码
使用系统滴答定时器来控制延时
  o# h" Q" e) u
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
微信图片_20230921140518.png
注意:串口、波特率、以及数据格式等8 x- M( K! V. d; A
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
) i2 w0 @4 n8 Y% E, s8 d
转载自: W-ML
如有侵权请联系删除
& u8 W0 `) d" V9 o( c3 T* c
! h; N% d' {1 \$ v6 `

* t" l9 s7 V3 G
: ?$ L2 Z6 o' r; h- D# P- Q3 k2 y)// 如果数据是以$开头则开始存储数据6 E# x" }0 L$ |& n; }+ D
    {* c. f- e0 {5 _7 R+ R" b
        memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区  ~, ~0 e$ k9 ~9 E. ^- c% ~$ l: D6 O
        Rx_Buffer[0] = '+ l; O( [& E# G7 o/ y

( I6 `3 I/ N3 ]. X# rUsart1:串口中断接收以“$”开头,“#”结尾的数据
0 f5 [8 f6 q/ ~. ]: f) t5 G
4、SysTick.c
  1. void Delay_us(uint16_t us)% B6 i& ?0 X' l+ h
  2. {
    ! m% L& h. M% g8 V& \4 Z
  3.     SysTick->CTRL =  0;// SysTick控制寄存器清零,停止SysTick定时器- j7 z2 W7 p' y) j) o, Q) C8 u9 f6 I
  4.     SysTick->LOAD =  72*us - 1;// 设置SysTick加载寄存器的值,确定延时的时间) W: ]1 L* V2 w. y  d  I
  5.     SysTick->VAL =  0;// 将SysTick当前值寄存器清零/ G$ e7 P# b* N
  6.     SysTick->CTRL =  5;// 设置SysTick控制寄存器,使其开始倒数计数,并启用SysTick定时器" |$ p9 u) |- G. a) J4 `" X
  7.     while((SysTick->CTRL & 0x00010000) == 0);// 等待SysTick定时器倒数完成' |5 f: Q# N9 H! v$ L
  8.     SysTick->CTRL =  0;// 再次将SysTick控制寄存器清零,停止SysTick定时器
    , @' ^4 A  S# f9 I/ B9 N6 o
  9. }
复制代码
使用系统滴答定时器来控制延时9 A: V# X( W8 ]+ x! G) W' y$ ]
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等% q: W% }3 o( G! f3 ], s) p! z
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。

3 N' E2 V1 S% k) N
转载自: W-ML
如有侵权请联系删除
& R1 I( W) n0 |  n
: X4 H' `9 K* |5 N2 E5 Y! O

0 X' Y7 T7 R& b# A+ j! L
3 T3 W8 U2 H8 a+ \* Y( W;5 h; s" w( A1 ], e0 f
        Rx_Index = 1;+ b( I" Z1 s0 ~+ b& D
    }5 a# |! e  e7 ?% h7 A
    else if(Rx_Buffer[Rx_Index] == '#' && Rx_Buffer[0] == '
4 W, g  [5 A7 P0 v

$ t0 L( [( z2 {5 F. ?Usart1:串口中断接收以“$”开头,“#”结尾的数据
1 z- `8 V" Y( w( S" j* F
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时& j% b7 i& G  t4 z
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等9 ~6 ^4 o; s5 V1 P) E
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。
0 O7 \% S6 }" F* h
转载自: W-ML
如有侵权请联系删除4 J# k  C) z7 Q+ I6 ^
3 Q+ n+ @; V! v$ O- b, J+ r) D* F" O
$ g+ }5 }* s+ J  L

% o+ Q( M8 ?2 a+ p. h8 c& M- t1 `# p)// 如果数据是以#结尾则结束数据存储并打印数据信息
6 L" n6 R: Z& ?' f" n2 h    {. r; [( n. B" |
          printf("Received: %sundefined", Rx_Buffer);// 打印接收到的数据
. k0 a- q# Z4 b3 V7 Q          memcpy(Data_Buffer, Rx_Buffer + 1, 3);// 使用memcpy函数进行数组内容复制
8 A0 r7 s; j: t  K1 H: m+ g6 E7 T          memset(Rx_Buffer, 0, sizeof(Rx_Buffer));// 清空接收缓冲区8 f) a' H' I4 B- m$ C8 l+ ?
          Rx_Index = 0;// 重置索引! |8 Q0 o! X7 S& L4 s8 ?
          Data_Flag = 1;// 数据标志位
, w: G+ Y* L& p6 R  X3 Y    }
! H0 l; u) n) L. }8 [    else( b3 p. _- ]+ u: h  h7 [
    {
. V6 w* f1 c  a5 \# e          Rx_Index++;// 增加索引,准备接收下一个字符
) G0 g' c  _, w- W4 f& w$ q    }4 J& O8 m1 a1 Z7 f5 k
    }; Q0 Z+ O3 l3 T' ]( b
}[/code]% n9 F: d" Z2 A7 q" o' S
2 l9 O# |8 V, q( E
Usart1:串口中断接收以“$”开头,“#”结尾的数据

0 h  {: ^" Y7 v7 W1 B5 L
4、SysTick.c
[        DISCUZ_CODE_7        ]
使用系统滴答定时器来控制延时
7 z; m0 X; W. Z3 n% y1 U! {+ H3 w
五、实践
通过串口发送指令控制舵机(180°舵机演示)
1、UartAssist
注意:串口、波特率、以及数据格式等
) f8 F( ]9 r1 L
2、现象
180°/270°舵机可以通过串口发送的指令控制舵机旋转的角度;
360°舵机可以通过串口发送的指令控制舵机旋转的方向和速度。

3 o$ A$ u  g+ e
转载自: W-ML
如有侵权请联系删除
0 K) g9 Q' |, `* @/ g/ {/ e
3 v& [; }; e% P
3 u; w1 c9 K7 A) @* q+ b! l
) F9 g* _( V' F/ d7 {" ~) z, Z3 m

, v9 n: I; a' u5 f* T
收藏 评论0 发布时间:2023-9-21 14:07

举报

0个回答

所属标签

相似分享

官网相关资源

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