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

【项目分享】基于STM32超声波避障小车

[复制链接]
STMCU-管管 发布时间:2020-10-9 10:44
【项目分享】基于STM32超声波避障小车7 U! u% P( I& i  P# M

* X, y' C9 ?/ X7 a; X  V! b
8 ]0 v6 K- ^& x. E% m) N不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车。这也是我曾经的一个课设,在此开源分享给大家,全文5000多字,干货满满,加油读完,保证你收货多多2 [! L. f+ k: g$ p, W5 V% \

# w0 u3 l0 I  `" S- z; V3 x! H/ D
, H% |5 ?2 I8 W+ M' L5 l

. @5 ?: r" I% O+ T& s处理器电路设计" f+ V9 }/ A- Y1 q
单片机是系统的CPU,是系统稳定、正常运行的重要前提,以下为单片机选型的两种方案:
% c3 ]; J2 e8 Z, [% T8 y6 l(1)传统的8位单片机,是通过超大规模集成电路对其进行集成为一个独立芯片的控制器。内部组件包括CPU、随机存储器、只读存储器、I/O接口、中断系统、计时器、串口通讯、数模转换等。STC89C52单片机是最常见的51单片机,但是资源较少,精确度低,处理速度相比STM32单片机差很多。: v0 p; {& Y2 F( L6 K: m  p2 ]9 `
(2)使用目前市面上最常见的STM32单片机,STM32系列单片机可分为ARMCortex-M3内核体系结构的不同应用领域。它可分为STM32F1系列和STM32F4系列,STM32F1系列单片机时钟频率最高可达72米,在同一产品中性能最好。单片机的基本处理速度为36米,16位单片机的性能也很好。微晶片的内建快闪记忆体相当大,范围从32kb到512kb,可视需要选择。单个设备的功耗非常低,仅360mA,32位单片机产品的功耗最低,每兆赫只有0.5安培。特别值得一提的是,内接单晶片汇流排是一种Harvard架构,可执行速度高达1.25 DMIPS/MHz的指令。此芯片越来越多地被用作主要控制器。8 ^( s6 g' B; d1 H
   通过对单片机的资源和处理时间的速度我们采用选择STM32103C8T6为本系统主控芯片,程序下载是只需要一个JLINK就可以轻松完成。控制器模块电路如下所示:: ~& w: ?; _6 Q: T' a! K
2.png
$ U! @' k1 w$ g' ^电源模块设计1 N0 r8 x/ T) X9 I
本设计采用锂电池供电, 模块的供电电压一般都为5V,同时超声波模块需要较大的电流才能正常工作,所以在降压的基础上也要保证足够大的输出电流。本设计采用可调输出版本,模块的输入电压范围广,输出电压在1.25V-35V内可调,电压转换效率高,输出纹波小。降压电路如下所示:
/ Z- `8 ~( ]0 V: B  |7 R 3.png
! o0 p% l+ d8 d4 ^4 p1 p电机驱动模块设计
8 H2 Z- P6 L) ?2 Z" O要完成转向是能够利用单片机实现的,然而单片机I0的带负载能力弱,因此我们选择了大功率放大器件TB6612FNG。TB6612FNG是采用MOSFET-H桥结构的双通道大电流电路输出,可以控制2个电机的驱动。相比普通的电机驱动,外围电路非常简单,只需要一个芯片和一个钽电容进行PWM输出滤波,系统尺寸小。PWM信号输入频率范围广,轻松满足本设计的需求。   
' V& k! J. V5 L8 ^1 Z: W! U 4.png ' P* v2 e  k" i: O
电机驱动引脚表
9 ~. x" O4 K; B( t8 m
  1. 1控制芯片:TB6612
    . H4 W6 T6 q; h
  2. 2控制芯片数量:2; _0 E5 `2 [( S5 u* a' g& G. M
  3. 3    1号TB6612引脚分配:
    , `7 O  ?8 t9 M" {3 {$ B
  4. 4     VM         PWMA--------->TIM1_CH1(PA8)( c' F, Z. @( W5 V3 q& g4 j
  5. 5     VCC        AIN2--------->GPIOB_120 q6 X9 T7 F+ y: A) x
  6. 6     GND        AIN1--------->GPIOB_13
    $ U7 w: i* M- O% m) P/ L
  7. 7     AO1        STBY--------->GPIOB_14) d6 q1 J3 E2 Q* n% i: k; ]0 Z, O
  8. 8     AO2        BIN1--------->GPIOB_15
    7 j% k+ I0 X! U' }5 m) E+ q
  9. 9     BO2        BIN2--------->GPIOA_12, D! P1 ^' ?. U5 y* h4 p+ G, E
  10. 10     BO1        PWMB--------->TIM1_CH2(PA9)
    " J6 t1 I  |; g; `' k  F$ m% R
  11. 11     GND        GND4 d5 A) j; c7 U' ], Q
  12. 12    2号TB6612引脚分配:1 [1 w* H) P% d1 K
  13. 13     VM         PWMA--------->TIM1_CH3(PA10)$ i; J7 d8 C* u1 X6 e4 m1 A, U
  14. 14     VCC        AIN2--------->GPIOB_5
    ' s  M7 [' D4 R  E/ N
  15. 15     GND        AIN1--------->GPIOB_69 g" h: n+ {( ~  m1 [* A
  16. 16     AO1        STBY--------->GPIOB_7. b$ ?: F% O* Y- w/ w- R: W
  17. 17     AO2        BIN1--------->GPIOB_8
    1 G: u$ Z/ _$ V- e5 {* f! i/ \
  18. 18     BO2        BIN2--------->GPIOA_9
    * n5 Z- ~7 K+ x8 j! N7 }
  19. 19     BO1        PWMB--------->TIM1_CH4(PA11)
    : ^! N1 C5 {* e1 H$ x  v
  20. 20     GND        GND; L  i$ z, V" Z! d2 J9 a/ [
  21. 21真值表
    : F; n' u+ ?1 A* u
  22. 22     AIN1   0     1     0     1, f) H9 Q3 v  A' s$ B" A
  23. 23     AIN2   0     0     1     17 ?5 i( _" D# l" J0 T4 m! W% ?
  24. 24     BIN1   0     1     0     1) O6 ?, M2 T  p6 h% h. @# x
  25. 25     BIN2   0     0     1     1
    ; d) U" f! |& w* A  |. o
  26. 26           停止  正转  反转  刹车
