前言
' I! x) E) P2 V# z本篇文章将带大家学习STM32智能小车的循迹功能。# E0 i: c+ Z, o
- y5 h( b& h+ N- L5 N0 o/ w" ]一、红外循迹模块工作原理及接线图
, X* _8 `4 R$ x9 U, I- G2 b红外循迹模块工作原理7 G! }$ o g/ p# X+ Q6 ]
电路工作描述, A- ^1 D& S: C; O) u
以其中一路为例
1 U8 k" z" P/ R. m; l! w( q7 d% @( }, E- m0 c. H
: o5 ?+ @% K+ ~" |
' P7 l9 t! L% A( b- q2 gTCRT5000传感器的红外发射二极管不断发射红外线,当发射的红外线没有被反射回来或者反射回的强度不够大时,红外接收管一直处于关闭状态,此时比较器LM393的2脚的电压低于3脚的电压,输出OUT1为低电平,LED1为点亮状态;当红外反射强度足够且被接收到时,比较器LM3932脚的电压大于3脚的电压,输出OUT1为低电平,LED1为熄灭状态。简单的可以理解为遇到黑线灯亮,遇到白线灯灭。
8 m7 X" F2 X% g: ^4 G6 g4 l; I! B: B1 v) O
红外循迹模块和STM32的接线图' X: y5 n6 U$ K: A5 T/ u
此红外循迹模块使用到了4个IO口分别接到了STM32的PA4~PA7。
5 A8 ~" B; }7 z9 h( r6 l* i9 s3 i' n; D5 v2 w# E
2 [# H6 A0 b' Q3 k& c0 [( J0 s# E8 p( B
二、cubeMX配置
% D! O1 M5 P! |& R' f! D" l$ Q将红外循迹的4个IO口都设置为上拉输入模式即可。 P( ^5 w: c$ E' X5 m3 P! r
- E9 H0 k2 T9 i
; r( u- `7 |( D4 `% y F8 D0 w. A1 q/ o! r: w. {
三、代码解析* {3 b$ q$ U1 d
find.c7 N8 K" n9 a7 ~6 G
5 L; O# I7 E0 z
- #include "find.h"- B# V% B( S$ y, u
- #include "Moto.h"
, ]1 m! E9 I; l) \ x
/ t2 I+ @: p1 K- extern TIM_HandleTypeDef htim3;
9 R3 o) ~1 H, i/ c" n' \8 Y* x& w* B
7 t' Y: C3 |5 Q- /*9 e5 M* d J- \! c& C* I' k( h6 a
- 函数功能:调节小车左右电机PWM6 J2 C: Z; C4 ^' N0 Y. `$ i3 c
- Left:左电机PWM
7 l; U' F1 I! q - Right:右电机PWM: ^8 s6 {* K1 R1 R1 q, {
- */9 x# M0 [% u" @) q3 K" V) g
- void Moto_speed_set(int Left,int Right)
- s4 R4 d0 U: _ - {0 H' @* n1 q2 {4 J/ O+ ^. j
- __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, Right);
6 h# l; S! T: `# ~) Y - __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, Left);
( e+ n" l3 }0 B) t/ O; E8 |+ f' _ - }
1 M, d6 t5 F: Z$ ^; m - # S0 N' f" H4 A! H5 P5 @& M0 p
- /*. I2 g; C4 r0 K; m' G3 d
- 函数功能:循迹1 q1 K9 V J7 }' e5 w
- */6 C8 z( [9 K l7 _8 B2 K
- void Find(void)
" ?% [; ?9 s8 a) y1 t4 a$ m* { - {
3 o3 i0 Z& E1 h8 D3 `! b# I - //全是白线前进
0 g4 H, v Q& K: R - if((IO1_read()==0)&&(IO2_read()==0)&&(IO3_read()==0)&&(IO4_read()==0))7 W) c' P: p {! v8 O) d
- {
: J( r, a( Q0 C. |$ \% }) d; l - Moto_speed_set(800,800);$ h- n# }1 m. E+ r& h! R
- car_move(0);
/ S8 f* u4 l0 q( k* ~ - }5 R& p$ S) b9 \
- //右边有黑线小车向左即左轮加速右轮减速
3 q# A2 s; B; e7 {# T. ^ - else if((IO1_read()==0)&&(IO2_read()==1)&&(IO3_read()==0)&&(IO4_read()==0))
, G$ O# b5 v3 ^5 V - {
( w. X" H# R/ R4 Q( R' v - Moto_speed_set(800,0);' I7 J/ P1 [' ]3 O7 E: w& R
- car_move(0); 1 K& n* v1 K3 G4 p, M4 q8 {
- }
5 H# \# L% D# f( m$ O' U - //右边有黑线小车向左即左轮加速右轮减速
' F6 O' m( N" p7 ] - else if((IO1_read()==1)&&(IO2_read()==1)&&(IO3_read()==0)&&(IO4_read()==0))
: T5 o: r2 q b: j, \' `- Z - {% v5 q' \* ?, x9 X5 R3 ?- B
- Moto_speed_set(800,0);
: n9 H, ?) \" |, s8 t: ? - car_move(0); ! W) Z( Q5 A8 F! `# B. B% p
- }
3 o2 y- T, q& ?# ]7 m+ U2 O - //右边有黑线小车向左即左轮加速右轮减速
: L4 r* z% t& ^' k: w) k+ B - else if((IO1_read()==1)&&(IO2_read()==0)&&(IO3_read()==0)&&(IO4_read()==0))8 J# A, T# ]- z- N% }$ _- D
- {
0 x" _! r0 J: B - Moto_speed_set(800,0);' N5 J) O; t8 |! |0 N! X
- car_move(0); * P- H. {1 {/ B5 |4 G* L( B
- }
5 K* q. t( I# V' G; Q3 b* ]6 V
& t% H) o$ N, H! X( n; d7 z
% o( m! ~' B7 l& o7 D: O4 T- //左边有黑线小车向右即右轮加速左轮减速
2 D# s& s) Z. @7 T6 e - else if((IO1_read()==0)&&(IO2_read()==0)&&(IO3_read()==1)&&(IO4_read()==0))" k( }: K ]% _
- {
# K( J0 W( u: w$ G: T ^3 [5 R - Moto_speed_set(0,800);
. V$ K/ z6 H, t- M0 M - car_move(0);
6 U/ J) C; Q* e3 v( f/ t - }/ m/ G5 ^) j# _% n
- //左边有黑线小车向右即右轮加速左轮减速
4 r5 ]6 p1 |/ s - else if((IO1_read()==0)&&(IO2_read()==0)&&(IO3_read()==1)&&(IO4_read()==1))
. d+ g d B4 `3 S- c3 C - {
) m' _ w' E2 z# C2 N$ P - Moto_speed_set(0,800);$ n9 K5 }# e+ O1 _8 `* ]+ s
- car_move(0);
# M7 F( B& S) N( d# V. O - }
2 P" Z" N( x8 H% j0 P1 f4 Q - //左边有黑线小车向右即右轮加速左轮减速0 E* b& c' U# @0 |3 W. j3 P8 D
- else if((IO1_read()==0)&&(IO2_read()==0)&&(IO3_read()==0)&&(IO4_read()==1))
& V8 x) l/ e+ @4 m* f7 N - {* R2 W8 u/ Y: ~9 J" S
- Moto_speed_set(0,800);9 q2 @, ^) ^6 _$ w/ G
- car_move(0);
% O. Z# b" P5 R6 V - }$ x1 n' P/ v" J& q# C/ ~4 M8 q
^1 b. Y7 t/ q5 e$ o/ K2 ~. D- //全是黑线停车
; a2 M9 M* r5 D; P8 N( V7 c! s- |9 A - if((IO1_read()==1)&&(IO2_read()==1)&&(IO3_read()==1)&&(IO4_read()==1)) k+ |8 c: y9 r0 d9 X9 @
- {* [/ {5 f' l7 b9 G
- Moto_speed_set(0,0);$ C I$ K; @+ K. r: m
- car_move(2);
9 z2 M/ T. `% s9 h1 Y1 t9 E# S. r5 ^ - }) E1 x0 P+ X; \* _; @8 C' W4 A+ x
- }
复制代码
9 ^5 [" b$ C6 E5 S7 \. ^. E: tfind.h6 i, g" f6 d( N& A% X: I
& `6 _8 a$ [& s3 S. m* p/ z
- #ifndef _FIND_H_
/ H# v$ s+ P& ]9 D8 J8 y - #define _FIND_H_
0 s; W6 C% V0 ?8 @! \3 D3 e% ~% E, N - : b9 c: s6 ^ S( [( m/ }
- #include "main.h"
- Y7 b0 X, z2 I5 K: i$ a - , X5 D; Q4 i7 b5 s% a8 Q
- #define u8 unsigned char
: A" J1 G- q+ l, ]! k% q - #define u16 unsigned short
" I: F" S3 L0 t! h8 m - #define u32 unsigned int
" Q% o' P, v9 i$ M - . m0 Z8 z$ e0 d0 S7 m* T" q# N
- //红外循迹IO口定义
) Y* s. e { r* B6 t* ~ - //传感器从右到左 IO1 IO2 IO3 IO4
5 N- k2 J$ T6 h, s: b$ x {9 t3 ?$ j - #define IO1_read() HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)
; b9 Y$ M- C% c. B. I* } - #define IO2_read() HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)8 L+ p) s& G1 s! z
- #define IO3_read() HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)
" ]0 E# ~& G6 @" V: j - #define IO4_read() HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)+ o ?9 a: c1 t+ r6 D+ [
- % o2 s) _! l, I
, d$ X" l1 ^5 B. w+ y9 z z- void Find(void);3 K1 Y* s5 A: f
- void Moto_speed_set(int Left,int Right);
8 I5 O5 O/ o2 R$ L" x3 `, M
8 {0 R: f3 Z3 d- A* B7 \3 g+ }9 x
- #endif
复制代码 4 P6 @- [1 `5 A+ s
总结
# q& O2 [$ `0 D5 Q# c- b循迹代码已经贴出希望大家可以好好理解一下循迹算法的编写。
! H1 e' ?: R7 P2 x
) E5 F" }* o+ w* }; E. `9 P9 I
* n! ?; c" P# n+ h( M |