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

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

[复制链接]
STMCU-管管 发布时间:2020-10-9 10:44
【项目分享】基于STM32超声波避障小车
  Y/ i9 a2 K2 e/ N" o9 n4 Q5 X. D3 M% u+ S

/ ]7 l* y( g/ X4 I, x不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车。这也是我曾经的一个课设,在此开源分享给大家,全文5000多字,干货满满,加油读完,保证你收货多多7 A& x+ n# G7 y. o  y2 o
$ v. h# G/ @3 X1 }' [! v
0 h- Y" f1 I/ I5 \% Q/ h4 A7 b7 |! q
& ~% f8 _5 _  F
处理器电路设计
! {& J+ y" N" U- H) m( g, S" J! V! m单片机是系统的CPU,是系统稳定、正常运行的重要前提,以下为单片机选型的两种方案:
' i4 Q6 b2 [2 p5 i# N(1)传统的8位单片机,是通过超大规模集成电路对其进行集成为一个独立芯片的控制器。内部组件包括CPU、随机存储器、只读存储器、I/O接口、中断系统、计时器、串口通讯、数模转换等。STC89C52单片机是最常见的51单片机,但是资源较少,精确度低,处理速度相比STM32单片机差很多。2 d- j4 r! ]# R) n! X
(2)使用目前市面上最常见的STM32单片机,STM32系列单片机可分为ARMCortex-M3内核体系结构的不同应用领域。它可分为STM32F1系列和STM32F4系列,STM32F1系列单片机时钟频率最高可达72米,在同一产品中性能最好。单片机的基本处理速度为36米,16位单片机的性能也很好。微晶片的内建快闪记忆体相当大,范围从32kb到512kb,可视需要选择。单个设备的功耗非常低,仅360mA,32位单片机产品的功耗最低,每兆赫只有0.5安培。特别值得一提的是,内接单晶片汇流排是一种Harvard架构,可执行速度高达1.25 DMIPS/MHz的指令。此芯片越来越多地被用作主要控制器。
- D7 j2 u- ~3 B* R   通过对单片机的资源和处理时间的速度我们采用选择STM32103C8T6为本系统主控芯片,程序下载是只需要一个JLINK就可以轻松完成。控制器模块电路如下所示:
) d0 J: N5 I: W* {3 ^- r  s. G 2.png + ]. ^0 @5 M4 w8 `/ m' x
电源模块设计
; X# c2 b" b* O3 U4 X* B本设计采用锂电池供电, 模块的供电电压一般都为5V,同时超声波模块需要较大的电流才能正常工作,所以在降压的基础上也要保证足够大的输出电流。本设计采用可调输出版本,模块的输入电压范围广,输出电压在1.25V-35V内可调,电压转换效率高,输出纹波小。降压电路如下所示:
  C3 P* a. ?2 m; z1 X 3.png , \" ~0 z2 ?/ m
电机驱动模块设计
, j6 [! U. r6 E. i要完成转向是能够利用单片机实现的,然而单片机I0的带负载能力弱,因此我们选择了大功率放大器件TB6612FNG。TB6612FNG是采用MOSFET-H桥结构的双通道大电流电路输出,可以控制2个电机的驱动。相比普通的电机驱动,外围电路非常简单,只需要一个芯片和一个钽电容进行PWM输出滤波,系统尺寸小。PWM信号输入频率范围广,轻松满足本设计的需求。    * q" b$ |6 e5 Y" Q. M% N
4.png
1 c9 X5 g- I$ z# B: ?3 X电机驱动引脚表
! M' u( Y5 j! `' z
  1. 1控制芯片:TB6612
    0 c' y% v% q9 Q$ X% N
  2. 2控制芯片数量:2
    % ^5 _1 k8 B1 P0 i0 X0 V
  3. 3    1号TB6612引脚分配:9 L0 }5 Y" E. R& }' y0 ?7 d( g
  4. 4     VM         PWMA--------->TIM1_CH1(PA8)+ g6 |2 Y: z$ P
  5. 5     VCC        AIN2--------->GPIOB_12
    & }9 a( ~+ r4 \* J- S% j( ~0 o
  6. 6     GND        AIN1--------->GPIOB_13* i! q0 a" m8 Q
  7. 7     AO1        STBY--------->GPIOB_14& A! z" F& S& D1 k8 t
  8. 8     AO2        BIN1--------->GPIOB_15
    $ f" R2 {6 L4 @5 z  ~* o7 l
  9. 9     BO2        BIN2--------->GPIOA_12
    ) e, P: H, ^- Y9 I8 w% s
  10. 10     BO1        PWMB--------->TIM1_CH2(PA9)* _! E3 A5 r7 \) f& K& r
  11. 11     GND        GND+ n) _$ v" ^0 N4 [0 @! i* r: a
  12. 12    2号TB6612引脚分配:3 S* O2 G+ o2 V' ]' L2 ^# A6 ^3 {6 J
  13. 13     VM         PWMA--------->TIM1_CH3(PA10)
    $ l6 t& R' ^% X9 V) R
  14. 14     VCC        AIN2--------->GPIOB_5+ J3 ^( Z$ M; S. b- Z; S
  15. 15     GND        AIN1--------->GPIOB_6
    2 D! G; Q; B  S
  16. 16     AO1        STBY--------->GPIOB_7
    : K5 N, x9 i* o2 M
  17. 17     AO2        BIN1--------->GPIOB_82 j* i9 U0 U8 U, ?3 r8 q6 k( M& @
  18. 18     BO2        BIN2--------->GPIOA_9
    - J. h' `- {. i8 x$ L
  19. 19     BO1        PWMB--------->TIM1_CH4(PA11)
    - T' k8 {( M% G8 S0 b
  20. 20     GND        GND
      O! h! I; o! K. K
  21. 21真值表
    ; }$ |$ L( A; a9 q" {$ L' H8 I
  22. 22     AIN1   0     1     0     1# P1 c' W7 e: j! P
  23. 23     AIN2   0     0     1     19 e5 n; L- _# L$ t9 U
  24. 24     BIN1   0     1     0     1
    , o. R5 b( u. m: |, R) ]
  25. 25     BIN2   0     0     1     1$ i/ B! B4 H3 y, Y5 F
  26. 26           停止  正转  反转  刹车
复制代码
8 I# @& e  {6 u! w

8 v% o+ O% A3 O5 L: L: [/ p电机所用到的定时器配置
" H% `) l) {, f' J# q
  1. <font size="3">1//初始化TIMX,设置TIMx的ARR,PSC
    ) z& s+ a$ ^+ Z& u: h+ ^6 U
  2. 2//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期
    ' n$ U+ m% m! x
  3. 3//定时器选择TIM12 F* z1 r% \' u& D" p' K* C
  4. 4static void TB6612_ADVANCE_TIM1_Mode_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)8 M( D+ o; @" p" V: T
  5. 5{
      f: K2 l1 P. q& \0 V! I. P. v+ d
  6. 6    //-----------------时基结构体初始化-------------------------/0 M! `; }- v1 p2 X* g
  7. 7    TIM_TimeBaseInitTypeDef TIM_TimeStructure;
    5 ^- Z& F* E  v5 I: j0 n- I
  8. 8    /*开启定时器1时钟,即内部时钟CK_INT=72M*/
    7 V- P- m  }- X" [* C3 {- m: u: h
  9. 9    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);$ {% j# X' C5 G% `& K: d/ a5 d% H
  10. 10    TIM_DeInit(TIMx);
    - W; D: u0 K! D8 J, a4 u
  11. 11    /*内部时钟作为计数器时钟,72MHZ*/
    # @" F( g8 m3 e" N& Y
  12. 12    TIM_InternalClockConfig(TIMx);
    ; [7 e" ?! o8 E( b# Y( o1 F' v
  13. 13    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/
    : m7 I! q9 `* O% D2 P$ t
  14. 14    TIM_TimeStructure.TIM_Period=arr;
    : l* S7 o& y- X
  15. 15    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(71+1)=1MHZ*/: M  ^" f2 S+ q( d* b) S- [2 t1 r
  16. 16    TIM_TimeStructure.TIM_Prescaler=psc-1;
    # r8 [; p4 r4 {) x
  17. 17    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/6 J* k" N# q" N% B- j
  18. 18    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;5 A( P/ }/ s+ l+ z
  19. 19    /*向上计数模式*/
    / z- a" ~# ?' c% e' E6 h& L3 ~
  20. 20    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
    4 r, g6 @4 D) h0 L
  21. 21    /*重复计数器*/
    3 M. b, k( T8 |; a+ L0 e9 n
  22. 22    TIM_TimeStructure.TIM_RepetitionCounter=0;. f, ?% M  p  J/ h
  23. 23    /*初始化定时器*/2 s9 S! Y1 l8 N: k
  24. 24    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);% Y* u8 w/ Z  |8 {0 ]1 g
  25. 25    /*使能ARR预装载寄存器(影子寄存器)*/
    # H7 a8 b6 {; i8 L
  26. 26    TIM_ARRPreloadConfig(TIMx,ENABLE);- n/ s1 I& C' G8 |( d* G; ^
  27. 27    //-----------------输出比较结构体初始化-----------------------/4 r$ F+ u, U# z; R
  28. 28    TIM_OCInitTypeDef   TIM_OCInitStructure;4 d8 c! x0 U" J& ]) j
  29. 29    /*PWM模式设置,设置为PWM模式1*/% {- g, T, D' h1 L5 v
  30. 30    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;! D. D. `6 F5 Y: ~* k
  31. 31    /*PWM输出使能相应的IO口输出信号*/
    : y4 }, t1 o" b; p0 g1 Z( N# _
  32. 32    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;5 `, O' i% Z& y
  33. 33    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/1 {& V) W9 y) E1 |
  34. 34    TIM_OCInitStructure.TIM_Pulse=duty;
    & N4 e8 y. A  D" w/ Q5 [. _
  35. 35    /*输出通道电平极性设置*/$ E/ p" v6 U4 M! p0 Z
  36. 36    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
    ' Y% m. }; A$ v7 t7 H# \4 i
  37. 37    /*初始化输出比较参数*/4 T& B. N% I  f9 d3 x1 o$ h" \
  38. 38    TIM_OC1Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道1
    0 p% T; e" V0 p4 i- ^( W. U) {
  39. 39    TIM_OC2Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道2
    6 }/ ^2 |2 N4 X, @) I2 L( ^
  40. 40    TIM_OC3Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道3! e$ l4 `3 w8 x& I
  41. 41    TIM_OC4Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道4+ l( E# q# J& f/ f6 [
  42. 42    /*自动重装载*/
    + @9 f* q6 x) O- P6 `7 k1 M
  43. 43    TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable);
    7 [6 f- O; e, x3 u. Z3 }5 x
  44. 44    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
    ! ?; P  A8 i8 g: l
  45. 45    TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable);
    : G: M2 l3 B! ?; M+ v7 U0 j
  46. 46    TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable);( W% O3 T" j; w6 v
  47. 47    /*使能计数器*/# R7 L3 p- j; _" L
  48. 48    TIM_Cmd(TIMx,ENABLE);- Z6 a- F) p% g, Z- f' U' @& M
  49. 49    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
    & I: K# p2 v4 R/ m
  50. 50    TIM_CtrlPWMOutputs(TIMx,ENABLE);    ' b( k6 R1 ?" J0 z
  51. 51}4 p; J9 {1 Z, h/ ?0 K  T
  52. 52//高级定时器输出通道初始化函数
    7 v8 L+ z0 J2 G
  53. 53static void TB6612_ADVANCE_TIM_Gpio_Config()
    / Z: S5 {# o& B2 l# n& G
  54. 54{
    7 p- {+ m8 n  A( f& t
  55. 55    GPIO_InitTypeDef  GPIO_InitStruct;" ~. ?- m( Y) p' G+ S
  56. 56    /*----------通道1配置--------------*/! I% s( D; [7 L5 n6 i  B
  57. 57    /*定时器1输出比较通道*/
    + r( ]5 z0 s) \( w' D' [  x4 x& Y( l5 G
  58. 58    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    # N0 R$ K0 Q9 m+ j
  59. 59    /*配置为复用推挽输出*/$ F# U" j& X4 m5 e, k7 O5 `2 C
  60. 60    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;! L0 q3 U% F9 P6 a4 x5 q8 K
  61. 61    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
    : |$ s! D  Q% ^2 q/ k8 h* K' l7 q
  62. 62    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;, M  h( Y# x% j: U% X9 P; |; O
  63. 63    GPIO_Init(GPIOA,&GPIO_InitStruct);
    - Z6 t! g" g& x* ]6 ~; P
  64. 64    /*-----------通道二配置-------------*/, E2 W' `  H1 @: f, }& o
  65. 65    /*定时器1输出比较通道*/1 z; {  n/ h' |* i0 u4 {
  66. 66    /*配置为复用推挽输出*/! G2 N3 y7 E! O7 O0 B6 X5 M1 e
  67. 67    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;: W$ w/ U1 P6 B
  68. 68    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;% [: a( K6 ^2 Q2 g. Q7 x8 g
  69. 69    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;; R! U7 Y0 D  i* U" N4 D
  70. 70    GPIO_Init(GPIOA,&GPIO_InitStruct);5 X% n% V+ y( D6 h' i4 R, e) P
  71. 71     /*-----------通道三配置-------------*/
    2 ~  q- |4 j. X8 n: }7 w* Z! x
  72. 72    /*定时器1输出比较通道*/
    5 n3 F; Y) [2 p) z+ T( g
  73. 73    /*配置为复用推挽输出*/( o+ G' l% c/ q' |0 W4 M$ J; C
  74. 74    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;" g6 j  \% G9 O. s6 y
  75. 75    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
    - Z! q8 c; R5 g
  76. 76    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    3 Z! c+ \8 O8 B, V6 l
  77. 77    GPIO_Init(GPIOA,&GPIO_InitStruct);" f( p6 C2 h% x+ \( m8 h
  78. 78     /*-----------通道四配置-------------*/
    $ X+ t$ p: `/ \! y) f! F- M2 i
  79. 79    /*定时器1输出比较通道*/# ?0 t- X; }' E
  80. 80    /*配置为复用推挽输出*/
    - I6 p1 i, w# ]
  81. 81    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    * X+ |, }0 P& q
  82. 82    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
    8 r3 t4 q$ ^0 f1 m8 _3 y
  83. 83    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    3 d  ]' @. A' n1 \
  84. 84    GPIO_Init(GPIOA,&GPIO_InitStruct);1 I: x) C, ?( J' P; N
  85. 85}</font>
复制代码

. z* B% w+ B6 c% a

2 Y  V) x0 t. M! y: R
( V5 F* Q$ c9 m, E# P
超声波模块2 n3 Q6 T: S- s
) F$ a0 b/ q1 V, v
: l! G- l  `  a$ g; y5 _8 M. l; }) A% N
采用HC-SR04超声波模块,该芯片具有较高的集成度以及良好的稳定性,测度距离十分精确,十分稳定。供电电压为DC5V供电电流小于10mA,探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)。HC-SR04实物图如下:$ |9 z3 v: S6 u9 K; Y
5.png
8 C' J( M: d! U4 x9 T该模块是利用单片机的IO触发电平测距,单片机内部利用普通定时器产生一个高电平信号之后,超声波就可以自主发送频率为40khz的方波,然后等待信号的返回;若有信号返回,单片机IO口就立刻输出一高电平,利用高电平产生的时间可以计算小车与障碍物的距离。最终距离就是高电平持续时间乘以声音在空气中传播的速度再除以2,可以反复测量距离。
+ u& y; {. e# C  s) M# y' {; \  在程序开始首先初始化超声波,利用定时器并设置时基的自动重装载初值1000,psc为预分频值72,这样的话我们产生一次中断的时间是1ms,并设置抢占优先级0,子优先级3。HC_SR04_Echo引脚接收到高电平,打开定时器,且每1ms进入一次中断。在测量时首先让Trig发送一个大于10us的高电平,然后拉高HC_SR04_Trig,当Echo为0时打开定时器计时,当Echo为1时关闭定时器,通过公式计算距离。
3 q4 e( z4 S/ S# g6 X模块工作原理:
5 Q& O: v- ]/ e5 Q(1)单片机触发引脚,输出高电平信号;, y9 u! G& y  K% w" |
(2)模块发送端自动发送特定频率的方波;
5 a- [% b9 |, }$ T! c, n(3)如果有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波的发射时长;2 B1 c$ l, {9 |  d
(4)测试距离=(高电平时间*声速(340M/S))/2。

  R1 ^9 r# h# h! T$ V注意:在硬件操作上需要首先让模块地端先连接,否则会影响模块工作。测距时,被测物体的摆放不能太过于杂乱,否则会影响测试结果。2 x9 c* F+ M2 x9 Q1 Y
6.png
2 N" U/ D7 C* Z8 F4 ^2 w. _超声波重要代码(可参考)
% ]3 ?9 o4 v8 V
  1. 1/* 获取接收到的高电平的时间(us*/
    0 R6 D% I: D8 t0 C
  2. 2uint32_t Get_HC_SR04_Time(void)
    ! H3 r) f9 T, l* Z5 N7 n+ F  `! S
  3. 3{
    ( [; ~, O  `) [) |/ W
  4. 4    uint32_t t=0;
    9 p' ~, D% i2 w, N1 T. |- ]% }
  5. 5    t=Acoustic_Distance_Count*1000;//us  }8 X" M3 \( k" S
  6. 6    t+=TIM_GetCounter(TIM2);//获取us
    ) J/ x1 C2 G9 |. P- e3 \' C
  7. 7    TIM2->CNT =0;
    2 E5 R: Q1 Z# E* ]- b
  8. 8    Acoustic_Distance_Count=0;6 f0 U6 {) u) I* g+ {7 l. J# o) @
  9. 9    Systic_Delay_us(100);% ~- H+ B1 q: d( I4 y- I1 a
  10. 10    return t;
    0 t6 a- k2 r6 B7 H9 x
  11. 11}5 d1 H' }6 d1 J0 C0 f
  12. 12/*获取距离*/
    / `" ^* N9 X8 C+ ^* D  n
  13. 13void Get_HC_SR04_Distance(void)
    ( G. [" l, ~3 H
  14. 14{
    9 M& F: I, |! S( k
  15. 15    static uint16_t count=0;
    + m1 _! V* J1 @$ p  D% l1 O; O9 m
  16. 16    switch(count)& Z) A# N1 e$ ]$ n0 ~0 G
  17. 17    {
    8 h2 F9 ?! m& j9 p/ V" j+ ?
  18. 18        case 1:
    + X- @! ~/ ]. n! W& {
  19. 19        {
    6 S; S5 W/ p# H; X4 @% d$ Y
  20. 20            GPIO_SetBits(Acoustic_Port,HC_SR04_Trig);//Trig发送一个大于10us的高电平
    ; S) j' K  E! h6 G  m' N
  21. 21        }break;
      n( j2 P% l, E; K
  22. 22  y" Y9 j( H4 X+ x) G- y" N6 Z2 F
  23. 23        case 15:3 t" a, r; l* Y- f/ P( d
  24. 24        {
    ( x. }' j2 ^2 {; m
  25. 25            count=0;9 H. ^/ t4 N) ~9 ^
  26. 26            GPIO_ResetBits(Acoustic_Port,HC_SR04_Trig);
    $ w+ K: P/ f: g5 n
  27. 27            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==0);//当Echo为0时打开定时器 计时+ T, O' ?7 r* ?' o, p
  28. 28            Open_Tim2();. N" v) m3 K3 [* b, b# e
  29. 29            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==1);//当Echo为0时打开定时器 计时+ X- l3 e9 m# i  ~0 p0 J
  30. 30            Close_Tim2();1 U2 U6 S! y7 A- G, F
  31. 31            HC_SR04_Distance=(float)(Get_HC_SR04_Time()/5.78);
    ) Q9 K7 Q& Y( c4 Y9 T1 R' R8 L
  32. 32" K# |' B6 M: I1 x8 Y
  33. 33        }break;8 y% Q, N2 t( a4 w* ~% x
  34. 34        default:break;  `) t3 x3 S6 K4 g2 a5 t/ m
  35. 35    }
    - J. s0 }. `! p4 g
  36. 36    count++;
    1 |7 ~. o" z* e( v
  37. 37}
复制代码
1 X0 p& H- B" U( E" B( R3 w

! u3 u: F2 d) R6 K0 v$ I4 t- n' T$ h9 U" x+ C0 z; `2 W! a+ q

