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

基于STM32超声波避障小车

[复制链接]
STMCU小助手 发布时间:2022-10-24 19:54
今天给大家介绍的的一个项目基于STM32超声波避障小车. V8 b/ n& l% s4 l% R$ T8 A

# A- f) f2 ]* b$ }# t9 m5 m" w

处理器电路设计

单片机是系统的CPU,是系统稳定、正常运行的重要前提,以下为单片机选型的两种方案:; k0 {- e& E( ?9 M; ]
(1)传统的8位单片机,是通过超大规模集成电路对其进行集成为一个独立芯片的控制器。内部组件包括CPU、随机存储器、只读存储器、I/O接口、中断系统、计时器、串口通讯、数模转换等。STC89C52单片机是最常见的51单片机,但是资源较少,精确度低,处理速度相比STM32单片机差很多。
(2)使用目前市面上最常见的STM32单片机,STM32系列单片机可分为ARMCortex-M3内核体系结构的不同应用领域。它可分为STM32F1系列和STM32F4系列,STM32F1系列单片机时钟频率最高可达72米,在同一产品中性能最好。单片机的基本处理速度为36米,16位单片机的性能也很好。微晶片的内建快闪记忆体相当大,范围从32kb到512kb,可视需要选择。单个设备的功耗非常低,仅360mA,32位单片机产品的功耗最低,每兆赫只有0.5安培。特别值得一提的是,内接单晶片汇流排是一种Harvard架构,可执行速度高达1.25 DMIPS/MHz的指令。此芯片越来越多地被用作主要控制器。
   通过对单片机的资源和处理时间的速度我们采用选择STM32103C8T6为本系统主控芯片,程序下载是只需要一个JLINK就可以轻松完成。控制器模块电路如下所示:

- ~$ X: U' W+ D8 P, k5 q7 v- I* L# |' N
微信图片_20221024195419.jpg

7 C$ T2 Y! ?, T5 O
电源模块设计

本设计采用锂电池供电, 模块的供电电压一般都为5V,同时超声波模块需要较大的电流才能正常工作,所以在降压的基础上也要保证足够大的输出电流。本设计采用可调输出版本,模块的输入电压范围广,输出电压在1.25V-35V内可调,电压转换效率高,输出纹波小。降压电路如下所示:

8 G' [' w6 z5 p% R* h' g3 n: I
微信图片_20221024195417.png

! S- M3 \  ^# F2 i
电机驱动模块设计

要完成转向是能够利用单片机实现的,然而单片机I0的带负载能力弱,因此我们选择了大功率放大器件TB6612FNG。TB6612FNG是采用MOSFET-H桥结构的双通道大电流电路输出,可以控制2个电机的驱动。相比普通的电机驱动,外围电路非常简单,只需要一个芯片和一个钽电容进行PWM输出滤波,系统尺寸小。PWM信号输入频率范围广,轻松满足本设计的需求。
   
微信图片_20221024195413.png
4 ]8 V% |1 |% C1 y
电机驱动引脚表
  1. 1控制芯片:TB6612  |8 r& H! J- }, D; s+ ?8 w  [* Y
  2. 2控制芯片数量:28 S) U. {6 o; `5 P3 ^
  3. 3    1号TB6612引脚分配:) _( D4 J0 `( I( M  d
  4. 4     VM         PWMA--------->TIM1_CH1(PA8)5 r0 Z: r+ {( `! X, r5 w$ Z  b" y
  5. 5     VCC        AIN2--------->GPIOB_124 Q: q% Y- V' y; L% A9 _
  6. 6     GND        AIN1--------->GPIOB_13
    " b9 ~0 S( r+ @# M; f
  7. 7     AO1        STBY--------->GPIOB_14
    8 _) o* P% B  b. v3 x! U1 f3 V. a8 v
  8. 8     AO2        BIN1--------->GPIOB_15
    . ^1 |( x* s' M" c# K, z( G% c
  9. 9     BO2        BIN2--------->GPIOA_12
    / h% `% S. X- q. E' @- a! {- m
  10. 10     BO1        PWMB--------->TIM1_CH2(PA9)0 y, A! r$ x, j* M- N0 B$ G
  11. 11     GND        GND7 e& o, ]% i  r6 w) V8 s
  12. 12    2号TB6612引脚分配:/ a, H$ i( l8 Y& E6 e$ N
  13. 13     VM         PWMA--------->TIM1_CH3(PA10)
    2 N8 K0 F2 w" v7 w6 H( H9 ~5 q
  14. 14     VCC        AIN2--------->GPIOB_5
    & c5 M# o4 t$ E( ]4 p/ v
  15. 15     GND        AIN1--------->GPIOB_6
    9 M. |0 O" Z# K, h% u
  16. 16     AO1        STBY--------->GPIOB_71 b1 K& Z+ |% l8 n3 q, m: f8 e( k
  17. 17     AO2        BIN1--------->GPIOB_8
    : X7 ^% a3 |" D$ {3 j
  18. 18     BO2        BIN2--------->GPIOA_9* L/ O& n) C; r. i. J
  19. 19     BO1        PWMB--------->TIM1_CH4(PA11)
    & C" S& m; L: A/ D( d/ J; _
  20. 20     GND        GND7 t( w& y9 k: A" ~$ V2 R+ ?
  21. 21真值表8 R6 p1 w  a  `# q! Q/ V3 v4 _& w
  22. 22     AIN1   0     1     0     1/ ^3 N6 Q( V" ]: i6 w: ^
  23. 23     AIN2   0     0     1     1) d! Y) p0 a$ }2 ]. \
  24. 24     BIN1   0     1     0     1
    : N6 c  |$ `$ l4 ?' N
  25. 25     BIN2   0     0     1     1
    : z9 n& h" E/ C" g- r
  26. 26           停止  正转  反转  刹车
复制代码

  q2 h6 ~5 u: @: w. t8 e. V
电机所用到的定时器配置
  1. 1//初始化TIMX,设置TIMx的ARR,PSC5 C1 X/ i) `6 R
  2. 2//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期6 p3 L8 n! j+ g5 K' W; P
  3. 3//定时器选择TIM1! v8 j: x8 j5 f2 b! y2 i
  4. 4static void TB6612_ADVANCE_TIM1_Mode_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)$ D7 P6 H8 [+ i* W
  5. 5{; W$ H" r- `; P" I) H, @& J" n
  6. 6    //-----------------时基结构体初始化-------------------------/
    - u# g% ]' f1 `+ P
  7. 7    TIM_TimeBaseInitTypeDef TIM_TimeStructure;
    ; w  K( M* D; I* J6 U
  8. 8    /*开启定时器1时钟,即内部时钟CK_INT=72M*/# l$ m. H7 `" Z( `1 g
  9. 9    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
    $ T# c$ D0 l; F$ R7 a9 N! E
  10. 10    TIM_DeInit(TIMx);
    * R% R( V! f1 p
  11. 11    /*内部时钟作为计数器时钟,72MHZ*/
    ; ^. r! o: ~# i1 D% L
  12. 12    TIM_InternalClockConfig(TIMx);
    / m  h8 `# ^# _2 w7 e7 J$ r/ J
  13. 13    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/
    ' e. u+ F4 S: A/ W( F, D( i
  14. 14    TIM_TimeStructure.TIM_Period=arr;0 g1 s; u0 l( M/ T7 B+ d
  15. 15    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(71+1)=1MHZ*/# k( v" `8 C  u- ^( `+ O5 c5 J
  16. 16    TIM_TimeStructure.TIM_Prescaler=psc-1;3 g4 G5 o! a7 ~. i- s8 T
  17. 17    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
    8 Z  c) q  B# y
  18. 18    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;7 ]2 s6 ~1 `/ W, V: E8 I5 S! ~" a* X
  19. 19    /*向上计数模式*/
    1 V6 D$ d. \' n1 `! C( V( d2 ~
  20. 20    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
    6 A% b# P: S+ k, k" E
  21. 21    /*重复计数器*/
    & \3 u' W: O& _, P- v5 P
  22. 22    TIM_TimeStructure.TIM_RepetitionCounter=0;# D6 N0 r' h( M8 k
  23. 23    /*初始化定时器*/8 E' p' K, |; B4 _; W: p' L# o
  24. 24    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);% N" B2 X" y; y& |3 E. e2 c
  25. 25    /*使能ARR预装载寄存器(影子寄存器)*/7 m6 J9 Q" \5 S/ i
  26. 26    TIM_ARRPreloadConfig(TIMx,ENABLE);2 `4 r: O' ]0 k# N5 `- O
  27. 27    //-----------------输出比较结构体初始化-----------------------/7 C) U, X' d/ ^$ W: r9 ?
  28. 28    TIM_OCInitTypeDef   TIM_OCInitStructure;' h+ m4 C2 m, d. ~9 l- R
  29. 29    /*PWM模式设置,设置为PWM模式1*/
    2 [& B! W; }( U! l: w5 F
  30. 30    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    + b$ Z( @- l: I, \4 Q9 @  G4 O
  31. 31    /*PWM输出使能相应的IO口输出信号*/1 P5 G. ^% R3 r. H
  32. 32    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
    2 Y% {% W8 J( Q% n8 \, E* I/ @; T% P! q
  33. 33    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
    ) K) n* S2 _( p5 p6 i$ K* @
  34. 34    TIM_OCInitStructure.TIM_Pulse=duty;% `7 [* x- N  Z- N6 e
  35. 35    /*输出通道电平极性设置*/" y8 C3 C* k9 Z! R8 [. u
  36. 36    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
    8 I  v6 G( R0 x. r& ]. O
  37. 37    /*初始化输出比较参数*/% y9 L1 Q) ]- k
  38. 38    TIM_OC1Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道1
    4 r2 e) J1 n/ r$ s+ Q& d7 g
  39. 39    TIM_OC2Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道2/ m. g. v7 L" Z: D* Y8 Y5 ]! z% ?
  40. 40    TIM_OC3Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道3; L/ m. L" d" e" v( N7 s9 {
  41. 41    TIM_OC4Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道49 \6 s( }, M/ {, P
  42. 42    /*自动重装载*/
    9 E/ B0 @6 m5 E6 x" s, d
  43. 43    TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable);) x/ n5 F$ t8 H  N! k8 A0 ?
  44. 44    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
    4 Y( h* c+ Q: v/ }/ m$ s
  45. 45    TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable);. O, |$ t+ |8 \
  46. 46    TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable);
    2 j$ E, y+ X8 A3 ]4 G' D8 q% @) h
  47. 47    /*使能计数器*/, D  C6 X4 Q: u
  48. 48    TIM_Cmd(TIMx,ENABLE);
      @: E  }; I- f
  49. 49    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
    ( @  j9 p) A' e$ d
  50. 50    TIM_CtrlPWMOutputs(TIMx,ENABLE);   
    , Z# _, E1 f' I5 C( G/ `! E
  51. 51}5 X2 g# z* k0 |$ N
  52. 52//高级定时器输出通道初始化函数
    3 T6 |7 |: o4 ?' i7 q$ L
  53. 53static void TB6612_ADVANCE_TIM_Gpio_Config()
    ( M5 w3 `$ D7 I2 N0 b. \) W4 V
  54. 54{
    ! b: p3 b( l/ r, \/ g- }& F
  55. 55    GPIO_InitTypeDef  GPIO_InitStruct;
    ) r( |: D9 q+ \! ~% i
  56. 56    /*----------通道1配置--------------*/" p. J" m) C" w# E6 a$ _
  57. 57    /*定时器1输出比较通道*/! M) @. g) y0 M5 g  Y
  58. 58    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);0 h& }! K0 [/ s+ J! B& R" S: E
  59. 59    /*配置为复用推挽输出*/4 T' ~+ ^; k, X/ k
  60. 60    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;7 C& R0 E& V) C9 A& {* V# t
  61. 61    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
    5 {' ^  u2 Q' }, G) t/ ?
  62. 62    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    5 s2 x% Z, P& s
  63. 63    GPIO_Init(GPIOA,&GPIO_InitStruct);
    0 ?" u5 B( E$ v! p  G6 T
  64. 64    /*-----------通道二配置-------------*/9 t9 q2 i# ^, Q8 u
  65. 65    /*定时器1输出比较通道*/* g: j0 v6 E. ]8 ~
  66. 66    /*配置为复用推挽输出*/
    9 e# V5 e# X4 ~% [6 O
  67. 67    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;# a# E# f0 u3 G
  68. 68    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;9 H: ^' C: N5 k5 m
  69. 69    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
      y- d7 }( R3 ^2 l
  70. 70    GPIO_Init(GPIOA,&GPIO_InitStruct);  V" y' v0 U1 V% r: V
  71. 71     /*-----------通道三配置-------------*/
    2 ^4 H% A5 l  x2 L: p
  72. 72    /*定时器1输出比较通道*/! L% v5 k% J. f. d' X5 D
  73. 73    /*配置为复用推挽输出*/
    + G- I- a3 }" I# k0 c+ _
  74. 74    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;% c3 T6 u* `" I  I+ B
  75. 75    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
    + L+ e5 S' Q. z4 t
  76. 76    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;+ a' [! z% L6 {8 N+ C/ F
  77. 77    GPIO_Init(GPIOA,&GPIO_InitStruct);- O4 `3 Q9 I+ A, H. L) [
  78. 78     /*-----------通道四配置-------------*/
    2 q! k4 d* X/ l% v& ~. s) a
  79. 79    /*定时器1输出比较通道*/# O4 N. m0 A* i" q
  80. 80    /*配置为复用推挽输出*/
    4 A4 K+ E1 }" w) n9 Z$ o
  81. 81    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    8 S2 \' s: @/ O  p" D6 k+ E5 G
  82. 82    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
    ! C) K; Z! ?: K1 ]  C* ^
  83. 83    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    8 l" n' d! D3 {* f* c; m! t  [
  84. 84    GPIO_Init(GPIOA,&GPIO_InitStruct);
    ! A1 V9 A% Y' W0 R" y
  85. 85}
复制代码

4 X: h7 d' ?: l
% P  @: Z* U# e8 m$ R0 m4 T" O

超声波模块8 ]8 q" G' g+ e+ @2 X& ^

采用HC-SR04超声波模块,该芯片具有较高的集成度以及良好的稳定性,测度距离十分精确,十分稳定。供电电压为DC5V供电电流小于10mA,探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)。HC-SR04实物图如下:

4 `1 i% B2 b% V  K4 S' d+ m
微信图片_20221024195407.png
+ i& M+ m) j" v& t" l6 }
该模块是利用单片机的IO触发电平测距,单片机内部利用普通定时器产生一个高电平信号之后,超声波就可以自主发送频率为40khz的方波,然后等待信号的返回;若有信号返回,单片机IO口就立刻输出一高电平,利用高电平产生的时间可以计算小车与障碍物的距离。最终距离就是高电平持续时间乘以声音在空气中传播的速度再除以2,可以反复测量距离。
  在程序开始首先初始化超声波,利用定时器并设置时基的自动重装载初值1000,psc为预分频值72,这样的话我们产生一次中断的时间是1ms,并设置抢占优先级0,子优先级3。HC_SR04_Echo引脚接收到高电平,打开定时器,且每1ms进入一次中断。在测量时首先让Trig发送一个大于10us的高电平,然后拉高HC_SR04_Trig,当Echo为0时打开定时器计时,当Echo为1时关闭定时器,通过公式计算距离。
模块工作原理:, Z. |* H1 M- v0 j
(1)单片机触发引脚,输出高电平信号;
6 e  d1 p: h: n2 z(2)模块发送端自动发送特定频率的方波;4 s( n# Y" N. S3 ]
(3)如果有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波的发射时长;
+ g0 {; H3 m" M( f0 z  m2 k(4)测试距离=(高电平时间*声速(340M/S))/2。
注意:在硬件操作上需要首先让模块地端先连接,否则会影响模块工作。测距时,被测物体的摆放不能太过于杂乱,否则会影响测试结果。
- F3 U% S" R/ w
微信图片_20221024195404.jpg

  }9 ?9 k$ `! Q3 {1 v( \超声波重要代码(可参考)
  1. 1/* 获取接收到的高电平的时间(us*/
    6 w5 j9 d8 v- Q. W! g. A7 L  ~" q
  2. 2uint32_t Get_HC_SR04_Time(void)
    % y2 ]( U. e5 K  k! ^3 G
  3. 3{
    / H4 e' ]6 O9 {* ^1 n2 [' m4 p
  4. 4    uint32_t t=0;0 @) l" ~5 T* W+ [5 x( j/ {6 v
  5. 5    t=Acoustic_Distance_Count*1000;//us
    # @3 V2 k& o! X: |6 i1 ?9 c
  6. 6    t+=TIM_GetCounter(TIM2);//获取us
    8 I" f9 G) }9 z8 }1 v* m
  7. 7    TIM2->CNT =0;
    * M' G- e) N* }3 g) d  h
  8. 8    Acoustic_Distance_Count=0;
    ( S0 i' V8 c+ A$ @, R+ a, N
  9. 9    Systic_Delay_us(100);; F! d4 ^3 \8 w" P8 B& a* W
  10. 10    return t;( r2 _$ E6 f7 Y) o! j
  11. 11}% G& ]& p+ q. q1 [
  12. 12/*获取距离*/
    ( T- |3 M2 j* z  n8 K( `& t5 Z0 C
  13. 13void Get_HC_SR04_Distance(void)  r' I+ `5 x8 E
  14. 14{
    ' A2 ?) u; k4 O  `  e1 h! O& [+ ]
  15. 15    static uint16_t count=0;
    & b" f1 n+ H: M8 u% p8 p1 d6 Y
  16. 16    switch(count)4 o2 j7 T) s. k- Q
  17. 17    {& q! M: e+ `! M! F  I  D
  18. 18        case 1:+ P1 V3 F6 A6 `/ I; d
  19. 19        {+ U/ s' z; r, M. ]0 O  I
  20. 20            GPIO_SetBits(Acoustic_Port,HC_SR04_Trig);//Trig发送一个大于10us的高电平
    + b  i5 m6 s6 Q. S0 k* j
  21. 21        }break;
    9 p2 E. r  H" @4 H% ^! N
  22. 22
    2 I6 S8 ~; A2 ?8 a6 S; Q
  23. 23        case 15:
    4 h) x* U+ h1 F3 u9 V6 A# d
  24. 24        {
    . k, U( b. q# R9 p) Y: y! f, G
  25. 25            count=0;
    9 W. ?! p# }& K9 |% o5 G
  26. 26            GPIO_ResetBits(Acoustic_Port,HC_SR04_Trig);
    * W! N( _4 ^+ E* F
  27. 27            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==0);//当Echo为0时打开定时器 计时% R; t! D% [* M* j4 D8 g* \2 S
  28. 28            Open_Tim2();8 N) P4 |6 }. X7 T, n6 i* G" ?& ]
  29. 29            while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==1);//当Echo为0时打开定时器 计时
    - D" Q0 x* ]4 g0 N  c( |
  30. 30            Close_Tim2();
    # G) T8 J; R. K1 d, v
  31. 31            HC_SR04_Distance=(float)(Get_HC_SR04_Time()/5.78);
    6 l3 j& E4 l- d6 O, l1 v' y9 j, g
  32. 32
    0 C: }9 O* K5 I2 `9 Z- q5 `
  33. 33        }break;
    , r; i! k% Z7 K$ q3 I+ a$ M  H
  34. 34        default:break;; ?* ?+ e' u& l7 D8 ~
  35. 35    }
    ; ?, i5 [* M! |' M5 U/ G2 S
  36. 36    count++;! |+ T, u; P% s3 v, W
  37. 37}
复制代码
' j0 t0 D* K/ L. e, ]

舵机模块

本系统使用的是SG90型号的舵机,舵机是一种常见的角度驱动器,本系统需要判断不同位置的障碍物可以且对转向的力度小。舵机可以理解为方向盘称,方向盘是一个常见的名字。它实际上是一个伺服马达。舵机实物图如下:/ W/ T  x8 @0 u( q0 u+ G' T
" G3 N* O7 i4 V  {% N
微信图片_20221024195400.png

# h3 q8 {0 u' N) N: |/ D3 `
舵机模块接口简单,舵机模块只有三个引脚。分别引引出了三根线左右两边是电源正负接口线,中间一根是PWM信号线直接连接单片机的控制引脚。通过控制单片机的引脚输出的脉冲宽度进而控制舵机旋转的角度。舵机每增加0.1ms 舵机对应增加9度。
0.5ms---------0
1.0ms---------45  
1.5ms---------90
2.0ms---------135
2.5ms-----------180
   20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平持续时间为1.5ms,周期为20ms的方波,duty=1.5/20=7.5%。在这里设置定时器自动重装载寄存器arr的值为1000,所以当占空比为百分之75是,在程序中就要设置占空比为75/1000=7.5%, 这就是具体的算法。
/ H% G. @  O" n( O, ]" v
舵机重要代码(可参考)
  1. 1/**PWM引脚初始化*/* g5 T7 l1 V. e/ H( P1 a
  2. 2static void SERVO_Gpio_Init(void); ?' J  A' \9 H9 c3 C
  3. 3{
    % g7 Y0 H, }& m6 L. t
  4. 4    GPIO_InitTypeDef  GPIO_InitStruct;
    . x/ I3 P. Q9 ~% x  y* P+ }0 z
  5. 5    /*----------通道2配置--------------*/+ I5 c' s0 N+ E) i1 Z& p$ T
  6. 6    /*定时器3输出比较通道*/
    0 ?& }7 [7 \9 e3 \, d
  7. 7    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    8 l/ V7 p5 Q" `2 [
  8. 8    /*配置为复用推挽输出*/0 L$ d  [- z: o1 W) k4 E) g, _
  9. 9    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;9 [* ?5 |! Q& f6 V4 d" |) K
  10. 10    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
    ( {* C5 x; L7 X
  11. 11    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;/ \* _( m: h- N9 f( x' U
  12. 12    GPIO_Init(GPIOA,&GPIO_InitStruct);
    * C: r& k  w4 M6 P& I
  13. 13}& e7 @4 c+ \* k/ r
  14. 14//定时器3初始化,设置TIMx的ARR,PSC& t; y0 J; G) l6 d& `/ E" W
  15. 15//arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期  R  `" j' ~* d; B' H
  16. 16static void SERVO_TIM_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty), G* N/ ]6 x/ B  s) z+ c; f0 \
  17. 17{0 {) H' p+ s3 O& p2 w# P
  18. 18    //-----------------时基结构体初始化-------------------------/
    7 s8 O+ V7 x+ Q/ x6 O4 a& S
  19. 19    TIM_TimeBaseInitTypeDef TIM_TimeStructure;
    / K  q$ d7 Z: _! u" Y
  20. 20    /*开启定时器3时钟,即内部时钟CK_INT=72M*/* O& K! q* C! e8 r) c  w2 L
  21. 21    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);% p4 q" P0 E% Y1 ?+ h
  22. 22    TIM_DeInit(TIMx);% L+ j/ B5 p3 S! _8 ?
  23. 23    /*内部时钟作为计数器时钟,72MHZ*/
    8 B0 q9 X# Q8 b: a
  24. 24    TIM_InternalClockConfig(TIMx);
    7 s, T& a, _4 K! ]5 A( G9 `6 s7 _
  25. 25    /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/' ^6 @$ E' P3 y/ b) q
  26. 26    TIM_TimeStructure.TIM_Period=arr;//1000 当定时器从0计数到999,即1000次,为一个定时周期/ [, n" y4 G4 D8 ]" |* d
  27. 27    /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(1440-1+1)=0.05MHZ*/
    . {/ z: M+ Y- y% n. g
  28. 28    TIM_TimeStructure.TIM_Prescaler=psc-1;;//1400  //即定时器的频率为5KHZ   
    # c, A0 Y' w' o& F& ?. l7 g
  29. 29    /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
    ! L" N* S1 f8 R; j
  30. 30    TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    ; H3 f5 A/ [' k
  31. 31    /*向上计数模式*/
    & C3 {( k# X6 g) V' x
  32. 32    TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
    . U& ]% T- T$ v5 h" b
  33. 33    /*重复计数器*/
    1 j- U" B' s  B# Y- z- y
  34. 34    TIM_TimeStructure.TIM_RepetitionCounter=0;
    1 T( }9 P0 F, A' ?: U+ P
  35. 35        /*初始化定时器*/
    9 q. r: V7 X' a5 h
  36. 36    TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
    / x3 {8 B$ v$ A0 Z& F- |4 X# f
  37. 37    /*使能ARR预装载寄存器(影子寄存器)*/
    * k  {( O$ ^( H- a9 i
  38. 38    TIM_ARRPreloadConfig(TIMx,ENABLE);3 A0 ?  `" A& S
  39. 39    //-----------------输出比较结构体初始化 开始-----------------------/
    9 t7 O: k# O% i( J  V
  40. 40    TIM_OCInitTypeDef   TIM_OCInitStructure;! {5 X' X' k0 F7 B  n8 ^
  41. 41    /*PWM模式设置,设置为PWM模式1*/( \7 {1 ?, y6 E1 z1 q5 J% L
  42. 42    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    / C: ?$ @+ N; ^* \( b
  43. 43    /*PWM输出使能相应的IO口输出信号*/
    2 a4 T3 r7 s( z' Q+ H) ]
  44. 44    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
    $ n5 v1 k. K9 [- V
  45. 45    /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/  C+ Z$ [" `0 n& {: n8 i4 ?& U0 ?
  46. 46    TIM_OCInitStructure.TIM_Pulse=duty;   //占空比大小: p& u9 h' M+ t& Y& L0 f: n, D0 V
  47. 47    /*输出通道电平极性设置*/
    $ \' e5 F0 w2 k$ C' U$ I
  48. 48    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;& q7 M3 Z) U7 O2 I
  49. 49    /*初始化输出比较参数*/
    " T- m' W0 {$ ]  n6 d# R" e
  50. 50    TIM_OC2Init(TIMx,&TIM_OCInitStructure);* _  h' v3 Z9 m
  51. 51    //-----------------输出比较结构体初始化 结束-----------------------/    ; L0 L- y& r; |5 m$ R
  52. 52    /*自动重装载*/' a- a+ m- h# P6 J; X: ^
  53. 53    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);: g9 i- ~9 e. u) w: d$ p7 p4 y4 K
  54. 54    /*使能计数器*/
    5 A* K. f3 n) G7 g7 D2 S
  55. 55    TIM_Cmd(TIMx,ENABLE);8 |0 Y6 A3 l1 f5 i$ o
  56. 56    /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
    + u9 s" C  D$ P* Q
  57. 57    TIM_CtrlPWMOutputs(TIMx,ENABLE);   
    1 h' D3 t; I" e# n! J; s& v
  58. 58}
    3 C  K$ W+ {0 N( F4 a0 F) F
  59. 59/*舵机PWM初始化# S8 L) f! X% H, A
  60. 60   每增加0.1ms 舵机对应增加9度
    : j  b7 P6 A/ A$ {1 ~' x
  61. 610.5ms---------0
    , X  Q9 N* M/ J
  62. 621.0ms---------45   
    3 g. {+ A; f+ E4 o0 M
  63. 631.5ms---------90+ E& ?  Q& d% A0 |% K- y& C0 C; F
  64. 642.0ms---------1358 I* b1 ~6 e7 R9 J1 i
  65. 652.5ms-----------180% q- D7 K  X+ D5 h8 \) \
  66. 662.1ms    turn_left=150
    + G- j; C7 u( Z4 r0 G) ?; I
  67. 670.8ms    turn_right=25
    5 Y- x/ M/ O+ j; N3 t
  68. 681.3ms    turn_front=75( W& j1 y7 Y5 F# [& z
  69. 6920ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平为1.5ms,周期为20ms的方波,duty=1.5/20=7.5% ,而定时器自动重装载寄存器arr的值为 1000 ,所以duty=75,时占空比为75/1000=7.5%.
    ' I% ^4 l3 a8 v2 v, ]% E
  70. 70*/
    . m7 y9 a" m( P3 B0 o" X
  71. 71void SERVO_Init(void)# Z: w- [9 O4 }" p/ [: ?7 B# x% v& H
  72. 72{
    8 G% L, J+ ]2 C2 |; u
  73. 73    SERVO_Gpio_Init();9 R7 @% v; f5 j
  74. 74    SERVO_TIM_Config(TIM3,1000,1440,turn_front);2 Q; O6 l$ r& x" V
  75. 75/** 我们把定时器设置自动重装载寄存器 arr 的值为 1000,设置时钟预分频器为 1440,则
    : L! U. K6 s* z5 ?
  76. 76驱动计数器的时钟:CK_CNT = CK_INT / (1440-1+1)=0.05M,则计数器计数一次的时间等于:$ F, C7 H3 s0 \# b6 b3 U
  77. 771/CK_CNT=20us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间
    % ?6 I: f. w7 U, [
  78. 78为:1/CK_CNT*ARR=20ms。; Y5 J$ J1 X# P
  79. 79PWM 信号的频率 f = TIM_CLK/{(ARR+1)*(PSC+1)}  TIM_CLK=72MHZ7 E# J1 |' q3 t( k% b. F: F/ ]
  80. 80               = 72 000 000/(1000*1440)=5KHZ    ; _9 m3 H9 A* p1 w
  81. 81*/    9 n0 f2 I) P% f- ]( P$ c
  82. 82}) C1 L; X8 L7 `4 ?
  83. 83/*舵机角度控制*/
    0 d' n* h; B' w, f
  84. 84void SERVO_Angle_Control(uint16_t Compare2)& Y. D/ T  X4 B. e' q7 D! P
  85. 85{
    , U! i' s* f" L5 _/ Z
  86. 86    TIM_SetCompare2(TIM3,Compare2);' |- ^! @& X0 R* A
  87. 87}
复制代码

/ ^* x" G6 y; T' m

编码器模块

调节小车前进的速度和避障快慢我们采用EC11旋转式编码器,可以用于光度、湿度、音量调节等参数的调节。EC11编码器的形状类似于电位器,中心有一个旋钮可以调节PWM信号,光电码盘利用光电转换原理输出三组方波脉冲。EC11编码器的实物图如下:" @2 w& J: m2 p$ V6 i0 U  P
; |" I3 o6 p' n9 \! U$ c8 V. D
微信图片_20221024195353.png
; D3 L+ F( E3 L3 }

OLED显示模块

用来显示小车转速,以及左右编码器数值和电池电压等参数所用的是OLED显示模块,分辨率较高,而且功耗低,正常显示时仅0.06W,供电电压范围在3.3V-5V,有IIC和SPI两种通信协议可供选择。显示模块的亮度和对比度可以通过程序设置。由于它使用寿命长以及其他的优点,OLED更加适合小系统,本系统由于单片机引脚有限,不适合利用简单的LCD1602或者12864来显示,在多方对比之下OLED效果更好。OLED显示部分相对比较简单,大家参考中景园的例程就可以实现。
$ w( I- i& v" z# O5 c
转载自:果果小师弟
; x$ O6 N$ u$ m7 K) x: p) X
收藏 评论0 发布时间:2022-10-24 19:54

举报

0个回答

所属标签

相似分享

官网相关资源

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