1、概述
+ O0 r* X4 S) F3 {7 y该智能风扇以STM32单片机为核心,结合红外遥控、人体感应、蓝牙数据传输、电机驱动等模块,实现风扇的启动、正反转、多级调速等功能,并通过物理按键、红外遥控以及手机APP三种不同的控制方式控制风扇实现各种功能,在LCD液晶屏上会实时显示智能风扇系统的实时状态,包括风力等级、工作模式、风扇转速等信息,在蓝牙连接的情况下会将这些信息发送给手机,在手机APP上实时更新显示。与此同时,风扇转动过程中安全保护机制也会同步开启,当检测到有人体靠近扇叶时,警报器鸣响,风扇立即停止转动。* u$ R( J: u/ }
: |; D) }1 ^$ h7 @1 H( T+ o/ S
' S; a" Q( c4 ^, a4 D8 n$ {8 n
; c6 |( e; a v9 p2 B' V9 i+ @3 v8 u2 ^+ p
2、硬件组成
2 e' \2 `& p3 |# vSTM32F103ZET6精英板、TFTLCD液晶屏、TCRT5000红外传感器、HC05蓝牙模块、L298N电机驱动模块、单片机自带红外遥控和红外接头
, R- Q9 u6 ^8 I) x9 l- }" q9 `! t. g: I2 G) v) @0 o
# I( e6 l8 l5 k
3 k/ Q+ W) A5 S" k) Z8 W# g0 r
+ k6 @4 v' U: S# y: o3、PWM调速原理
+ F( }0 |; o/ S- p# N 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。- r2 @' ~/ B) D+ }6 n( o
8 I2 R1 I* i& E# W8 M: m
我们知道,单片机的IO口输出的是数字信号,IO口只能输出高电平和低电平。假设高电平为5V 低电平则为0V 那么我们要输出不同的模拟电压,就要用到PWM,通过改变IO口输出的方波的占空比从而获得使用数字信号模拟成的模拟电压信号。PWM为高电平,电机提速运转,为低电平,电机不提速运转,如此一来,可以控制占空比来控制电机在一个PWM周期内的提速时间。* e% [ R" [) t8 S+ m/ o
9 M2 | w4 q' G$ i: P
' @5 J9 p; J* H L3 J( ~4 p0 z. e4、L298N电机驱动控制原理) p; m8 n3 @0 p2 l+ A8 I
0 M$ N6 N0 [) s# ~
6 x/ r, U, o& N3 W9 N0 x. |4 p v( U# ]2 j
L298N的两种接线方式8 o9 ]0 @9 ]1 x+ Z% {
(1)不用拔去ENA的跳线帽,此时使能端为5V电机满占空比驱动,全速运行;同理可知输入端IN3 IN4对应输出B口的逻辑全速则不用拔去ENB的跳线帽。8 t! h- G4 D/ D
(2)若要对直流电机进行PWM调速,需设置IN1和 IN2,确定电机的转动方向然后对使能端(本设计PWM输出引脚是PB5,所以驱动的ENA连接PB5)输出РWM脉冲,即可实现调速。
% |& A; l/ Z# l" O( f, G- H, B8 s# O# h
- e7 f: H! `; e# C7 L5、红外线遥控编码原理
2 ]# ^ ~# S- e& \6 ?红外线遥控是目前使用最广泛的一种通信和遥控手段。由于红外线遥控装置具有体积小、功耗低、功能强、成本低等特点,因而,继彩电、录像机之后,在录音机、音响设备、空凋机以及玩具等其它小型电器装置上也纷纷采用红外线遥控。4 X* t8 y4 }* I9 w$ a6 O
* J7 y6 X/ f, w/ u* \! T: u红外传感器红外发射二极管不断发射红外线,当发射出的红外线没有被反射回来或被反射回来但强度不够大时,光敏三极管一直处于关断状态,此时模块输出端为低电平,指示二极管一直处于熄灭状态;被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,光敏三极管饱和,此时模块的输出端为高电平,通过检测输出端的电平高低,判断风扇周围是否存在人体。
" [* I$ z& \) \( J! l
4 A2 r( J+ N" R
T/ m/ o% G% L& {2 q
. ~1 M A8 `* Q% r1 j
6、软件设计
/ D$ N9 B+ s& c% TPWM配置(PB5)
% J0 Z% I, @( X! |- void TIM3_PWM_Init(u16 arr,u16 psc)8 ]1 C" I3 K% t
- {
& ?8 b3 L4 Z3 ? - GPIO_InitTypeDef GPIO_InitStructure;
1 v6 F2 l3 R9 @2 W( n* j - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
$ l' m: H9 `& q" u, g0 T% U - TIM_OCInitTypeDef TIM_OCInitStructure;; o9 p" b5 D' k( V' t
-
: u; W1 c. e. `! U- F% ` - # {4 E5 r2 A8 q+ C/ a
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟, z" @( L/ t! R% @% H3 l6 r- p, x3 S
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟
! V, e$ N5 ]% ? - , B+ C4 w3 W1 G* `" {# w, I
- GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5 # u _& ?2 t4 I; {. G* }( b
- ' A5 I. W: u9 X+ D6 [3 s
- //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5
! @1 v- p; p2 L - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2: ?. w% d/ V, f f6 J( s; _
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
# I. w8 S" f4 A: V5 U+ H0 F - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;$ ~( L. D+ K. E; N( g( K4 b( q( ~9 c
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO" Y q# I0 B l& |5 e. J1 n+ ~
-
$ j9 b& ^$ _/ @. i5 _( N - //初始化TIM3
; y1 o' g% y" d# ^/ M - TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
3 h9 T, |/ ]9 { - TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 ' n/ @0 h6 W, [- ~* A- s/ m
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim3 G, A- B- a, |
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式, u! J8 y$ v- X2 L7 W* {0 t: i" O
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位5 r( @ j: n$ J2 w" A; n; a+ e/ E
- . d: P& P, O: s$ f {3 K) E8 C" d# O
- //初始化TIM3 Channel2 PWM模式
; v) Z3 V: F1 U3 t - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
' s7 t: T& P4 u& L! E5 n* k; Q - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能/ Y7 F9 H8 l" s: U! W3 x# ?
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
8 d R6 n" m3 u$ M' N' o - TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
" S a' u* h3 G6 }- Y" }% B) Z4 q M -
2 E# p' u# H. a - TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器/ c6 X9 X9 x0 h+ s2 ~5 N
- 1 ]" o" p* K. j6 S6 X/ f b# F
- TIM_Cmd(TIM3, ENABLE); //使能TIM3 - }6 P% v5 p# g2 Q6 g
- }
复制代码 ! m) D# Z0 V1 x* g
红外传感(VCC、GND、PD1)& a3 W& }3 V7 [0 z3 ` L3 d
- if(INFRARED_STATE()==0) //返回低电平,说明有障碍物0 n* K- i! k( V! b l! I
- {
/ }5 w/ b5 c" ?3 D2 L( q6 n& |) \ - BEEP=1;
1 d$ @- X' i. i- j% Z% u1 F' d5 F7 ^ - delay_ms(50);5 [' j2 [% N* }
- BEEP=0;
3 t. d+ e9 Q% f' O8 A - GPIO_ResetBits(GPIOB,GPIO_Pin_13);
4 k% q9 C/ n1 T4 \ - GPIO_ResetBits(GPIOB,GPIO_Pin_14);
8 W8 e. ~6 K) ~6 b - }
复制代码
6 l, I+ b8 @: J. V8 Y3 N蓝牙配置(3.3V、GND、PA9接RXD、PA10接TXD)- S+ a" m u; d
- void uart_init(u32 bound){2 R. J6 V y) `( u! R
- //GPIO端口设置7 _9 d' _5 q' v8 b
- GPIO_InitTypeDef GPIO_InitStructure;
7 Q$ ^( K. m! b - USART_InitTypeDef USART_InitStructure;
/ E" N5 ?0 x, k9 Z( ]7 L - NVIC_InitTypeDef NVIC_InitStructure;
1 N6 o1 C; Q. |) }- w' @) h6 f -
( w1 C8 }- b. T; J, C - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟2 l; m9 M9 L8 o' b' N
-
4 o k9 K- W7 r+ C' g - //USART1_TX GPIOA.9" j' Q3 m8 I$ _& Y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.91 l1 o; ?* ~" F7 C1 q; _
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
! D7 W4 a( S. @9 w - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出" p5 ^* R: S! w$ N+ B# l/ D
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
3 G+ t2 t2 \5 C h& [& A0 V2 F7 R -
4 M8 _. R8 r3 C1 b& c. L - //USART1_RX GPIOA.10初始化/ ]/ C% Z6 C2 P/ S2 ^8 ^
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10. \! g% @0 q9 T ]
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
+ _9 d ?0 Q: _" R - GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
; n3 a2 y3 T/ D& I4 Y6 [ - * C( P, s, B+ n: y$ k0 {1 G
- //Usart1 NVIC 配置
2 O9 [ B/ k8 m( n+ a2 ] - NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;& o' Y/ H6 N: m9 n6 T& v7 J
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级32 T3 z9 C# C1 O, g8 C
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
# d8 z8 m- s6 H& h8 g1 p - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
$ _) M! U- d M0 z7 L2 _0 P - NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器( w6 F8 X7 m$ l
-
4 [9 t; b4 Y3 }0 b& n3 F - //USART 初始化设置 c7 [3 D- n( `; l
-
+ z/ O! e0 v/ N O6 k$ V - USART_InitStructure.USART_BaudRate = bound;//串口波特率9 k0 k- ?* P0 o& T
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式9 c7 b4 o! m% A8 X' v
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
/ C0 f7 P9 j' ?' v - USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位& R9 `1 I, T0 ~1 M- ~5 G* B
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
% O( z1 i) v) S# k0 p0 J% t9 D% c7 n) Q3 D - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式8 g- z4 H9 k9 @" L4 G
- 7 x" K4 }; [4 v* g, ~, q1 f4 L: o8 S2 A
- USART_Init(USART1, &USART_InitStructure); //初始化串口1
; l# o5 ?* E1 P$ G: N/ ^! Z2 Y - USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
( p7 t& @2 @4 m1 J- W - USART_Cmd(USART1, ENABLE); //使能串口1
5 Y9 P0 k0 \. i9 h -
2 ^6 I; X. G# e8 B" K4 _ - }& o: w+ @* z/ D: |: R* z, h
- ) \* G; a, ?, r/ D& T, ~, _+ |
- void USART1_IRQHandler(void) //串口1中断服务程序
7 |" @/ k; @$ A) h, e, g0 X& \ - {1 t$ D3 t. \1 Y6 Z8 Q' n
- $ w# q, ]" ] [
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到数据
- G3 d D! W O k& z0 F" L - {
7 G, x- N% d+ v0 W0 L3 [ Y - uart_receive = USART_ReceiveData(USART1);' ]6 d8 h! W4 j/ k
- if(uart_receive == '3') //正转7 G, k: @, O1 a
- {1 d4 J9 r. n/ B4 c4 J% V6 _7 Q9 y
- GPIO_ResetBits(GPIOB,GPIO_Pin_13); / |1 X' Y: I2 V
- GPIO_SetBits(GPIOB,GPIO_Pin_14);
+ e5 {$ B. b1 c1 I5 l8 E" C# V - TIM_SetCompare2(TIM3,300); ; k# W( Z# j; }) F
- }
- W n* s0 u8 ~6 u6 \0 | -
+ o o& i4 j$ H7 B l! y - if(uart_receive == '1') //停
$ f. ]' }9 B: Y - {7 ~1 \, e4 X* Q( S) p: f# S* s3 N
- GPIO_ResetBits(GPIOB,GPIO_Pin_13); r" M- l6 M1 _, F$ k9 q! W7 v
- GPIO_ResetBits(GPIOB,GPIO_Pin_14);
" ~1 \4 g, Q4 l7 P7 E - }
9 E* }% I. Z: [5 b - else if(uart_receive == '2') //反转; e+ A( Y/ X! [% E% v5 o
- {+ j) U2 ~$ I$ k
- GPIO_SetBits(GPIOB,GPIO_Pin_13);
/ X% t3 K3 {0 {1 [ r4 p - GPIO_ResetBits(GPIOB,GPIO_Pin_14); 5 A" E. ~9 `! f) M, [9 C# P
- TIM_SetCompare2(TIM3,300);
: R0 f' Z7 N6 V+ y# m - } & @" J/ O- k7 [! U
- else if(uart_receive == '4') //睡眠风
5 p# K0 u% }5 Z8 d' I - {9 R4 h5 Y" d# C) m) `3 h- P
- TIM_SetCompare2(TIM3,400);
' i& s/ M9 y) E# ?+ z - } else if (uart_receive == '8') //强力风
4 o# i9 n. d# V! D9 A - {
& |, H! l+ f1 D3 G1 e - TIM_SetCompare2(TIM3,80);
( Q1 o' |. E# F+ Y( _( u - } ! A! s+ L' o {* z+ ^- o0 T
- }
5 f. R" E9 x" w" E8 ^' l - ( U- z. |6 Y. t6 I
- % n+ G& N( l8 ]4 I
- USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断待处理位
# n5 W3 [. \9 Z3 B2 A" _- K - }
复制代码
m: H9 v/ l9 B4 G3 q' m) ]7、实物测试6 G" _& k( A; @" [( F( @
* e9 e7 h1 k9 b5 t
% x. u% D! B+ p, i5 o9 t- | m" K8 J% `3 D9 C
5 H0 l' Y, V+ g3 E
S5 V, E; T5 p0 f+ l$ V$ \2 p9 J0 f; Y8 [ X
1 X; B$ h! Z9 M0 e) x+ Y' X, ~, m
8 ]) @: o; ^) ~! q E, e
& D# {& u$ O( q
————————————————! y3 a9 X: X9 q
版权声明:huy1n94 W3 I: n! A1 D+ R, D5 z
如有侵权请联系删除0 z9 S: K4 O, Q4 O" a# a
|