一、课题
1 [/ J% g0 c! r) r- B/ I1、用 DHT11 温湿度传感器获取温湿度信息,显示到OLED屏上1 ]& M; E* q* }, p" D* x
2、用 MQ-135 空气质量传感器获取空气质量信息,显示到OLED屏上/ }7 W' o! D4 w4 R: Z
3、设计一个报警系统,可以设置温湿度与空气质量的上限,超过这个值蜂鸣器发出声响报警( |/ T" u9 K2 b+ |9 ~! H" l
; M P# o) K$ p0 L
二、准备材料
8 C# R v8 H, N4 q4 a(一)、主控芯片stm32f103c8t6核心板
O' _( P* H- Q
V- R) p" ^. s. d3 O" R- h( U* C$ V
(二)DHT11温湿度传感器
/ f. O1 E- K4 g1 D; X6 P8 n: p. a
6 K! }9 M7 F1 s6 o, \
# p# `0 _! \' x4 a(三)mq135空气质量传感器
: l$ `# L( x. Y( B2 J' k3 h# W3 \ J; T$ o2 F# l& t
6 _, i" [; Z& \ M* t
0 G# D4 c1 Z- [+ v9 j' i
(四)4针IIC OLED
9 u: f; y/ k0 {0 D/ W7 a% x) y4 v0 }' C l! j
. @2 p) G$ t3 G5 Y4 } _
8 x7 ?& J, b8 I5 e7 \三、原理图与PCB设计
2 ^( \ E9 Y# _0 S/ R# b8 J(一)原理图设计
# u; J# o" @9 Y# K* z- T- U8 q* w7 u& a7 ]
/ L9 m- A1 K2 E; [, D3 r- A2 A$ M7 K/ d* O
8 l; W8 S4 L* X* x
(二)PCB设计
l- I- @( F; a& i1 e
g' j! {. S" @
9 u; O( _! r& Z; X, d) z
; X5 r9 k& l( e/ t" ]四、程序设计3 p- d Q2 b5 ?; S; u
(一)DHT11驱动* E5 L% F3 m) {
DHT11.c: _7 R" @4 J; t5 V/ s7 t; s6 b7 |, u
1 A" [9 l) O. a2 D- w, G
- #include "DHT11.h"# U$ n6 z4 ^; ~( X- h" h/ i( ?
- #include "delay.h"
8 l8 |0 D. `4 c
0 @9 ?) V( i4 h
3 J5 T* }6 o! A2 C/ \
3 B* o. H! a k U- //???DHT11
3 i+ @1 K2 z1 R- l - //??:??????(????)1 K8 i: C+ o1 K' W- H
- u8 DHT11_Init()
y2 j N! f! t1 j# U% \# k, Y - {4 F+ x0 F7 N! Z, a1 q
- GPIO_InitTypeDef GPIO_InitStruce;& M- I2 k5 w$ u/ ^! z8 \+ I2 Y
- RCC_APB2PeriphClockCmd(DHT11_DQ_RCC,ENABLE); //????PA0
, S5 }- O; ~9 n; j5 u -
( j0 Z; V$ d" j! ]5 F, t - GPIO_InitStruce.GPIO_Pin = DHT11_DQ_PIN;2 R D; j% W+ n. t5 N8 Z
- GPIO_InitStruce.GPIO_Mode = GPIO_Mode_Out_PP;) U$ g# Z f- ` C k
- GPIO_InitStruce.GPIO_Speed = GPIO_Speed_50MHz;
. e' r/ v: p* y0 T, B: m% W - GPIO_Init(DHT11_DQ_PORT,&GPIO_InitStruce);9 m) V7 {9 k0 S2 x9 u- A5 w1 S- R
- ; K5 P E8 }% Z# B$ |
- DHT11_Rst();
$ x* r: v, S, a/ m) X - t9 E- G; A6 ], v$ \
- return DHT11_Check();5 }$ Z: }* r+ \! ~4 B, O+ R& Y
- } |& a4 l7 D' f4 M( Z" I8 c+ B
6 w9 H% A# c" k# d- 4 M9 D2 N, H9 k% b, U. X
- ( ~" K6 f+ j3 k& A
- 1 g/ ]5 a: U. p
- //??DHT118 E4 o% P( i1 [, V
- void DHT11_Rst(void) ) l4 ~6 ~6 E7 J, m r6 N% @' E; c w8 f
- {
: s$ b: F4 |5 a4 @ a2 e - DHT11_IO_OUT(); //SET OUTPUT. N! ?( l, |/ V8 i3 n8 h) ?
- DHT11_DQ_OUT=0; //??DQ* F$ s# v3 F) ?& d6 ^
- delay_ms(20); //????18ms$ K! n2 f' D) c: G! [. y6 ]+ a
- DHT11_DQ_OUT=1; //DQ=1
- _1 n" r4 k/ W9 m' B# y$ X - delay_us(30); //????20~40us
- X2 @1 {5 l- U( P# s3 V+ T5 c! ? - }6 ~0 E* d$ ?0 Z
2 b: }. v/ f+ e! }
: V0 j5 a. ~( y4 U" h! S
' ]4 ^3 `+ g' T$ z% l- //??DHT11???) N0 W- L8 N: B4 v# W9 w
- //??1:????DHT11???; j% t0 s5 H8 r+ G& f
- //??0:??$ M% |' O- S7 G- Z2 k
- u8 DHT11_Check(void) * y" X1 j- |8 i! H" E
- {
: `% y, `, C( R0 Z/ X - u8 retry=0;2 F& K" q- j, A: c$ i4 j
- DHT11_IO_IN();//SET INPUT
' F! \7 I0 ]* Y0 U2 a- z - while (DHT11_DQ_IN&&retry<100)//DHT11???40~80us5 q# }" `% o; O7 L* D" v4 B
- {
" r' d" ?" p5 Q+ _* `0 @ - retry++;
' }: e; t6 m. c* A2 j5 n - delay_us(1);
, C' N, s/ @/ ^( d- ] - };
: {* c8 w6 u- I1 D3 t: W* g7 V4 C - if(retry>=100)return 1;0 j y1 ^ K" n( t' |; x# o, M
- else retry=0;
; Q0 |" o; _0 @ - while (!DHT11_DQ_IN&&retry<100)//DHT11????????40~80us
4 G0 k D% f3 E - {
# h0 T5 k& {1 h7 | - retry++; # t( A+ e& X Y& m: w. n
- delay_us(1);
# d7 H. d1 w `6 w1 a - };
) p; r; u0 T, M2 Q9 s% a+ Z3 X - if(retry>=100)return 1;
# w6 _8 F$ X/ r* Y4 J/ m - return 0;
$ l$ {) }: }" e; H }. I) ? - }4 v! C7 d$ j* d8 \
- 0 }( z: \, |! l h5 p8 @
" o! B1 {1 _# Z) E# j- //?DHT11?????
( l' z1 e* o1 {) |# q - //???:1/09 K. S" x3 E; `
- u8 DHT11_Read_Bit(void) ; A, q# @2 B' i9 l. T' D; W- q
- {
6 N3 m! _% d% v2 h5 b+ }3 F - u8 retry=0;
1 _2 H) W2 K: \2 [ - while(DHT11_DQ_IN&&retry<100)//???????
$ |8 L/ _% F* I1 ] - {/ J1 T, _9 V( a9 b+ j u( n
- retry++;
' P, a' z6 L. E4 i! ?+ N3 z - delay_us(1);
4 L9 T" [9 [0 E" O+ E% w - }
6 u, |& F* H4 ?+ i" w% C7 b0 u/ ]( n0 ~ - retry=0;
7 R4 P+ C8 P5 @+ u J5 ]) |' E - while(!DHT11_DQ_IN&&retry<100)//??????
! m( v% I" o1 R+ L4 z8 T1 g - {3 c) @. \- ~3 \8 e. m
- retry++; $ ?# i- n& k a5 I
- delay_us(1);7 U0 v' w) F4 Q% R
- }
! ?3 S1 v' j, m3 C+ Y - delay_us(40);//??40us
+ P* Z- t8 H' x2 R - if(DHT11_DQ_IN): L% b- c! A9 |) _9 D8 k
- return 1;* J- ?% s; L* U& W z+ d
- else ( J! x, [, T2 y) W4 i* y
- return 0; 1 H! z: f" Y; o, h. w7 H% C
- }7 Y8 E+ U: H- l: G
3 ? ~: l7 ?. _0 s2 ?& s1 Q4 m- b$ {! W% {3 u
- K, X) I) c$ Q. H' d
- //?DHT11??????' a( n4 |/ w9 _& R
- //???:?????$ ~: i/ ]# Y0 v5 z" c& C( ?
- u8 DHT11_Read_Byte(void) ' J, \( Z P; @1 z* ~
- { 8 X6 v7 z' Q& q) \ k4 p/ Y( u S
- u8 i,dat;5 d; h- Q6 X, e8 [
- dat=0;
/ g% m6 P( b( o! F: D+ K: ^ z$ j4 {$ R - for (i=0;i<8;i++)
9 Z$ q/ Y2 Q0 |+ \9 k' f - {7 ^+ V& a& U# y, N2 d
- dat<<=1;
! _' b* V: B6 U7 a6 g - dat|=DHT11_Read_Bit();
- C% h8 V' M" l7 N* M - } - g4 g7 _+ e t; Y" D
- return dat;0 X. g; J4 j6 A. f2 b& Z' {0 k# ^
- }
" ]! G5 ~ ?" L5 a6 ?, W - ; q& ~ V- \% V
- 2 n( G* u4 M! ~# \8 S
- y! r* K7 z9 Z( J- //?DHT11??????1 E2 h; S. [2 ? E/ K: n
- //temp:???(??:0~50? humi:???(??:20%~90%); P$ Q9 V1 R$ t- E ?
- //???:0,??;1,????2 c8 C) ^; y4 ]9 B8 ]
- u8 DHT11_Read_Data(u8 *temp,u8 *humi) , V+ s' D) y- ~, r5 U
- {
" v5 K2 P+ ]! J3 }( Y - u8 buf[5];
3 n9 |" [( ]& k7 ~0 z - u8 i;
; E7 E& F2 m& H. _/ y - DHT11_Rst();3 j4 j& {% d3 U$ w* E- ~. a
- if(DHT11_Check()==0)1 e' s7 u/ d1 Q& e* K- F
- {. T. J/ x- @/ {& G1 ?, v2 i7 y5 W
- for(i=0;i<5;i++)//??40???
: q% f( L, s) w0 M, Q6 A - {
& a1 l6 a" F; C - buf<i>=DHT11_Read_Byte();
+ A" O2 m! U, B, p1 E - }5 i+ T( j, f, q, e( p9 T
- if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
5 w" P7 u: T' k! L - {4 S& m# u$ W2 C# @# D8 I4 M O
- *humi=buf[0];. ?) r- Q2 V% H0 W
- *temp=buf[2];
3 k5 n: V3 b. r+ j. F+ _ - }2 u. I" q' g: p1 B# |" h0 g! h
- }else return 1;2 n( x# s" A7 j: ?) K# G; P- F- e
- return 0;
4 L- S! |7 }; b j! H7 j. K7 J( G, f - }
' r9 N. a! l) O - </i>
复制代码
' b+ O- n. A$ O( H$ n: {DHT11.h
* l4 \2 l6 j, D" X0 |" ]5 X; g6 c" t$ E M, W R
- #ifndef __DHT11_H
9 R5 v0 L: o/ [. m - #define __DHT11_H 0 @* Q5 |3 s. I, b3 D
- #include "sys.h". i# M# a* u; U: n
7 p5 y a, n1 {( I# [# ?5 E4 C. j( R# b- #define DHT11_IO_IN() {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=8<<20;}
7 m+ }2 ^* u, ? - #define DHT11_IO_OUT() {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=3<<20;}% ]. h0 j; [' T F8 p( ]7 e
0 v7 @/ h- B+ s- F/ a- 3 e ?+ @+ L1 g- r
- #define DHT11_DQ_OUT PAout(5)
2 i$ T% T3 }; ], V5 ?" I0 j - #define DHT11_DQ_IN PAin(5) $ z j* v/ W) o5 P2 k+ c' U
- ! r6 J4 b H d& T. e, ]
- #define DHT11_DQ_RCC RCC_APB2Periph_GPIOA" o; A, X6 k5 H( v$ c. o
- #define DHT11_DQ_PIN GPIO_Pin_5
5 X$ _- M. Z! D' b' z - #define DHT11_DQ_PORT GPIOA8 @( K9 M( X9 T; V# R2 ?- c
- , q! V$ t5 t- |
- u8 DHT11_Init(void);
/ a- g+ S( F; G* O2 r% S! ] - u8 DHT11_Read_Data(u8 *temp,u8 *humi);. _. B# V7 j' w
- u8 DHT11_Read_Byte(void);" |# u+ N; |9 r# @ N" @- d
- u8 DHT11_Read_Bit(void);
" G1 Q8 U U9 D% u. i - void DHT11_Rst(void);
+ A* L3 w# ?+ p% f! Y - u8 DHT11_Check(void);
- n: G1 s2 o. D2 ~5 {0 s
) @* ~ H5 n) Y2 J: f2 L4 A# v- y( |7 y- #endif
复制代码 ' u4 ^7 u& d2 g" x* B) t
(二)MQ-135驱动,由于用的是ADC,直接上ADC代码1 C" j, M# p0 o1 }. ?) J* N- _
' R2 d& K* B8 F3 B3 K
- #include "adc.h", `- T( i! p" q. B
- #include "delay.h"3 i! Z1 U% j/ F0 A
-
: j" {. _" o" P4 ^ - //初始化ADC, d2 R3 i1 d" ?! q3 W
- //这里我们仅以规则通道为例) i0 r% F* V2 y/ S6 j8 Q3 B) z
- //我们默认将开启通道0~3
! y. o2 Z6 C7 Y( J - void Adc_Init(void)
, p# N: U: J* {6 X - { " }9 g* B v( _6 c0 e; C9 g! d- G7 [
- ADC_InitTypeDef ADC_InitStructure;
6 a2 V! w4 n% A4 a3 |) ?$ w - GPIO_InitTypeDef GPIO_InitStructure;8 O6 H; C; S2 W1 r4 I
- 0 p9 l2 ~, Z' F3 h+ d/ i3 F
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //使能ADC1通道时钟3 Z+ x" [% y& _" K( b
- % s" Q- F2 G" H
* Y/ D/ {' p0 X- RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M) }+ Y8 g- p. L% z6 U3 ?9 V: J8 L
- # M1 `% i/ P2 n5 z: U+ X, h
- //PA1 作为模拟通道输入引脚
9 M# D! J2 L/ \4 p% G( y - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
- u# ?" I5 s+ {1 V* N4 V) _ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 F. f# V9 R! n5 G
- GPIO_Init(GPIOA, &GPIO_InitStructure);
! k! B2 Q6 M1 y% ]0 J8 [8 r C - 4 w- [, m% ^! _+ V+ M
- ADC_DeInit(ADC1); //复位ADC1 ; c4 {& P- q. |( R* Q. y4 k
) p- p9 b6 M/ \. N% L: V- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
# u3 c5 X/ D- p+ z; } - ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式2 H7 T4 R7 J- E5 }; D/ [, z* D
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式0 i9 S8 b7 [$ K6 x
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
) m. j8 q$ @/ k3 U# h3 d - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
8 m) Q! u7 q$ P, {( ~& O- j# j- I& X - ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目8 i* T$ f7 b# ?2 h! b7 ?
- ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ( f" [' E: H1 U; j8 h6 U
- ) D) b/ L+ J5 O" W8 n
- % G5 C; v; s$ G% v/ T$ ]
- ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1- U/ p% s3 w+ }
- $ M/ r2 _: \' A
- ADC_ResetCalibration(ADC1); //使能复位校准
- u, z( I) Y5 C( `' a -
& F% d: V1 H" J9 N; Z+ D - while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
5 R" `1 Y! S, U/ z3 E+ g* _ -
4 t) Q3 k# w% d, H - ADC_StartCalibration(ADC1); //开启AD校准$ X0 Y5 b4 }' J9 c2 b7 V
' R+ U4 o7 P# ]! I* N5 \. E0 x- while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束8 c9 |+ ?2 s9 b# M$ ^$ C
* X. U; F+ M* t8 ^; v3 c- // ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
/ d# g$ e' |- n. `1 F) s
) L% L b2 b) ~, F0 Q- } ; \1 U$ ?; @- u8 w d
- //获得ADC值
0 N: w4 p% y, s - //ch:通道值 0~3- G5 B" _' ?. @& {
- u16 Get_Adc(u8 ch) / b; n( [& e0 A9 a5 P. O8 @
- {# x) I1 X: ?% @: i2 z* h
- //设置指定ADC的规则组通道,一个序列,采样时间
& E, _& ?2 h7 ^; ` t8 L - ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期
+ |; w& {! M4 g - " p% \, x: |+ H2 Z+ C' E
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
# d5 c" _4 x" v2 l6 Y -
$ k: b8 C8 C' {9 P* }- F9 N: M - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束0 b1 s( J6 b% h% [" h
0 p( E+ P. L) f% B- return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
( D. M( d9 m% \1 h* ~ - }. b/ q8 n1 D, K4 ?& ?$ T5 }; A
- % r% V) m) k, C- f
- u16 Get_Adc_Average(u8 ch,u8 times)9 w* f+ ~: O- ?5 @3 S# l" h, h* `7 n
- {9 [4 ^/ C, O: {% d b/ {
- u32 temp_val=0;
* F$ o- a& e/ a% Q0 U' C - u8 t;9 V8 ^- t$ E O$ `6 ?$ `
- for(t=0;t<times;t++)
3 U/ ]! i+ T& [ - {. n* S M: X. ?
- temp_val+=Get_Adc(ch);0 O0 R P! R9 \8 s8 [$ M6 s' |
- delay_ms(5);
- r7 m, a5 U$ ? Y" J" J- ? - }. T0 b' x5 Q5 ?! ~
- return temp_val/times;
0 y; c% |$ h- T& N9 ~) P - } * X/ \6 |8 u7 l5 C3 E/ i
复制代码 ! T( E- F( w+ i( ^0 n
(三)主程序
4 W# N5 E0 h3 `5 }" r% w0 `: H- \3 \' h- O4 i+ f K
main.c部分代码
7 X* _" D5 J1 }- I/ A1 K0 n
( j' t) l2 h0 R/ |1 O- int main(void)
! a- w9 p+ n- j, ^8 u - { " I. m: E8 ?2 D i
- u16 key;! d/ w" J* I; L2 t- u
- int adc,cnt=0;( D k; i& w3 x R6 R' \
- float volt;
4 U" b0 X$ |1 [* y4 A, t - delay_init();
# k: a9 U# N4 p: K' S( P, Z - NVIC_Configuration(); , U$ k |' M* Q, Z* U7 D F
- BEEP_Init();
3 z" O9 m+ m9 Y, m. Q5 H. p - OLED_Init(); # O5 i% t* c4 h& q1 e+ t
- OLED_Clear();
5 X, I* K" C3 | - uart_init(115200);2 K0 R5 O& W, K' h6 X
- printf("欢迎使用化作尘健康小工具\r\n");0 h) h* p4 o* S1 b+ {1 e
- KEY_Init();5 @. d5 V: M! g, U0 e8 ]( h" Y; O% ^# p6 ~
- LED_Init();
( O" v: |( O8 l' j7 V - TIM3_Int_Init(500-1,720-1);
5 P! E9 X1 o# X) p1 J$ L - " E4 m% l, p: B0 v' E
- DEV_Init();
+ Y) v6 ^& b" v8 Y3 a+ q5 u - 4 ^' J \' `% O2 D% T9 Z3 G. C
-
# h7 t- g/ L* {3 R - OLED_Clear();
M7 |2 S" Z9 v1 K) S - OLED_Dis_Menu();8 }6 t( e4 f$ L# S+ Z: U" M6 a& H, P7 V
- while(1) - |. Z# Y2 D' R( m# n8 ~8 g
- { 7 z+ m' E4 `& a/ t O
- if(cnt++ ==1000), E# _2 E+ P& I9 [% ]. i; H S/ O, m
- {
" c, a3 g4 N% n - cnt = 0;" }3 t: n# A+ _5 ^ s5 R
- LED0=!LED0;- a9 L- A+ g8 t5 _/ f
- adc = Get_Adc_Average(0,5);
/ U% \- C1 K" H: `& P - volt = adc*3.3/4096;3 @0 S- J7 v; U
- air = pow((3.4880*10*volt)/(5-volt),(1.0/0.3203));
2 W% v1 D' j2 b: s2 R. \/ H - printf("air :%d\r\n",air);
. d4 ~: } A* t; r - //获取温湿度 y: D( \/ d; O
- DHT11_Read_Data( &temp, &humi);6 `* Y4 t3 l" {7 \. }
- if(last_temp!=temp || last_humi!=humi)0 K- I1 l9 g2 _) a1 G3 `% R% I; X
- {
: z0 F, ]( P' [- C) X+ C) d# N" P2 S - OLED_Dis_DHT(temp,humi,air);
p. J! a" {: }3 U: ?" _ - }6 [/ ^. l" w7 x; A+ f/ e- X: u* B
- }
$ f' `/ ?5 ^" G' B7 F - key = Key_GetValue(); //按键扫描
& W5 w5 ^ B4 h6 |7 f - if(key)& |2 i9 j( S* a) B- |
- DealKeyVal(key);
3 M$ E# }0 z( G" y+ B' q - if(!KEY1_IO())( H9 ?& n* E" i- ~" m. Q
- {: T2 b% G O, G, g
- printf("%d\r\n",GetTime());
_$ c5 |5 A( } R' w4 j - }# f N7 s4 `5 @! |, y2 ^4 q5 b- C
- if(temp>Max_temp || humi>Max_humi || air>Max_air)/ a5 A! f1 ?* M7 e- @; h
- {3 f# O4 ^" b/ k
- if(cnt<500)BEEP=1;
1 z+ t6 \* U$ w7 k# Y/ a/ R/ l6 m - else if(cnt<1000)BEEP=0;
* N! |0 F, [+ u - }else BEEP=0;
4 O7 o0 |& x" T6 l1 w+ p2 h - 8 {# v" {& H- V; R$ w/ O
-
& s' i9 N+ Z( m9 h9 [0 ~ - delay_ms(1);
' m7 O8 b8 z' d9 B; p - } # j( H5 b2 y/ d
-
6 X. M; ~( k' R - }
复制代码
# J8 x! l l, @# J/ N# V$ g& `; P& Z. u& q6 n
! x1 z8 h d- J8 V1 T9 Q: |
: x$ l3 ]9 {, g
7 k! c/ y$ W7 @8 j- i2 ~( p |