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

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

[复制链接]
STMCU-管管 发布时间:2020-10-9 10:44
【项目分享】基于STM32超声波避障小车
( q2 J$ K6 t! M8 F  X' B
3 L. c" O. v/ {* ~9 C
$ n& d$ R* A7 {( L+ k% F* I不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车。这也是我曾经的一个课设,在此开源分享给大家,全文5000多字,干货满满,加油读完,保证你收货多多
4 o2 ^. L* c$ p) R
) C  v7 N* d7 P
7 I1 o2 w$ [2 W3 P- j1 I

) ]/ @% v* U) ^5 [. M# V$ c" e处理器电路设计9 j2 g. T0 r$ g# J: e# k' D! k+ q: X
单片机是系统的CPU,是系统稳定、正常运行的重要前提,以下为单片机选型的两种方案:
+ N2 @" B+ i; ]9 r0 i(1)传统的8位单片机,是通过超大规模集成电路对其进行集成为一个独立芯片的控制器。内部组件包括CPU、随机存储器、只读存储器、I/O接口、中断系统、计时器、串口通讯、数模转换等。STC89C52单片机是最常见的51单片机,但是资源较少,精确度低,处理速度相比STM32单片机差很多。
8 r7 u% l" _0 a2 o2 C  C8 w(2)使用目前市面上最常见的STM32单片机,STM32系列单片机可分为ARMCortex-M3内核体系结构的不同应用领域。它可分为STM32F1系列和STM32F4系列,STM32F1系列单片机时钟频率最高可达72米,在同一产品中性能最好。单片机的基本处理速度为36米,16位单片机的性能也很好。微晶片的内建快闪记忆体相当大,范围从32kb到512kb,可视需要选择。单个设备的功耗非常低,仅360mA,32位单片机产品的功耗最低,每兆赫只有0.5安培。特别值得一提的是,内接单晶片汇流排是一种Harvard架构,可执行速度高达1.25 DMIPS/MHz的指令。此芯片越来越多地被用作主要控制器。
! p2 j- p4 Y4 L# U% |   通过对单片机的资源和处理时间的速度我们采用选择STM32103C8T6为本系统主控芯片,程序下载是只需要一个JLINK就可以轻松完成。控制器模块电路如下所示:
; q. f+ I$ S) \" ~ 2.png
/ q. V3 q- a) a: L. q& m! X1 ]' q电源模块设计% M1 f2 Z- ?, m  \' l$ V; y
本设计采用锂电池供电, 模块的供电电压一般都为5V,同时超声波模块需要较大的电流才能正常工作,所以在降压的基础上也要保证足够大的输出电流。本设计采用可调输出版本,模块的输入电压范围广,输出电压在1.25V-35V内可调,电压转换效率高,输出纹波小。降压电路如下所示:
9 U( }+ e* }5 R  B 3.png # t6 s- F; i# J4 M
电机驱动模块设计
/ ?! a, M( Y. K9 `5 ?7 m要完成转向是能够利用单片机实现的,然而单片机I0的带负载能力弱,因此我们选择了大功率放大器件TB6612FNG。TB6612FNG是采用MOSFET-H桥结构的双通道大电流电路输出,可以控制2个电机的驱动。相比普通的电机驱动,外围电路非常简单,只需要一个芯片和一个钽电容进行PWM输出滤波,系统尺寸小。PWM信号输入频率范围广,轻松满足本设计的需求。   
9 ~  e: A' h4 g$ r  i0 g$ l 4.png
' B9 f* G- I/ b+ j2 O' x$ Z电机驱动引脚表+ a- d9 l3 {# Q) w! X; k4 B0 _
  1. 1控制芯片:TB66129 v# ^" e4 d# T: l
  2. 2控制芯片数量:2) M  R* t* ?- s( m" Z
  3. 3    1号TB6612引脚分配:6 d. Y; r) e& Z! ]6 W- ^
  4. 4     VM         PWMA--------->TIM1_CH1(PA8)/ }- u$ b3 M8 a, x0 z
  5. 5     VCC        AIN2--------->GPIOB_12
    / A" a* _- c7 ?7 T0 X$ X
  6. 6     GND        AIN1--------->GPIOB_13' o" A! |2 W  a5 T  I( W
  7. 7     AO1        STBY--------->GPIOB_14% c: _+ Z0 {! Y1 j
  8. 8     AO2        BIN1--------->GPIOB_15. b' g8 I! X- {+ F
  9. 9     BO2        BIN2--------->GPIOA_127 v, R$ K0 d; H8 l, M# a3 l
  10. 10     BO1        PWMB--------->TIM1_CH2(PA9)
    : X5 x5 l$ F# l/ `) \9 w0 t
  11. 11     GND        GND; j' n5 B4 z. }' m. P- \/ [0 E* V! f
  12. 12    2号TB6612引脚分配:
    1 O: Q. I4 [$ U3 t1 x
  13. 13     VM         PWMA--------->TIM1_CH3(PA10)
    0 \9 w8 L; S; k5 V  z: H+ x
  14. 14     VCC        AIN2--------->GPIOB_5
      V2 Q& z" {  q
  15. 15     GND        AIN1--------->GPIOB_6' F" c' k; N9 G9 E4 E: o- @) d
  16. 16     AO1        STBY--------->GPIOB_75 J( G: s1 @( k; l% c
  17. 17     AO2        BIN1--------->GPIOB_8: S- x7 \" U: s2 V0 o# Q2 d* V7 M
  18. 18     BO2        BIN2--------->GPIOA_97 u" @  Z+ o9 y2 |
  19. 19     BO1        PWMB--------->TIM1_CH4(PA11)
      g2 v* S$ c( e1 O& s# _
  20. 20     GND        GND
    : L: G: J9 V, r% S
  21. 21真值表% F+ L8 ?$ D3 D7 Y$ m$ x
  22. 22     AIN1   0     1     0     13 U. _; w* f5 @, y
  23. 23     AIN2   0     0     1     1
    & _$ L- p* I' X% V' l4 Y, Y
  24. 24     BIN1   0     1     0     1: J" J2 _  j+ Y& u& z* g
  25. 25     BIN2   0     0     1     1
    ' U" F" C  `. w: T
  26. 26           停止  正转  反转  刹车
复制代码
0 \0 S0 x" }. R6 }! H4 N- V

! e6 c  M- E- }* e1 E电机所用到的定时器配置0 W& x8 z& ]; h) ~! z3 j
  1. <font size="3">1//初始化TIMX,设置TIMx的ARR,PSC
    + h8 d+ ^: l* E
  2. 2//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期8 r. d7 g# J$ f# B/ ?! w9 a
  3. 3//定时器选择TIM1
    7 Q% M& H1 A9 {* a
  4. 4static void TB6612_ADVANCE_TIM1_Mode_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)- B9 Q' n2 i9 Q+ O
  5. 5{* B/ J; b) ^, }3 E, X- u
  6. 6    //-----------------时基结构体初始化-------------------------/
    ( d  T$ D4 J& @3 Q; h5 y- e
  7. 7    TIM_TimeBaseInitTypeDef TIM_TimeStructure;0 p; _! Z0 z3 w' @& T& D# p
  8. 8    /*开启定时器1时钟,即内部时钟CK_INT=72M*/
      V. X$ \5 K4 F+ n2 n' _/ E* u# c
  9. 9    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
    : E0 n/ J1 E  }1 R9 @3 c# ^
  10. 10    TIM_DeInit(TIMx);' A" T0 a  p% r! _6 q8 M
  11. 11    /*内部时钟作为计数器时钟,72MHZ*/+ D# ?1 _# P  f
  12. 12    TIM_InternalClockConfig(TIMx);
    # j  b8 c# w* L- Q) n+ r
  13. 13    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/- \- k2 q% G7 f* f1 G; k; U
  14. 14    TIM_TimeStructure.TIM_Period=arr;1 v, \; F* z2 H3 ~. T
  15. 15    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(71+1)=1MHZ*/
    " {$ F" {7 E1 D
  16. 16    TIM_TimeStructure.TIM_Prescaler=psc-1;. P  L. c  W! _( c/ A" P7 C
  17. 17    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/: i9 W9 c9 j# _& z( Q8 G4 e
  18. 18    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;8 t% {" ]/ M% k6 |7 V" f
  19. 19    /*向上计数模式*/# B+ _: q" z7 H/ O! x! U
  20. 20    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
    1 A7 ^2 ~, G! R  k/ W$ ?9 P
  21. 21    /*重复计数器*/; c, U: S: R/ I! m- n
  22. 22    TIM_TimeStructure.TIM_RepetitionCounter=0;
    + J2 U$ a* y0 J' X
  23. 23    /*初始化定时器*/
    ' r; |$ r9 c8 Z5 p9 Z
  24. 24    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);3 x5 S' P; n/ Z; ?0 k! s7 Y
  25. 25    /*使能ARR预装载寄存器(影子寄存器)*/
    ! ^7 o  G7 r$ k  {% @
  26. 26    TIM_ARRPreloadConfig(TIMx,ENABLE);2 M" F/ a( J/ z2 n! Z* ~4 s
  27. 27    //-----------------输出比较结构体初始化-----------------------/
    - N4 I3 ?* o- F' f$ W) C: x1 r
  28. 28    TIM_OCInitTypeDef   TIM_OCInitStructure;
    6 z3 @* J& X5 B" O
  29. 29    /*PWM模式设置,设置为PWM模式1*/
    7 k* k2 _5 b$ s6 W, W% z7 t, d- f1 {
  30. 30    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;3 O5 _3 u+ g+ o7 \2 k4 O
  31. 31    /*PWM输出使能相应的IO口输出信号*/
    * J: a8 f  }3 |% W2 H- l  O, ?2 B
  32. 32    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;/ ^, Y* O' e$ s, o3 H
  33. 33    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/' y" f/ e* _! w: x
  34. 34    TIM_OCInitStructure.TIM_Pulse=duty;7 r! \  b) v6 X/ O. ]; j! a) z8 q. m
  35. 35    /*输出通道电平极性设置*/8 _& ?* [' @% n, n- O) h1 i( Y
  36. 36    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;2 z  N/ R6 Q8 D. g
  37. 37    /*初始化输出比较参数*/0 d) L, j! B# z% `
  38. 38    TIM_OC1Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道1+ v& q, I, o/ Z
  39. 39    TIM_OC2Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道2
    1 \( B. t! }" [& Q
  40. 40    TIM_OC3Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道3' q" s; e; m4 C% w- \( R9 G" J
  41. 41    TIM_OC4Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道4; w& k8 J1 T% P
  42. 42    /*自动重装载*/7 k: {9 \5 c2 L9 z
  43. 43    TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable);0 [/ @; o7 ~) T% F  }$ x
  44. 44    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
    % |# ]% ]  x/ X
  45. 45    TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable);0 ^( @0 k. j* k  Q' a( M+ i
  46. 46    TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable);2 I9 O2 m: ~8 n# E$ ^7 {$ C& N
  47. 47    /*使能计数器*/
    3 s$ c3 E8 r/ ^0 ^
  48. 48    TIM_Cmd(TIMx,ENABLE);( h) i! q& i/ C- }/ P
  49. 49    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/% f/ E  b/ F3 Q! S1 F/ o
  50. 50    TIM_CtrlPWMOutputs(TIMx,ENABLE);    / I6 o8 v) R  E
  51. 51}
    9 \2 z4 r/ Y  L/ I+ D
  52. 52//高级定时器输出通道初始化函数# _  X& Z& g, s( E
  53. 53static void TB6612_ADVANCE_TIM_Gpio_Config()
    6 Q( x8 e, v& i5 B
  54. 54{
    8 m% C7 Z7 L/ k$ C2 Q8 I
  55. 55    GPIO_InitTypeDef  GPIO_InitStruct;
    % K4 x/ I9 D, V! Z+ A
  56. 56    /*----------通道1配置--------------*/
    * ?8 }  W0 J# ~9 J" T
  57. 57    /*定时器1输出比较通道*/$ z* Z, p! w7 n; g6 y- }
  58. 58    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);' I0 u+ I/ m4 I
  59. 59    /*配置为复用推挽输出*/
    - E" D& e5 d: f* Y: a
  60. 60    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    1 m3 Z7 T, a% r* Z
  61. 61    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
    ( }7 h8 p1 m9 x5 o8 N. @
  62. 62    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;4 ]0 h  s' V7 w+ |! l2 |
  63. 63    GPIO_Init(GPIOA,&GPIO_InitStruct);
    * R! c2 g3 h# B% O
  64. 64    /*-----------通道二配置-------------*/$ ^2 H& [* ?- m$ e3 Q
  65. 65    /*定时器1输出比较通道*/- Y& J& m/ K% ~2 B& y
  66. 66    /*配置为复用推挽输出*/. l% E' f- K( h
  67. 67    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    ( p( n7 z1 j9 \, j4 X
  68. 68    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;$ ]- O5 a4 N9 y" C, q
  69. 69    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    % k) \, |5 v$ S; M3 |. U% T' g5 O
  70. 70    GPIO_Init(GPIOA,&GPIO_InitStruct);+ ], u- T: N6 z- E4 t  k
  71. 71     /*-----------通道三配置-------------*/: Z' h/ Y7 L, ~$ }
  72. 72    /*定时器1输出比较通道*/
    9 j8 B  k  }/ K2 \2 W
  73. 73    /*配置为复用推挽输出*/! T" n# t. m5 Q7 C4 d
  74. 74    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;5 u; E! m. {! B
  75. 75    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
    * [$ B! ~; u6 g' _
  76. 76    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    / o) M  q& ^* a
  77. 77    GPIO_Init(GPIOA,&GPIO_InitStruct);
    : ]% U, w& O6 a& e+ {# Z  ~, P- j1 B
  78. 78     /*-----------通道四配置-------------*/
    . I4 s0 W5 d$ r/ {. z# K
  79. 79    /*定时器1输出比较通道*/6 U# R& v8 E* @/ I0 [1 p
  80. 80    /*配置为复用推挽输出*/
    ! _* N5 x* y' m4 I- V
  81. 81    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;$ l8 N" Q6 \. v" H
  82. 82    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;! ]2 u4 R* A4 I$ ], W5 ?+ i' S
  83. 83    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;( m1 z; [. U1 ~& e! F
  84. 84    GPIO_Init(GPIOA,&GPIO_InitStruct);
    6 a* l& R' C4 d
  85. 85}</font>
复制代码
2 Y+ K) C8 l  M  m" N8 Z  f; N5 E
5 r& ^! E' ~* P