3 P- s/ Y& L! R9 B
( R4 i( y5 b: E  y" ~6 B, Y+ [
舵机模块
' O2 n& V  ?" z$ }9 R( `
   

- d* q9 |1 K" B! \+ l本系统使用的是SG90型号的舵机,舵机是一种常见的角度驱动器,本系统需要判断不同位置的障碍物可以且对转向的力度小。舵机可以理解为方向盘称,方向盘是一个常见的名字。它实际上是一个伺服马达。舵机实物图如下:
8 ^- ?3 |' s  |2 L 7.png ' I/ g! `1 B4 c8 L- W, ]
舵机模块接口简单,舵机模块只有三个引脚。分别引引出了三根线左右两边是电源正负接口线,中间一根是PWM信号线直接连接单片机的控制引脚。通过控制单片机的引脚输出的脉冲宽度进而控制舵机旋转的角度。舵机每增加0.1ms 舵机对应增加9度。
( A4 l; S9 u0 J5 w; P0.5ms---------0
5 A& Y! ]' M1 n6 `1.0ms---------45  # i$ u) {, H( W3 S
1.5ms---------90
& g( ~. Z. j7 I/ I' t% |6 V2.0ms---------135- [8 L" b+ h% p* ?) F. y& ?- O
2.5ms-----------180
& W6 u9 z+ J6 H) ~2 X! S   20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平持续时间为1.5ms,周期为20ms的方波,duty=1.5/20=7.5%。在这里设置定时器自动重装载寄存器arr的值为1000,所以当占空比为百分之75是,在程序中就要设置占空比为75/1000=7.5%, 这就是具体的算法。3 V2 y7 X& X" p# e* [/ _
舵机重要代码(可参考)( y+ ^/ S, P, `: Y& j/ b- c8 R" U
  1. 1/**PWM引脚初始化*/
    - \0 K$ Y6 \1 I3 D& B
  2. 2static void SERVO_Gpio_Init(void)
    ! ?" H* K. ^7 Z4 H; v4 J
  3. 3{
    . W5 p! m9 w) E1 }6 |
  4. 4    GPIO_InitTypeDef  GPIO_InitStruct;
    8 C3 G3 Z6 {, q9 h4 _; t! H" C$ F; e
  5. 5    /*----------通道2配置--------------*/
    . T: E' m# `7 F- Q
  6. 6    /*定时器3输出比较通道*/- W! K6 t1 N/ ~  C7 v
  7. 7    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    # E9 \. b$ r; e' A6 B
  8. 8    /*配置为复用推挽输出*/
    # l) v1 V0 v" }* v6 p6 s
  9. 9    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    ( L6 L, ?9 s  ]2 h# S; h$ z
  10. 10    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
    + d" j" H! O8 M5 N% \8 e$ g
  11. 11    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    . _# i% [  Y" c
  12. 12    GPIO_Init(GPIOA,&GPIO_InitStruct);   A* {  c) X. c3 U/ _& e
  13. 13}! I9 H0 c2 ?" z- F& l4 r
  14. 14//定时器3初始化,设置TIMx的ARR,PSC) H( p1 X! C3 _# k+ ^3 X8 ~
  15. 15//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期
    . u$ b: Q% f) S1 O* p' C; V
  16. 16static void SERVO_TIM_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)
    % F8 Y+ F1 t; j" t  b, f
  17. 17{  L, N: f7 Y/ ^$ J. Y4 p, m. ]
  18. 18    //-----------------时基结构体初始化-------------------------/
    : N. n, _, A0 m: f1 B
  19. 19    TIM_TimeBaseInitTypeDef TIM_TimeStructure;
    % s. E" x8 i7 J5 U) C9 r+ p) h. l9 Q% d
  20. 20    /*开启定时器3时钟,即内部时钟CK_INT=72M*/3 E% F, t8 J( u4 c
  21. 21    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    & C, ^' i! b2 s3 M1 `1 z
  22. 22    TIM_DeInit(TIMx);- R+ X7 r( @3 [6 w3 Q' s3 H
  23. 23    /*内部时钟作为计数器时钟,72MHZ*/& M: R% H; Q* d+ _, d; X
  24. 24    TIM_InternalClockConfig(TIMx);
    ; T8 W; s6 }: I9 Z2 j, Q
  25. 25    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/6 }! x7 d; ^/ V' \% S; ^
  26. 26    TIM_TimeStructure.TIM_Period=arr;//1000 当定时器从0计数到999,即1000次,为一个定时周期( R* Z: L( t6 t% ]* Q; M% M
  27. 27    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(1440-1+1)=0.05MHZ*/6 `# x+ T. ]) I1 Q! x3 n# B0 p) u
  28. 28    TIM_TimeStructure.TIM_Prescaler=psc-1;;//1400  //即定时器的频率为5KHZ   
    4 F) u" w3 X1 i9 y7 n" l; E2 p
  29. 29    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
    9 K9 c* s2 v9 b6 Z
  30. 30    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;$ s  ]- t* t! s& K9 l7 I0 s8 h6 L
  31. 31    /*向上计数模式*/
    * e8 k& ]0 p% c* \  n- l- e
  32. 32    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
    7 }3 o( W$ s. x- M6 N% K- j# |
  33. 33    /*重复计数器*/$ @# j$ j1 _$ Y; y- e1 E
  34. 34    TIM_TimeStructure.TIM_RepetitionCounter=0;
    ; b" [' r2 S% X! k5 Q& l$ y$ f
  35. 35        /*初始化定时器*/! ^  u( E, M0 v
  36. 36    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
    & A7 }, W: X- G
  37. 37    /*使能ARR预装载寄存器(影子寄存器)*/: C) m. c" s3 p- n9 d
  38. 38    TIM_ARRPreloadConfig(TIMx,ENABLE);
    & l( S+ }8 O$ ?0 G9 r& F2 G) r2 p
  39. 39    //-----------------输出比较结构体初始化 开始-----------------------/; K6 [+ s/ l5 s* u
  40. 40    TIM_OCInitTypeDef   TIM_OCInitStructure;) y4 p. T$ j  S1 r
  41. 41    /*PWM模式设置,设置为PWM模式1*/
    ' {$ A+ X, K& O6 s' r% m  X
  42. 42    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    6 }, N% E3 a+ U( T. F
  43. 43    /*PWM输出使能相应的IO口输出信号*/. z1 H' G& I# ^- |8 U
  44. 44    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;6 m4 u0 m3 P: e. f: v8 M
  45. 45    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
    + \9 E! `  \, u( m' W7 g8 [3 X
  46. 46    TIM_OCInitStructure.TIM_Pulse=duty;   //占空比大小
    , v; J  c$ M# T$ d9 @
  47. 47    /*输出通道电平极性设置*/
    ! k* ~4 B4 T+ h# F6 l5 A
  48. 48    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;" q+ Q: B2 E( J$ Q- x! I& B, b
  49. 49    /*初始化输出比较参数*/) y5 W5 P1 H" d$ E0 I
  50. 50    TIM_OC2Init(TIMx,&TIM_OCInitStructure);
    2 c. Q1 z0 Z2 k  r. P1 w. E
  51. 51    //-----------------输出比较结构体初始化 结束-----------------------/   
    ( f& ]4 e- c* F3 `% l
  52. 52    /*自动重装载*/8 ^& y! }7 U1 E8 ?% g
  53. 53    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);7 h( k5 U5 A- _2 }: a
  54. 54    /*使能计数器*/# e$ h4 W: U- l, g- b
  55. 55    TIM_Cmd(TIMx,ENABLE);
    . x* z- H- L* W, [8 r& l
  56. 56    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
    8 p4 ?0 b2 t' n; A$ J3 `
  57. 57    TIM_CtrlPWMOutputs(TIMx,ENABLE);   
    9 S- w7 Z% b. \
  58. 58}
    3 V# Y9 a( G4 e  t, @: y/ \- Q
  59. 59/*舵机PWM初始化
    $ l% C7 X" J- F  a7 X
  60. 60   每增加0.1ms 舵机对应增加9度
    4 X. J: v) j& S: H4 a( m4 _. g( w
  61. 610.5ms---------0, M1 N/ H9 C* s
  62. 621.0ms---------45   
    4 ]; c  s! P3 ~1 G. r- C
  63. 631.5ms---------90
    " D# B% D# D, T* T; N% S
  64. 642.0ms---------135- Z4 J5 ?/ y) K, b/ Q/ ~. \3 l1 B
  65. 652.5ms-----------180
    8 p) S/ r+ [; c5 ?( G
  66. 662.1ms    turn_left=150
    6 z6 B* K) I7 z
  67. 670.8ms    turn_right=25
    6 t, n& c. K0 b0 E* n" b1 U
  68. 681.3ms    turn_front=75
    9 ]8 P7 e1 W! G. q6 S, I+ y
  69. 6920ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平为1.5ms,周期为20ms的方波,duty=1.5/20=7.5% ,而定时器自动重装载寄存器arr的值为 1000 ,所以duty=75,时占空比为75/1000=7.5%. # S) q( ~* e& i* P- L, Q
  70. 70*/
    9 l, E  X. t# o+ i) F* K
  71. 71void SERVO_Init(void)8 E7 q3 R9 E3 }/ M3 ]3 T) ^0 P+ o
  72. 72{7 [( `' T- K) l2 Z. W/ h+ q
  73. 73    SERVO_Gpio_Init();
    - q/ _9 n9 t! `0 G2 z, C' J
  74. 74    SERVO_TIM_Config(TIM3,1000,1440,turn_front);, ^' n4 n" l+ m9 N4 L5 N
  75. 75/** 我们把定时器设置自动重装载寄存器 arr 的值为 1000,设置时钟预分频器为 1440,则5 d0 D& Z! N/ Y; j4 h$ A# h2 r
  76. 76驱动计数器的时钟:CK_CNT = CK_INT / (1440-1+1)=0.05M,则计数器计数一次的时间等于:$ U/ ~9 ~$ D7 u
  77. 771/CK_CNT=20us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间
    # |- j& A/ \$ R5 u) Q) C
  78. 78为:1/CK_CNT*ARR=20ms。
    ) G3 U' l9 E! h8 F! q  X3 x4 C
  79. 79PWM 信号的频率 f = TIM_CLK/{(ARR+1)*(PSC+1)}  TIM_CLK=72MHZ
    6 m/ X0 N5 n0 n: P1 p8 V& j& g  @. [7 `
  80. 80               = 72 000 000/(1000*1440)=5KHZ    7 j& a' e1 K" j6 i% E
  81. 81*/    0 }0 z7 B- E6 N" q+ y9 t
  82. 82}
    ( N6 p6 `  [* i$ @
  83. 83/*舵机角度控制*/
    4 {2 R% _+ t5 p% V$ M' u
  84. 84void SERVO_Angle_Control(uint16_t Compare2)% A  J% E2 F$ b+ _" B) u1 p* w
  85. 85{
    * T! H* T" G: }. y. @
  86. 86    TIM_SetCompare2(TIM3,Compare2);$ M  Z- K; H1 c8 H& s  i' E7 R
  87. 87}
复制代码

; a3 H0 w" _+ {

' ?5 x, H* x; o+ W& o# t  [7 c
编码器模块
3 C7 d6 x# R9 X& T
' V0 G- x& c" N- o
调节小车前进的速度和避障快慢我们采用EC11旋转式编码器,可以用于光度、湿度、音量调节等参数的调节。EC11编码器的形状类似于电位器,中心有一个旋钮可以调节PWM信号,光电码盘利用光电转换原理输出三组方波脉冲。EC11编码器的实物图如下:
# \  v# R7 k: G5 c% d 8.png
+ X8 w9 q& B' R( J# h- D! j3 J& T3 b
( Z3 a# `: M# z, |& t+ Q* H+ a
OLED显示模块
: ~/ j; A+ _7 j( E: U; J9 X
; w$ V7 |( m# `, X5 W% ^
用来显示小车转速,以及左右编码器数值和电池电压等参数所用的是OLED显示模块,分辨率较高,而且功耗低,正常显示时仅0.06W,供电电压范围在3.3V-5V,有IIC和SPI两种通信协议可供选择。显示模块的亮度和对比度可以通过程序设置。由于它使用寿命长以及其他的优点,OLED更加适合小系统,本系统由于单片机引脚有限,不适合利用简单的LCD1602或者12864来显示,在多方对比之下OLED效果更好。OLED显示部分相对比较简单,大家参考中景园的例程就可以实现。. F2 E1 y+ S* E

6 \! V- {1 X8 Q5 ^. J9 M- p- F
4 w# m  `/ A* S. r( z

, _& w! ]6 h& P/ I0 b
- g" H' h; i, D6 z  N
文章出处:程序员小哈
1 X2 n7 C6 y8 ^! v) Z  O
赞 收藏 4 评论1 发布时间:2020-10-9 10:44

举报

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