复制代码
% r# @% p3 D3 m' z
1 z; l, G. m, z' k( G! s) z
电机所用到的定时器配置
( ]: u. `) _8 |+ n  v, X
  1. <font size="3">1//初始化TIMX,设置TIMx的ARR,PSC
    - `' }2 u. Z" a4 B
  2. 2//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期% r1 Q8 ~7 e9 W$ ~
  3. 3//定时器选择TIM1
    ! |& v& {% s3 o7 z" {: @5 k+ J
  4. 4static void TB6612_ADVANCE_TIM1_Mode_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty): b8 e" v4 s, R, c% m# O% f2 M
  5. 5{. a. L& H4 P1 B& }
  6. 6    //-----------------时基结构体初始化-------------------------/
    6 [5 K( ?6 C" e
  7. 7    TIM_TimeBaseInitTypeDef TIM_TimeStructure;* f- _) q% V6 }) X' h/ P
  8. 8    /*开启定时器1时钟,即内部时钟CK_INT=72M*/
    8 v1 R# L) t, }% ]4 M
  9. 9    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
    ' f4 ~( n1 F  o3 Z" V5 [
  10. 10    TIM_DeInit(TIMx);5 {! G0 k" J) t; D1 U* N+ c/ A
  11. 11    /*内部时钟作为计数器时钟,72MHZ*/
    ( p# r2 ^9 N7 v8 r
  12. 12    TIM_InternalClockConfig(TIMx);" c3 W: [1 v. m+ S6 }( y
  13. 13    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/
    $ U8 I4 c3 t/ ~/ U8 u
  14. 14    TIM_TimeStructure.TIM_Period=arr;
    ' n8 i0 t5 f& k6 j) S" N/ ~! w
  15. 15    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(71+1)=1MHZ*/
    8 Z+ F2 O" q( f/ g! j$ _5 Y
  16. 16    TIM_TimeStructure.TIM_Prescaler=psc-1;7 q. B9 Z. l7 b2 q0 y4 ~" G. Q
  17. 17    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/) Z" W2 \, X+ G2 D
  18. 18    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;  }$ M- L/ H) ^" Q% T1 G
  19. 19    /*向上计数模式*/0 Q% h; K1 |8 e4 N
  20. 20    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;/ _% ]3 I3 L" q% k
  21. 21    /*重复计数器*/
    - g; J( |$ C$ G* y
  22. 22    TIM_TimeStructure.TIM_RepetitionCounter=0;! y) G5 [: f; ?
  23. 23    /*初始化定时器*/7 `0 p: B9 O# N! D# _
  24. 24    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
    3 M4 c% `* H4 ^" |" V
  25. 25    /*使能ARR预装载寄存器(影子寄存器)*/& t+ ?1 m: g7 e% ?2 l% s3 {
  26. 26    TIM_ARRPreloadConfig(TIMx,ENABLE);5 n* b  @% a% ^" ?  g
  27. 27    //-----------------输出比较结构体初始化-----------------------/
    8 O2 q" K+ d$ y( B# T
  28. 28    TIM_OCInitTypeDef   TIM_OCInitStructure;8 z! l' I3 ~0 Z/ n4 z  X1 v! a* _" G
  29. 29    /*PWM模式设置,设置为PWM模式1*/
    6 w: q  t. O8 u
  30. 30    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    0 m- h2 K" [+ o3 E
  31. 31    /*PWM输出使能相应的IO口输出信号*// h' I) q/ W- G- Z. y
  32. 32    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;- `$ T  H' L+ E1 S
  33. 33    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
    0 T& X0 K6 i. K' r
  34. 34    TIM_OCInitStructure.TIM_Pulse=duty;
    ' `3 X/ X( M7 }. g$ {( ^1 E
  35. 35    /*输出通道电平极性设置*/
    % O, f4 R: ], ?; \, ^3 ~9 M* e; I
  36. 36    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
    $ i- m- m6 r& a
  37. 37    /*初始化输出比较参数*/
    ( Z$ N# p, I& K* `2 y( M& E# U
  38. 38    TIM_OC1Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道1
    ' [% W8 m" f. z
  39. 39    TIM_OC2Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道2
    ' u; C- s3 m( h6 r% [9 y: @
  40. 40    TIM_OC3Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道3) r" M+ d/ ^+ e" w6 j  @; L
  41. 41    TIM_OC4Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道4
    ; a' G4 e" G$ L& ?2 W
  42. 42    /*自动重装载*/2 J  v: h/ \/ K% m0 U4 A* d3 u" ~
  43. 43    TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable);
    ! m- H. X2 L3 p* A
  44. 44    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
    . H" |$ e7 N% |7 C
  45. 45    TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable);. n4 S8 ^, z% a; t6 h  f2 E+ [- M
  46. 46    TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable);+ B0 P; c. T3 V
  47. 47    /*使能计数器*/
    , W/ S* S, w# d5 Q( Y& n& @3 ^
  48. 48    TIM_Cmd(TIMx,ENABLE);$ |; h! w" m; M0 b
  49. 49    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/( a( ^4 ]6 j( D+ F% x
  50. 50    TIM_CtrlPWMOutputs(TIMx,ENABLE);    1 n3 a/ ]6 L% P& _0 T7 P
  51. 51}/ @& s7 G$ [% V' G5 v
  52. 52//高级定时器输出通道初始化函数
    # D2 k$ R# S9 d9 z8 F/ }
  53. 53static void TB6612_ADVANCE_TIM_Gpio_Config()
    9 q( F! e' v& E- L
  54. 54{
    - u; s0 q( t/ \8 i
  55. 55    GPIO_InitTypeDef  GPIO_InitStruct;
    ( i" \) C7 U! Q) b. G- |
  56. 56    /*----------通道1配置--------------*// x( U+ B" P0 z: L' {
  57. 57    /*定时器1输出比较通道*/
    , |; e6 g8 e3 E; b
  58. 58    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    6 y+ c( D, S$ [; q1 ]
  59. 59    /*配置为复用推挽输出*/
    , X" C$ j1 f. U
  60. 60    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    " _* ]2 P; k5 ?- c
  61. 61    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
    6 B& n  z2 @  [' g
  62. 62    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    % U. A. b2 }8 }! s
  63. 63    GPIO_Init(GPIOA,&GPIO_InitStruct);
    ) o4 U' c& u, Q  D- Y5 V
  64. 64    /*-----------通道二配置-------------*/' H% u) ^/ L2 @! U7 i  B7 w, K
  65. 65    /*定时器1输出比较通道*/6 z; k$ {$ z/ n, D7 z
  66. 66    /*配置为复用推挽输出*/; O% V# W$ ]! n
  67. 67    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    # M5 I6 B) @; A% Q
  68. 68    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;) ?! M& O+ |! w) j( A, Q
  69. 69    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;, Q0 r0 K/ H5 @6 }9 V8 ^* b8 N
  70. 70    GPIO_Init(GPIOA,&GPIO_InitStruct);
    3 d: O  P3 U* n. ?7 }
  71. 71     /*-----------通道三配置-------------*/# Q, Y- U2 @! w) Q: c% I- K4 v
  72. 72    /*定时器1输出比较通道*/- i# K! [% h2 W
  73. 73    /*配置为复用推挽输出*/
    3 J6 m3 `( _1 I
  74. 74    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;3 u" ^2 y0 A* W5 {% O, R" E
  75. 75    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;  R% [3 o- j# ~' J: h
  76. 76    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    ; z" K/ ]# P8 o% D" d6 \
  77. 77    GPIO_Init(GPIOA,&GPIO_InitStruct);2 G! d4 ^6 o6 m' R: B8 g0 [: W4 Y
  78. 78     /*-----------通道四配置-------------*/
    ! n' u# B- ~' I. S
  79. 79    /*定时器1输出比较通道*/& W4 i. R9 z9 S  w. o0 L, o
  80. 80    /*配置为复用推挽输出*/
    8 e. N, H9 s/ k2 m# J1 F% C
  81. 81    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    # D$ S7 W) n+ q+ g
  82. 82    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;1 N  R9 L9 m1 Z
  83. 83    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;, a" \( {& s$ F, d. ^$ v
  84. 84    GPIO_Init(GPIOA,&GPIO_InitStruct);
    8 \# i0 s/ f7 q  J9 @* d9 Q4 S- f
  85. 85}</font>
复制代码

+ i) i, {3 x1 q, E  M! K) E

9 |+ P3 s& _8 f. M
( [5 \- b- ^$ H+ y
超声波模块# Z5 z. E: z% B. l
) A$ \/ g# X! @# u* \
2 _) I9 w& f* X! w' o4 J" C
采用HC-SR04超声波模块,该芯片具有较高的集成度以及良好的稳定性,测度距离十分精确,十分稳定。供电电压为DC5V供电电流小于10mA,探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)。HC-SR04实物图如下:
" E; K" C  \! G  y 5.png 4 R, S& d! l& b( M% D$ t; C: w' Y
该模块是利用单片机的IO触发电平测距,单片机内部利用普通定时器产生一个高电平信号之后,超声波就可以自主发送频率为40khz的方波,然后等待信号的返回;若有信号返回,单片机IO口就立刻输出一高电平,利用高电平产生的时间可以计算小车与障碍物的距离。最终距离就是高电平持续时间乘以声音在空气中传播的速度再除以2,可以反复测量距离。( ~  W# Q, K6 s" C
  在程序开始首先初始化超声波,利用定时器并设置时基的自动重装载初值1000,psc为预分频值72,这样的话我们产生一次中断的时间是1ms,并设置抢占优先级0,子优先级3。HC_SR04_Echo引脚接收到高电平,打开定时器,且每1ms进入一次中断。在测量时首先让Trig发送一个大于10us的高电平,然后拉高HC_SR04_Trig,当Echo为0时打开定时器计时,当Echo为1时关闭定时器,通过公式计算距离。
+ _2 ^; S$ E% T4 i- D5 V1 X模块工作原理:
/ ?+ U* r$ w9 r4 V4 D9 b, a(1)单片机触发引脚,输出高电平信号;
+ m: A9 E8 @! D(2)模块发送端自动发送特定频率的方波;* o- x3 o/ r: I
(3)如果有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波的发射时长;
+ N6 @+ ]9 x9 Q$ ?' t* b/ \5 ?(4)测试距离=(高电平时间*声速(340M/S))/2。
" d/ R  F9 G: N1 ^
注意:在硬件操作上需要首先让模块地端先连接,否则会影响模块工作。测距时,被测物体的摆放不能太过于杂乱,否则会影响测试结果。+ u+ E+ b9 E4 X2 {* k( w. L
6.png
1 H8 b8 V" F# k5 N1 f( }/ m( }超声波重要代码(可参考)
4 m& p) L! ?) |8 y! V: j, X1 U
  1. 1/* 获取接收到的高电平的时间(us*/
    7 @; M5 u; w2 [1 r+ N% P. A
  2. 2uint32_t Get_HC_SR04_Time(void)
      l7 P. N& }+ R
  3. 3{% ]6 F. {# a9 o' d8 z$ e7 o1 ?
  4. 4    uint32_t t=0;
    " U' T. Z' |  [. o3 F' t; R
  5. 5    t=Acoustic_Distance_Count*1000;//us4 x  L& [0 R4 L" g( Q; ]
  6. 6    t+=TIM_GetCounter(TIM2);//获取us0 Y. `" K* d# S; U. H
  7. 7    TIM2->CNT =0;
      {) s* x9 v9 P
  8. 8    Acoustic_Distance_Count=0;
    & t+ ~+ E' I5 V+ [9 [9 c
  9. 9    Systic_Delay_us(100);8 g. d$ s; f) l" v8 r# S
  10. 10    return t;
    ; _4 d% T3 _! m" K, B: ~6 U
  11. 11}
    ! I4 x) w/ j. ~+ Z4 g
  12. 12/*获取距离*/
    ! Z" H$ z0 \+ i/ R0 s- y4 v+ Z
  13. 13void Get_HC_SR04_Distance(void)3 a* b: f+ b6 _+ i
  14. 14{
    / \/ j7 K6 D( Z
  15. 15    static uint16_t count=0;7 o# d5 i0 T- u% h1 A) Z
  16. 16    switch(count)
    1 F  z# y% G1 Q4 q' U) C
  17. 17    {7 O1 P- i; T2 b. Y$ j1 I8 ?- g
  18. 18        case 1:
      D' p! e. v" Q. ]
  19. 19        {
    5 ~8 s+ R6 f0 T
  20. 20            GPIO_SetBits(Acoustic_Port,HC_SR04_Trig);//Trig发送一个大于10us的高电平
    ) I" Y- M- _$ Z; U
  21. 21        }break;
    2 Q) [) B6 }4 b& X2 N
  22. 22. A& X- T: s* W0 t) `
  23. 23        case 15:
    / ^' _% \7 T0 ~$ Z2 c
  24. 24        {
    5 h/ V7 X5 K& f& G# p1 p0 n
  25. 25            count=0;4 U) b. F. I+ m& C1 ~: E; x# |
  26. 26            GPIO_ResetBits(Acoustic_Port,HC_SR04_Trig);
    4 T( `+ n$ C, E0 L" K6 `3 l
  27. 27            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==0);//当Echo为0时打开定时器 计时$ s- W% Q" a; @: v6 w7 Q
  28. 28            Open_Tim2();
    + ^9 n, t/ G! d: y. x+ b
  29. 29            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==1);//当Echo为0时打开定时器 计时: b2 c" N' g7 x; d$ \6 r0 M
  30. 30            Close_Tim2();+ _2 Q6 V  p! L9 P. b( l
  31. 31            HC_SR04_Distance=(float)(Get_HC_SR04_Time()/5.78);
    5 X# Y* g6 d( O
  32. 32+ `: ^" F8 O2 ^
  33. 33        }break;* o0 S2 x9 X- I* I7 ]& A+ o
  34. 34        default:break;# o& q2 `: l6 P  i' m: s+ \( Y
  35. 35    }
    6 Z! t$ q2 B3 N/ k3 R/ H
  36. 36    count++;! v4 t0 R' p# q; ?; d, L$ @
  37. 37}