8 d4 {* K# o/ h/ b; _+ u
超声波模块5 V5 K6 Y$ d- I; u, N
/ `  c: k# m: J3 X9 s! u0 ^! {5 Q

, e& }/ b6 A: Z, Z- H9 K; j
采用HC-SR04超声波模块,该芯片具有较高的集成度以及良好的稳定性,测度距离十分精确,十分稳定。供电电压为DC5V供电电流小于10mA,探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)。HC-SR04实物图如下:
2 ~! n/ A# C( g 5.png 7 C  }' U5 ]- H6 F: X  X
该模块是利用单片机的IO触发电平测距,单片机内部利用普通定时器产生一个高电平信号之后,超声波就可以自主发送频率为40khz的方波,然后等待信号的返回;若有信号返回,单片机IO口就立刻输出一高电平,利用高电平产生的时间可以计算小车与障碍物的距离。最终距离就是高电平持续时间乘以声音在空气中传播的速度再除以2,可以反复测量距离。
7 \/ Q$ Q0 o2 _  在程序开始首先初始化超声波,利用定时器并设置时基的自动重装载初值1000,psc为预分频值72,这样的话我们产生一次中断的时间是1ms,并设置抢占优先级0,子优先级3。HC_SR04_Echo引脚接收到高电平,打开定时器,且每1ms进入一次中断。在测量时首先让Trig发送一个大于10us的高电平,然后拉高HC_SR04_Trig,当Echo为0时打开定时器计时,当Echo为1时关闭定时器,通过公式计算距离。
/ ]' j3 w# n1 i  Y模块工作原理:3 m# B6 t' O9 u% }3 Y
(1)单片机触发引脚,输出高电平信号;! t; z9 C: C: E( F, [6 _' A
(2)模块发送端自动发送特定频率的方波;  B! A' ~; Z8 v- }* [
(3)如果有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波的发射时长;5 R4 f, W, V$ u% ^6 h! B
(4)测试距离=(高电平时间*声速(340M/S))/2。
' o; a6 j( C$ F8 i
注意:在硬件操作上需要首先让模块地端先连接,否则会影响模块工作。测距时,被测物体的摆放不能太过于杂乱,否则会影响测试结果。- V) L5 @; l% F# G7 ?3 m
6.png , W( t5 ^  q! u- I
超声波重要代码(可参考)
6 d. i/ H* I) g0 ~
  1. 1/* 获取接收到的高电平的时间(us*/9 G$ @0 B2 g7 k" T% |! y
  2. 2uint32_t Get_HC_SR04_Time(void)
    4 }% Z8 w- s9 X
  3. 3{  g; M$ q# H& _% }" G6 ^
  4. 4    uint32_t t=0;* @) E: l7 d7 ?( c+ D# s/ Y5 P( O& v
  5. 5    t=Acoustic_Distance_Count*1000;//us
    4 Y' @) s/ _- {5 A1 l( m+ e3 B  N, o
  6. 6    t+=TIM_GetCounter(TIM2);//获取us
    $ f7 ~) O4 X0 \5 x
  7. 7    TIM2->CNT =0;4 X% ~9 n- P1 [, g4 s2 V: L) b" U9 w
  8. 8    Acoustic_Distance_Count=0;3 r. ?9 v+ ^! A% z0 N$ v
  9. 9    Systic_Delay_us(100);" ?' V; ^, u5 l' [' \- J9 x4 Y' B
  10. 10    return t;1 k9 F3 G; K: M) |: b8 t7 L& H
  11. 11}1 B% c1 H* S. D! U" B$ L4 p
  12. 12/*获取距离*/9 a  l% @1 L& @4 ^' X& D& Y
  13. 13void Get_HC_SR04_Distance(void)
    1 q: J( D: f6 H/ o& X# {% o
  14. 14{
    ! I; s% m$ w5 c/ _9 K$ v& W
  15. 15    static uint16_t count=0;
    " l9 ?! @7 u6 c
  16. 16    switch(count)3 U, |- ^. h3 [8 n$ Y
  17. 17    {+ J: \* N8 t. `3 [6 h
  18. 18        case 1:  {+ ?! o6 N0 W0 _. l
  19. 19        {
    - w3 m  N/ D7 d. O" @9 E
  20. 20            GPIO_SetBits(Acoustic_Port,HC_SR04_Trig);//Trig发送一个大于10us的高电平: K: V) z, \$ X, ?2 `8 x' q
  21. 21        }break;' \9 G+ Z% w1 r! ^
  22. 22
    8 S; F7 a  B% ~. d  L7 @9 d
  23. 23        case 15:0 I7 y9 B; d% ~) }. B
  24. 24        {. n( |5 u9 K5 w3 f" T: o2 N
  25. 25            count=0;
    2 @( i4 c5 W. N+ L# x! y
  26. 26            GPIO_ResetBits(Acoustic_Port,HC_SR04_Trig);
    & d2 q& z  j" a$ B3 O
  27. 27            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==0);//当Echo为0时打开定时器 计时- \/ z# ?7 n9 F' I. n5 ~' j+ c% O
  28. 28            Open_Tim2();
    " o6 T% F, i) h* v! F
  29. 29            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==1);//当Echo为0时打开定时器 计时
      S6 |* }. o/ b' L! o! K. L9 C& P
  30. 30            Close_Tim2();
    + P) c& P2 N( f) |- K5 J
  31. 31            HC_SR04_Distance=(float)(Get_HC_SR04_Time()/5.78);
      d+ B7 J( ~4 Z# i
  32. 32
    ' R' ]' [- Z; c; N4 e* C6 m
  33. 33        }break;; {9 C. P+ C! Y2 Q' U; b: b/ ~
  34. 34        default:break;
    * R: a- V$ W$ J: A; r& [) \  x
  35. 35    }
      }% M" q5 s3 u8 h2 a8 S2 [- E9 b
  36. 36    count++;8 K1 E6 q8 U! W* J! Z2 \
  37. 37}