复制代码

6 [  d( z/ M) z& m- Z! v
- Z7 a6 F# k# r& O6 K3 G" ~0 Z/ @
/ G. B4 {+ u$ n+ H# \2 J" ^
% f1 P$ t" H. l# ?' A5 s* r

) F4 o4 N5 `8 [1 ^3 W7 g6 G
舵机模块
- p, V$ I- ^- o$ j8 M
   
8 X# v; c( [4 q& K$ l
本系统使用的是SG90型号的舵机,舵机是一种常见的角度驱动器,本系统需要判断不同位置的障碍物可以且对转向的力度小。舵机可以理解为方向盘称,方向盘是一个常见的名字。它实际上是一个伺服马达。舵机实物图如下:
, y1 _2 l) ]" e 7.png   b! _* N8 y9 d+ E
舵机模块接口简单,舵机模块只有三个引脚。分别引引出了三根线左右两边是电源正负接口线,中间一根是PWM信号线直接连接单片机的控制引脚。通过控制单片机的引脚输出的脉冲宽度进而控制舵机旋转的角度。舵机每增加0.1ms 舵机对应增加9度。! H( V' G9 M# M% v, D( {- E
0.5ms---------0' z" n& h# s7 t/ m8 S
1.0ms---------45  
$ L& Q: Y' L( E1.5ms---------90
. q# y+ G/ f4 m# z2.0ms---------135
+ E; R; ]- d3 S, C  |0 t* T. ?2.5ms-----------180
! o1 y1 i7 w2 V/ {. ]   20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平持续时间为1.5ms,周期为20ms的方波,duty=1.5/20=7.5%。在这里设置定时器自动重装载寄存器arr的值为1000,所以当占空比为百分之75是,在程序中就要设置占空比为75/1000=7.5%, 这就是具体的算法。- L( b/ _0 }$ n1 s! U
舵机重要代码(可参考)
; {/ O) N/ {+ B1 x) D) U! ?
  1. 1/**PWM引脚初始化*/, b; o: i( A  p8 h' [+ G
  2. 2static void SERVO_Gpio_Init(void)2 S1 z# j. q4 w
  3. 3{
    9 P( J1 x6 L9 u, @6 @
  4. 4    GPIO_InitTypeDef  GPIO_InitStruct;0 d3 u6 L9 a: G/ s+ E, z! s
  5. 5    /*----------通道2配置--------------*/
    ; h; f2 Z: B. @- F4 x; L+ C% e
  6. 6    /*定时器3输出比较通道*/
    2 k" G4 |* ~# y( y/ g# ^
  7. 7    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);- k9 B! K8 Y. o6 d- G- Y" m
  8. 8    /*配置为复用推挽输出*/
    2 e, k8 G( B1 N" G, g
  9. 9    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;6 _) z% z& W( }+ N
  10. 10    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
    / x2 f1 B# ^# b  P) R- ]
  11. 11    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;% P. j3 Y0 m" j. E' J
  12. 12    GPIO_Init(GPIOA,&GPIO_InitStruct);
    2 b' v/ U! j' F: E+ d  d
  13. 13}& a" P- Q. N& N  l& j0 q+ z7 X4 R
  14. 14//定时器3初始化,设置TIMx的ARR,PSC
    % J7 S: _  c: z& P: N) @
  15. 15//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期
    ) D8 L, q" c! K; R- }- R
  16. 16static void SERVO_TIM_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)9 t) `  Q# L  J, S
  17. 17{8 a1 v. k: L# u9 z5 I9 `' ~+ [# {, ~
  18. 18    //-----------------时基结构体初始化-------------------------/
    5 T; o/ M0 }1 `8 {! ]+ ?# q& b
  19. 19    TIM_TimeBaseInitTypeDef TIM_TimeStructure;
    % M5 J- s( p0 S4 C
  20. 20    /*开启定时器3时钟,即内部时钟CK_INT=72M*/4 \9 L' ~* ^& B% D+ S; V1 o4 s. ^
  21. 21    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    ! H. t6 b: I4 O( c$ z3 E0 b
  22. 22    TIM_DeInit(TIMx);
    ; }2 ~6 P+ X7 p! J
  23. 23    /*内部时钟作为计数器时钟,72MHZ*/; p& W' l- T& N( }' S
  24. 24    TIM_InternalClockConfig(TIMx);" M9 {1 Q8 r( t7 V1 e
  25. 25    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/& c6 B9 l' L8 I2 q' a5 F0 T
  26. 26    TIM_TimeStructure.TIM_Period=arr;//1000 当定时器从0计数到999,即1000次,为一个定时周期
    $ R; c6 b5 _6 S+ Q
  27. 27    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(1440-1+1)=0.05MHZ*/7 S& Z. y- B5 X0 ]% P: C
  28. 28    TIM_TimeStructure.TIM_Prescaler=psc-1;;//1400  //即定时器的频率为5KHZ   
    6 i2 i& R2 P/ M) w4 ?" z
  29. 29    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
    % d8 U( Z  T4 ]
  30. 30    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;. f% |9 l  c& u& K/ t$ r
  31. 31    /*向上计数模式*/
    , ?- W) _! M7 |& L# J: ?4 \: F3 b
  32. 32    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
    * c  m3 N7 Z' q6 ?( Z  L
  33. 33    /*重复计数器*/
    # N0 \' [, e1 m6 a( |* L5 K& F
  34. 34    TIM_TimeStructure.TIM_RepetitionCounter=0;3 s" g6 Z3 K$ D, w
  35. 35        /*初始化定时器*/
    # O1 v. i4 y3 n9 c% X9 k
  36. 36    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
    5 Y. i6 X9 K% ]1 E7 A
  37. 37    /*使能ARR预装载寄存器(影子寄存器)*/! n: n9 S9 s8 d% [1 V
  38. 38    TIM_ARRPreloadConfig(TIMx,ENABLE);
      E- i! M9 R0 s: c6 w
  39. 39    //-----------------输出比较结构体初始化 开始-----------------------/" l5 h3 ^5 O+ f$ p* P* P
  40. 40    TIM_OCInitTypeDef   TIM_OCInitStructure;
      L: X* d* ?/ G7 F; G
  41. 41    /*PWM模式设置,设置为PWM模式1*/
    6 Q1 V( ]! X  S
  42. 42    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;/ N9 `6 _; k! H- X& j1 T7 t
  43. 43    /*PWM输出使能相应的IO口输出信号*/
    $ X5 Q- O3 w6 u1 D+ ~6 C
  44. 44    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;& Z. n4 p0 d# a0 y: p
  45. 45    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
    9 f" v. |, D# _8 P: a# G5 o' }
  46. 46    TIM_OCInitStructure.TIM_Pulse=duty;   //占空比大小8 E$ z9 D+ A2 M0 X  a# |* Q
  47. 47    /*输出通道电平极性设置*/
    & P) Y' G" _( U3 X8 D
  48. 48    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;+ h3 G+ Z7 I, j
  49. 49    /*初始化输出比较参数*/8 r$ B6 y. h! s3 r, ]
  50. 50    TIM_OC2Init(TIMx,&TIM_OCInitStructure);6 t8 Y, o8 [+ d
  51. 51    //-----------------输出比较结构体初始化 结束-----------------------/      u0 q4 u% M  M8 V+ ]2 |- t5 X# i
  52. 52    /*自动重装载*/, q9 ~$ e' b6 T0 x8 s9 G: v
  53. 53    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
    4 L% @6 M/ o2 n& H4 b) |
  54. 54    /*使能计数器*/! R0 ~5 \" L, x  I% Y1 _7 ?" G3 w
  55. 55    TIM_Cmd(TIMx,ENABLE);
    ' X4 @  k0 N; p: r
  56. 56    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
    ) U" I: }0 r" a% }# f
  57. 57    TIM_CtrlPWMOutputs(TIMx,ENABLE);   
    + i& l& h/ @0 z7 t* D* o
  58. 58}
    9 \6 h$ `; p4 |: q! K0 R
  59. 59/*舵机PWM初始化
    ; h, h% L& U- ~: v+ W/ N$ u: M* z
  60. 60   每增加0.1ms 舵机对应增加9度
    . b7 o# O# e2 }# X
  61. 610.5ms---------0
    0 r8 ^) G' x' c  K* Z/ J- s' c, q- _
  62. 621.0ms---------45   
    0 A4 R3 _0 \7 C3 w- C3 G$ C: _* `
  63. 631.5ms---------90
    : u- s) r* i' p- i% |
  64. 642.0ms---------135
    1 L; u( @/ H0 U& Q5 C" b6 _
  65. 652.5ms-----------1802 J% V  t& H. _  `8 |/ u8 S
  66. 662.1ms    turn_left=150% S) U0 R8 U' x; [1 P! ~: r7 S$ W  h
  67. 670.8ms    turn_right=25" l4 h+ d- f* v  _' `
  68. 681.3ms    turn_front=75: a7 H: e' m+ C+ U
  69. 6920ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平为1.5ms,周期为20ms的方波,duty=1.5/20=7.5% ,而定时器自动重装载寄存器arr的值为 1000 ,所以duty=75,时占空比为75/1000=7.5%. 2 Z/ j; r9 Q2 p5 u5 }
  70. 70*/3 X; j) w+ P; m# G. u
  71. 71void SERVO_Init(void)
    $ m- D9 s" m5 I: c! l: V) e$ W" a
  72. 72{& u( E) c7 y3 `( I% L# C4 ]! R0 S
  73. 73    SERVO_Gpio_Init();+ \$ L. d# ^- k& K8 I- K3 u8 w. m1 g
  74. 74    SERVO_TIM_Config(TIM3,1000,1440,turn_front);4 n% d" ^, H+ Z) @' z
  75. 75/** 我们把定时器设置自动重装载寄存器 arr 的值为 1000,设置时钟预分频器为 1440,则
    " U5 D" o- |9 [1 f0 F2 A7 x
  76. 76驱动计数器的时钟:CK_CNT = CK_INT / (1440-1+1)=0.05M,则计数器计数一次的时间等于:
    " x5 B$ V2 v# I; x0 t' C% \
  77. 771/CK_CNT=20us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间. z1 u, p% [9 Y) T" }$ ^' g/ S. n
  78. 78为:1/CK_CNT*ARR=20ms。
    7 Z. o* {& n, }: E
  79. 79PWM 信号的频率 f = TIM_CLK/{(ARR+1)*(PSC+1)}  TIM_CLK=72MHZ
    3 `. M5 L' ]3 ~: L4 C* f. j
  80. 80               = 72 000 000/(1000*1440)=5KHZ    1 V8 `* N; A1 f
  81. 81*/    2 p, T9 P2 ~+ s& K3 [7 e( p5 k
  82. 82}
    9 W' r8 \8 [5 d- j, W) {. R0 ?. B
  83. 83/*舵机角度控制*/) `8 u# e; r( _; ^/ j& R
  84. 84void SERVO_Angle_Control(uint16_t Compare2)9 n; p  ^2 Z# E2 _
  85. 85{; R' E; ^6 U! y# S- j1 f8 e
  86. 86    TIM_SetCompare2(TIM3,Compare2);( K' n# N& q: {
  87. 87}
复制代码
* }( s2 K5 `+ o! x1 h

  I" L# H% f+ _' p) Q% U  E2 b- |
编码器模块
3 C9 T4 f) t1 q! b3 x) `4 u1 R# M
/ c4 R4 \* z/ w0 M, e* c9 ]0 {
调节小车前进的速度和避障快慢我们采用EC11旋转式编码器,可以用于光度、湿度、音量调节等参数的调节。EC11编码器的形状类似于电位器,中心有一个旋钮可以调节PWM信号,光电码盘利用光电转换原理输出三组方波脉冲。EC11编码器的实物图如下:: j. q1 ?' v2 B+ y* ?2 b! L6 p& }
8.png
6 P7 K' i3 I/ ]( |0 g; h0 x  {
4 v$ M7 P% E* r6 o& ?: g
OLED显示模块2 I! R/ K" S4 J/ |! O4 L

  ^* x0 ~- e" [1 A5 w8 K! w  [
用来显示小车转速,以及左右编码器数值和电池电压等参数所用的是OLED显示模块,分辨率较高,而且功耗低,正常显示时仅0.06W,供电电压范围在3.3V-5V,有IIC和SPI两种通信协议可供选择。显示模块的亮度和对比度可以通过程序设置。由于它使用寿命长以及其他的优点,OLED更加适合小系统,本系统由于单片机引脚有限,不适合利用简单的LCD1602或者12864来显示,在多方对比之下OLED效果更好。OLED显示部分相对比较简单,大家参考中景园的例程就可以实现。2 W5 |4 [* A! }6 m

& |% w( P2 Q' x6 E- d6 Z' O

) w/ N0 n* ^$ ?/ U
2 x$ f, K5 Z& B  \+ [+ L. L

4 j  q2 D9 S2 u$ X文章出处:程序员小哈6 ^' ~4 a/ t* u" H; r# R7 F6 L
收藏 4 评论1 发布时间:2020-10-9 10:44

举报

1个回答
老牛洋车 回答时间:2020-10-9 12:15:04
不错的资料,期待后续。

所属标签

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