复制代码

7 Y1 C. l  s- E* T1 C% ]/ n6 C8 H# Q7 ?7 ~- Z# E+ z' w! Y1 P

; |. a) k& u0 a
. {0 e  l$ ]' p

) G0 |1 E* A5 ?+ U
舵机模块1 h0 L& o' E/ X( \% c! P- ]1 d
   
. H4 ^5 y' y8 E3 X' D# O
本系统使用的是SG90型号的舵机,舵机是一种常见的角度驱动器,本系统需要判断不同位置的障碍物可以且对转向的力度小。舵机可以理解为方向盘称,方向盘是一个常见的名字。它实际上是一个伺服马达。舵机实物图如下:5 U% ]/ Q; `- S  E3 ]0 I
7.png 0 {3 Y7 b) S6 ?8 T4 F
舵机模块接口简单,舵机模块只有三个引脚。分别引引出了三根线左右两边是电源正负接口线,中间一根是PWM信号线直接连接单片机的控制引脚。通过控制单片机的引脚输出的脉冲宽度进而控制舵机旋转的角度。舵机每增加0.1ms 舵机对应增加9度。3 Z$ T" w( h/ ]8 c8 c- u: w0 _
0.5ms---------0! s6 H8 F6 @/ t' d! J
1.0ms---------45  
& m& g; O- v. z1.5ms---------90
6 y% X5 b4 _3 v. W" Q/ {# A2.0ms---------135" @( r' ^& \2 S5 }4 b
2.5ms-----------180% f& p: {9 M* Q8 J! A
   20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平持续时间为1.5ms,周期为20ms的方波,duty=1.5/20=7.5%。在这里设置定时器自动重装载寄存器arr的值为1000,所以当占空比为百分之75是,在程序中就要设置占空比为75/1000=7.5%, 这就是具体的算法。0 h& U" E% {2 \1 f! ~
舵机重要代码(可参考): d$ k0 x7 ?5 v6 s
  1. 1/**PWM引脚初始化*/
    0 I( \% ~" n5 h% L& Q- _
  2. 2static void SERVO_Gpio_Init(void)! i$ C1 j2 S2 R; }
  3. 3{, E) ]1 I5 L3 k/ i
  4. 4    GPIO_InitTypeDef  GPIO_InitStruct;
    ; s9 Y& |/ c! b. R8 C* C5 ?6 ]
  5. 5    /*----------通道2配置--------------*/& ^- u% _7 ~8 d) F
  6. 6    /*定时器3输出比较通道*/4 j2 R3 ~+ T$ L7 o
  7. 7    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);( d! U0 R) J5 f
  8. 8    /*配置为复用推挽输出*/9 u% O7 P( D' R6 P+ i
  9. 9    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;$ j  ^4 u' x1 x4 S3 Q# w( A
  10. 10    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
    ! O$ y% o8 M; o5 `' l# s
  11. 11    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;. g4 S* }; J- ]0 f! u. ~/ ]
  12. 12    GPIO_Init(GPIOA,&GPIO_InitStruct); . a4 y. g( }7 ]3 i+ k. s
  13. 13}3 t6 x9 j. W" E, P5 }- M
  14. 14//定时器3初始化,设置TIMx的ARR,PSC2 H5 m# Z" H5 i- ?! m& B
  15. 15//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期3 e$ `* O) G( g$ w
  16. 16static void SERVO_TIM_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)
    0 ?- H6 {' ^+ O& c/ b) i6 Q
  17. 17{4 b$ a( s! d% z9 l, L
  18. 18    //-----------------时基结构体初始化-------------------------/
    0 Z5 \3 V2 }  p) F' m
  19. 19    TIM_TimeBaseInitTypeDef TIM_TimeStructure;
    - h5 ^& ^, ~; i& r+ k9 k
  20. 20    /*开启定时器3时钟,即内部时钟CK_INT=72M*/6 V; X# \' ?' g
  21. 21    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);( f/ G$ f5 u8 M% V
  22. 22    TIM_DeInit(TIMx);2 e' c% d9 u1 ^9 j4 w+ Q
  23. 23    /*内部时钟作为计数器时钟,72MHZ*/
    ! l8 @) C. E; [, c
  24. 24    TIM_InternalClockConfig(TIMx);+ A) e$ C5 P+ M
  25. 25    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/8 q0 m& U5 q0 T7 R% [
  26. 26    TIM_TimeStructure.TIM_Period=arr;//1000 当定时器从0计数到999,即1000次,为一个定时周期
    % ~$ s1 o9 X! g7 t! i- d7 e& Y3 ]' F
  27. 27    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(1440-1+1)=0.05MHZ*/
    6 y4 a  I$ e. @: L0 F8 F( {1 O0 O# `1 `
  28. 28    TIM_TimeStructure.TIM_Prescaler=psc-1;;//1400  //即定时器的频率为5KHZ   ' _8 O2 Y+ s. f; Y. H
  29. 29    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/  \7 L; E& q- j! a8 L% J3 ]. F2 l
  30. 30    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    : g# P& u9 r* s8 ]3 o. K
  31. 31    /*向上计数模式*/) z4 ]1 R7 m. j  Y+ d. N# v4 B" h
  32. 32    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;4 U7 A% V* Y( D6 |: N: X5 i0 }7 T+ N
  33. 33    /*重复计数器*/
    % I  j5 Y4 l5 i1 I- i
  34. 34    TIM_TimeStructure.TIM_RepetitionCounter=0;
    * U# }$ C3 T& Y# Z, o* Z9 A9 O
  35. 35        /*初始化定时器*/! ]0 v, ~1 v3 d9 r/ w4 e1 u9 d9 i
  36. 36    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);( }, P! J2 P! X
  37. 37    /*使能ARR预装载寄存器(影子寄存器)*/
    / e" E6 @3 }/ q4 Y$ c$ O5 _0 y
  38. 38    TIM_ARRPreloadConfig(TIMx,ENABLE);
    ( R+ I% t6 z" C) U2 k. Y
  39. 39    //-----------------输出比较结构体初始化 开始-----------------------/& J  f+ q' J0 T
  40. 40    TIM_OCInitTypeDef   TIM_OCInitStructure;
    / G! f: R' }, ]1 t( ^2 i
  41. 41    /*PWM模式设置,设置为PWM模式1*/
    $ n  X" P5 o( N. ~" G. ?4 x
  42. 42    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    ; b( S0 s5 x8 v8 k& [9 K
  43. 43    /*PWM输出使能相应的IO口输出信号*/
    4 Y4 H( J! j& O
  44. 44    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;. d& Q* N$ x5 {& ~7 w* E1 l* V
  45. 45    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
    * J' s" V2 E2 O; c3 D* G
  46. 46    TIM_OCInitStructure.TIM_Pulse=duty;   //占空比大小0 m# R5 R7 a, b5 j! o+ ~
  47. 47    /*输出通道电平极性设置*/
    0 \! X/ j1 O) |; W( U& }5 p* B  |1 y
  48. 48    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
    " d' r$ M+ X( O9 Z
  49. 49    /*初始化输出比较参数*/$ C, s! _3 w9 q7 G/ t  b/ m* I/ O
  50. 50    TIM_OC2Init(TIMx,&TIM_OCInitStructure);2 G, \+ l( A, Z  Q0 I
  51. 51    //-----------------输出比较结构体初始化 结束-----------------------/    0 v* P& ]. k& w6 w6 h
  52. 52    /*自动重装载*/
    ( P) A/ P4 T4 ^8 ^; |% s+ M" k; y
  53. 53    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);2 L" a* I# ]2 t  g7 [# S0 T' W( r
  54. 54    /*使能计数器*/
    # \6 w( h8 r) n9 {* ~1 L
  55. 55    TIM_Cmd(TIMx,ENABLE);5 `+ b% o! G: r! P3 u' g
  56. 56    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/+ e" i( }: a3 [
  57. 57    TIM_CtrlPWMOutputs(TIMx,ENABLE);   
    6 r; o5 ?3 w$ d/ N/ {/ t0 |
  58. 58}
      H4 M1 F5 G# c
  59. 59/*舵机PWM初始化- F- Z3 \! B( A, h+ e9 Z
  60. 60   每增加0.1ms 舵机对应增加9度( M$ A4 N6 y1 r
  61. 610.5ms---------02 G( R  t9 @  f" V: H+ a- z
  62. 621.0ms---------45   ) D" e+ \6 F+ s
  63. 631.5ms---------90
    " i9 Q1 z( H5 B, }  w9 [7 t) c
  64. 642.0ms---------135& o. w3 ]2 q" a9 I
  65. 652.5ms-----------180
    2 p% q8 g% a6 l4 s) @
  66. 662.1ms    turn_left=1508 k; d8 M7 {/ W6 Q4 d5 A* ?. f
  67. 670.8ms    turn_right=25
    : j2 A# r$ r- q( e" \1 z
  68. 681.3ms    turn_front=75
    1 t0 I( x8 A5 _' ?& R
  69. 6920ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平为1.5ms,周期为20ms的方波,duty=1.5/20=7.5% ,而定时器自动重装载寄存器arr的值为 1000 ,所以duty=75,时占空比为75/1000=7.5%.
    0 V' q, Z9 u' ^8 p2 P) k9 S
  70. 70*/
    . Y) m$ J5 K1 L
  71. 71void SERVO_Init(void)( T: ?0 h8 Y' `# o* H
  72. 72{
    ( |' n& ?. W! g$ T  }. @7 z
  73. 73    SERVO_Gpio_Init();; Q* A5 K0 b8 }- @0 ~" A+ b
  74. 74    SERVO_TIM_Config(TIM3,1000,1440,turn_front);
    ! P9 i  c' t% R( s. ]
  75. 75/** 我们把定时器设置自动重装载寄存器 arr 的值为 1000,设置时钟预分频器为 1440,则2 }4 L/ F- H) Y2 j! E4 E
  76. 76驱动计数器的时钟:CK_CNT = CK_INT / (1440-1+1)=0.05M,则计数器计数一次的时间等于:
    ! d( @; Q1 p. t* b- d' H
  77. 771/CK_CNT=20us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间
    % q" E/ v' q! |/ q
  78. 78为:1/CK_CNT*ARR=20ms。
    ) R/ @" F* Y, {; p6 T
  79. 79PWM 信号的频率 f = TIM_CLK/{(ARR+1)*(PSC+1)}  TIM_CLK=72MHZ  m$ C1 T' D% h3 n3 U
  80. 80               = 72 000 000/(1000*1440)=5KHZ    ' l7 U  S% V% Z3 q/ M. O6 \
  81. 81*/    3 z5 `1 G) A& d/ M1 s) [2 }+ `
  82. 82}6 }& j) S  |) Q- @- v2 J
  83. 83/*舵机角度控制*/% n- \5 n3 h5 m( v4 a) a! O! K* X/ u
  84. 84void SERVO_Angle_Control(uint16_t Compare2)  L! z8 K3 `, l* F1 @
  85. 85{' R/ i) T, H3 |  s  ]+ ^' w% n
  86. 86    TIM_SetCompare2(TIM3,Compare2);: H/ ?0 |8 |4 {% }# A& n
  87. 87}
复制代码

, z+ T0 U( o' H) K
5 t- Y7 L" ^1 }2 @
编码器模块
8 |1 b+ C, C. Y3 S" c
: Q3 ~2 V1 A; |! z( k$ j. ]
调节小车前进的速度和避障快慢我们采用EC11旋转式编码器,可以用于光度、湿度、音量调节等参数的调节。EC11编码器的形状类似于电位器,中心有一个旋钮可以调节PWM信号,光电码盘利用光电转换原理输出三组方波脉冲。EC11编码器的实物图如下:+ ^( o, n( z) t4 S" d# K& o/ Y
8.png & F! G4 Q' m5 Y6 s3 J$ \
% o- ]# z2 z9 o# j- |
OLED显示模块
/ u1 o8 M. I' _; }/ p
3 _1 [: C/ \0 p
用来显示小车转速,以及左右编码器数值和电池电压等参数所用的是OLED显示模块,分辨率较高,而且功耗低,正常显示时仅0.06W,供电电压范围在3.3V-5V,有IIC和SPI两种通信协议可供选择。显示模块的亮度和对比度可以通过程序设置。由于它使用寿命长以及其他的优点,OLED更加适合小系统,本系统由于单片机引脚有限,不适合利用简单的LCD1602或者12864来显示,在多方对比之下OLED效果更好。OLED显示部分相对比较简单,大家参考中景园的例程就可以实现。
$ x/ x6 S% w& N8 T, y! f8 \9 ~9 j% y/ q5 o
4 u4 h7 Z8 J( l  l
( R5 w+ C& b+ p. K" v

: U3 R% @' u, G文章出处:程序员小哈
/ Q3 n6 r# G8 O6 M* g+ {
收藏 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 手机版