最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了$ h! g' S# [! _7 v
所以拿出来分享给大家。
6 D3 h7 P. F0 ~' p7 S$ \
( W1 M. u: y# A! P2 n% C6 p7 v( ~sht30外观* S8 y- P' @+ S% A' s1 b, W
3 G9 P) g8 U6 l, {+ v9 A/ K- @
! A) Z) a. x/ i4 U* W1 J. v
, a2 w: F+ d) U- T+ {/ R4 w$ d驱动不是自己写的, 是采用CSDN上的一位朋友的 ,这里贴出来的代码不是本文的主旨, 重要是教会大
- Y0 Y; S8 w) \7 _1 }& H6 u
% I! i- r) H( T: g; Y& l家如何配置各个端口(因为是模拟iic 所以大多数引脚都模拟为SCLK和DATA)。% Q/ u: `% x! \! _% ]" _
: W( x% Q% y8 P1 e% P/ T J3 w \. @串口输出图
1 a& @- r% e; T% c; A
0 X! J& K' ]" W. Q
) `' g `' Z6 K3 s1 A6 f, g7 b$ J( M# d/ e s
, x& M0 M0 w0 k5 d2 n1 J/ d8 S
驱动代码: v, D" m( @( R- x
5 N" l1 I: H) N5 o# Z6 l6 i
+ Z/ \ t& Q0 V5 V: Z
sht30.c
# S$ F$ B0 v9 y- e$ w( m- #include "SHT30.h"
$ g( }+ N( b! A' z - % h. O6 Z: u. x" R
- #define write 0, b- g! J/ G( C
- #define read 1# L9 A- c1 q3 l. `# S* F2 U
) _% w% u" ~ I/ e4 T# W) Y0 L- //IIC总线接口定义% i3 z& b1 ^" n) }5 r
- #define SCL PAout(5)- S9 w. e6 b+ F6 V. M* x7 N
- #define SDA_OUT PAout(6)
$ D; R- e0 A5 t- E - #define SDA_IN PAin(6)
6 ~3 [% O7 _% \: R: F6 f - #define IIC_INPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=8<<24;}6 j& j+ |6 t9 k/ \! t5 T
- #define IIC_OUTPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=3<<24;}
% F2 J4 D+ Q/ I7 ?! n, F
- o# M! K; J& i1 N7 W O-
1 }, U! ?( E+ ]0 V - float humiture[4];. H& B# w k* t: j
- u8 humiture_buff1[20];# N" J# X+ U( z& n
2 x2 B, H, K; ^/ D1 c/ \( u- void SHT30_Init(void)) m; C: W4 C0 G+ x
- {
+ H, {8 G! g) x3 [9 K5 \ - GPIO_InitTypeDef GPIO_InitStructure;# c) P J( L3 a7 O# M1 H: n
- //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟
% `1 E' S7 h; J+ u# A* q _ - RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
* J4 e# _6 b, V } - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;9 k5 E- r4 e2 E/ t$ R
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
( } B9 w3 @& ?3 m8 X4 t! S - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/ l& a# w$ ^- _ - GPIO_Init(GPIOA, &GPIO_InitStructure);$ P/ s3 ?+ q. v6 E% z
- SCL=1;( \' G/ ?% b1 W
- SDA_OUT=1;# r3 }; E$ a6 s" D+ g6 |. |
- }
! y* @+ O, O( v. X& l - /*主机发送ACK*/
( g* t2 \2 u& ~( `9 z2 r5 V7 V - void IIC_ACK(void)
! J2 _$ W) y' t- X5 @ - {6 A; l; p# ^0 k- k1 B
- IIC_OUTPUT_MODE_SET();
5 n" {* C* t9 } - SCL=0;" N" a* u" j/ n; _6 L4 ]( A! C2 A1 P
- delay_us(2); * H& C- z. M( H# b
- SDA_OUT=0;" u* P( i. M- P+ x
- delay_us(2);
9 |4 w$ b4 v3 v6 q( b - SCL=1;% k/ |3 C( G0 l1 A* c; l6 |1 }
- delay_us(2);
" @* [3 r* a9 c. v - SCL=0;
% T5 ]: R3 H& n6 P% b - delay_us(1);
4 c8 Q) m4 Z/ h' N5 [ - }
8 ?" w. d {; e. [9 j+ ?) l* U3 @ - /*主机不发送ACK*/
) B* F8 y4 t2 X$ r- a2 W/ J - void IIC_NACK(void)
+ [6 ~9 r3 x, d1 ^/ d& t5 p - {0 V6 Y: @3 L, o
- IIC_OUTPUT_MODE_SET();
$ j: T7 [2 m8 h& Y$ M1 {2 F7 D - SCL=0;
. } D$ z! O) U2 P) h - delay_us(2);
. n& `. h" e( N9 v - SDA_OUT=1;
% V# ^$ m+ g, B& ~3 [ - delay_us(2); 8 [5 [' p& i6 T
- SCL=1;2 [& E, s3 u7 [( J2 n
- delay_us(2); 4 D9 k( j X3 m% L3 j5 l
- SCL=0;
6 M8 P" ~, C; |& V4 e5 R - delay_us(1);
7 U7 E+ _) t( M6 d6 o5 a - }
. F, P' e' R; r4 B# N) P4 e( q - /*主机等待从机的ACK*/) \5 H$ Z7 s1 [9 C: y
- u8 IIC_wait_ACK(void)
7 g' _- a) r, ^0 l/ G - {
8 w* [5 Q( v6 I0 ?% K3 U - u8 t = 200;
; Q4 Z2 C- w8 S - IIC_OUTPUT_MODE_SET();# z, P6 k- V0 L, h% U
- SDA_OUT=1;//8位发送完后释放数据线,准备接收应答位 6 {$ [; h7 r3 }# r4 K* b
- delay_us(1);# L: A! O8 n; [7 g0 a! \
- SCL=0;7 |# t: z6 @/ S1 ?
- delay_us(1);
/ f2 @" a T! d: P - IIC_INPUT_MODE_SET();
8 y6 |7 w8 b8 y% a7 J/ e! K - delay_us(1); 4 d' |- f# X5 Y# B1 [+ j
- while(SDA_IN)//等待SHT30应答
1 R0 h+ y n Y7 | A4 w0 ^ - {" i% M9 d- Y9 R7 O% k. E% e6 S! u
- t--;
# x& m7 _# W( R# _* c - delay_us(1);
& G; ?% n& w" t2 Y - if(t==0)
t) G3 v* u& \# E - {
2 M- M+ s2 X0 d& h+ a& e" w - SCL=0;
7 b) `+ t$ T( e$ E, u - return 1;
4 H( T1 r: O; R6 d - }0 `0 R7 a; F7 S! p {* j& z7 y
- delay_us(1); + A3 p2 _/ v: x( _7 Q
- }5 Z6 I. C, }% V/ b3 E" G$ ^
- delay_us(1); - |: v) g' z8 @1 g" M: t
- SCL=1;( ?( k8 f/ N! ]' ]# l
- delay_us(1);/ E4 i3 e* s. p, P) ^
- SCL=0;
5 R9 P* e# K7 o4 C" S3 q - delay_us(1);
% Z) d6 E7 M! t, J$ W2 m; [! E3 a1 m - return 0; ! k4 p. @6 ^- v
- }) @2 @+ p0 ^) D' D s. O8 v9 c
- /*******************************************************************
; C6 W9 D0 x+ I' o1 ]% K4 Y - 功能:启动I2C总线,即发送I2C起始条件. / m. G2 f1 C' g+ h
- ********************************************************************/4 y2 f2 Q; U4 C- ~" w$ o
- void IIC_Start(void)1 z& {+ h2 I+ Y/ o G0 _6 Q
- {
" r& h5 r' ^# W' M' u- w `- a) n - IIC_OUTPUT_MODE_SET();
# b) a& E1 V: a+ |3 k1 a7 [7 S. ?+ V7 B - SDA_OUT=1;. \: u5 W& J5 V
- SCL=1;
9 T( y' A( m) `0 Z w6 c - delay_us(4);
- X) Q' a. g u8 ?' b - SDA_OUT=0;
: o& M# l0 y5 f4 u0 ]$ S+ L - delay_us(4); 5 d- Y0 H, h8 o0 C: L
- SCL=0;# U0 y2 @7 Y' A/ k9 y; f
- }
" x5 u3 d& g" A# h - 4 k# H; F9 Y" ]
- /*******************************************************************
J0 l- L0 b' l3 |" E - 功能:结束I2C总线,即发送I2C结束条件.
$ S1 b2 m) i: M$ V) E" y; w - ********************************************************************/
* S. {9 R6 c: Q# i7 G4 M/ I. l! @ - void IIC_Stop(void)
" i% _9 I- c, B* |# }" X, ^2 c - {/ G( ]5 X9 z* M& O; M% c2 i T! I/ i
- IIC_OUTPUT_MODE_SET();
2 q% f1 i) R/ n; @; z3 Y2 `2 h - SCL=0;
d3 \+ A8 O1 p) }8 x: O1 x - SDA_OUT=0;
/ e7 G: Y& y) Y/ m - delay_us(4);
- H: ?& _% ~, o, E2 ?( p - SCL=1;) l* t) }1 H8 a% ?- G1 w
- delay_us(4);
( J+ |5 m8 ?6 e5 H" n: \% t( x3 r - SDA_OUT=1;0 K. T2 {% U1 N* w% c
- delay_us(4);
# ~$ \8 x0 }7 y# [+ ^$ F - }
& f( C9 j8 }3 _0 y5 j - # N0 y' J& j6 ^1 E
- /*******************************************************************
7 m% Q$ f# e5 m7 R1 a( I' a - 字节数据发送函数
* `0 l m$ E2 {: W - 函数原型: void SendByte(UCHAR c);
. I# Z3 x' k D2 Z - 功能:将数据c发送出去,可以是地址,也可以是数据
2 y" J" h/ b0 @7 W: E" o# S - ********************************************************************/
5 H) o8 [& q. Z9 \" i - void IIC_SendByte(u8 byte)
; d6 A2 `- m8 M% D& ? - {+ j9 k) W' \: u3 M$ |; d: v- b+ y
- u8 BitCnt;
/ [4 V( a8 i- l' @+ z$ Q - IIC_OUTPUT_MODE_SET();
6 s: R1 k7 l" U! ^2 D# v) q" f* E - SCL=0;
' ?' D1 J% _, s* x. V% W - for(BitCnt=0;BitCnt<8;BitCnt++)//要传送的数据长度为8位
7 l. ^) S" e8 R0 O# T8 F i& b - {
, w4 ?) d+ `( d8 L - if(byte&0x80) SDA_OUT=1;//判断发送位
# B5 ^% e% M2 S2 D, i/ a - else SDA_OUT=0; + {' n& G, c3 Z- }
- byte<<=1;
/ P9 t! a# _" a1 I5 K - delay_us(2);
, E. v9 F1 V/ h8 X& E - SCL=1;
! w) `9 X& ~2 F( A. t% x' a - delay_us(2);. |0 x, [1 z; P0 m3 ^# p( Y* t' L
- SCL=0;
) E. C! H0 A: m - delay_us(2);) q% ?. H$ B+ b/ R8 j& i# o
- }1 P# `. D& A/ [* L8 ^$ ~, X
- }
. A4 ?4 D7 S2 _5 |" I' n" k - /*******************************************************************( X8 y: E; _0 ~% n" f6 E
- 字节数据接收函数 4 v9 Z' p* K3 @4 L* p
- 函数原型: UCHAR RcvByte();
" k/ G8 x3 r. M* I - 功能: 用来接收从器件传来的数据
- A7 ]7 ?1 h8 s# A3 ~7 b* G - ********************************************************************/ 4 m+ V5 y4 B! M c& T- r, y. S
- u8 IIC_RcvByte(void)
( W. ]" u; f( ?* R/ { - {, n" r4 Q' d$ C. R& h+ Q
- u8 retc;
2 @2 N K3 a0 n& w; E - u8 BitCnt;+ _2 q7 H: r8 \" H1 b0 [9 D H
- retc=0;
0 V7 d0 Y2 _7 s8 M - IIC_INPUT_MODE_SET();//置数据线为输入方式4 p( F3 ?: H0 u
- delay_us(1);
$ v- g4 M Q1 @3 ] }. E - for(BitCnt=0;BitCnt<8;BitCnt++)& L) {) p% N5 }
- {
8 _" B$ L; }( F% W8 A - SCL=0;//置时钟线为低,准备接收数据位
0 Y) B4 y, w$ p - delay_us(2); & A( y! A h" t+ i4 M; N5 a$ j
- SCL=1;//置时钟线为高使数据线上数据有效 & h$ z% X E3 n# j
- retc=retc<<1;& w2 i" g8 N, p( X
- if(SDA_IN) retc |=1;//读数据位,接收的数据位放入retc中 + d3 @& M1 f1 W* s* Z3 f
- delay_us(1); m$ f [2 x) ]3 D" q+ Q
- }
4 I# ?9 Q% a, U; E; H3 E - SCL=0; * M- A( H2 h5 f) w! g, p$ d7 e! t6 t$ p
- return(retc);
4 |$ V' D( G, q. M0 n - }
- V- Z/ }; B7 c$ \0 P) j& D! \# ~: O - /*******************************************************************; b8 d. O6 Q) t5 w5 M/ u
- 温湿度获取函数 ( k& z6 U0 { ]' o a6 E/ x2 J
- 函数原型: SHT30_read_result(u8 addr);' Z9 Z+ E7 ~/ A6 h+ ]
- 功能: 用来接收从器件采集并合成温湿度! e' t% M$ R1 s8 {
- ********************************************************************/ 3 A, p: U- U. E* b: N/ b
- void SHT30_read_result(u8 addr)" K! S2 e. }. U; ?$ x. p
- {
% I! w D" h. h5 k4 l' [ - u16 tem,hum;) \2 T- a* K# \3 Q1 I" i/ f+ n/ `
- u16 buff[6];7 e; w+ c8 Q" x/ S; F
- float Temperature=0;& ^, D0 C5 I( k
- float Humidity=0;2 j: q( X* Z; E& H, }
- * G; C. I7 H8 [9 r5 D
- IIC_Start();) Z J* R ~% N5 U! c1 h2 \) v, k
- IIC_SendByte(addr<<1 | write);//写7位I2C设备地址加0作为写取位,1为读取位
% J, D' F3 S# J1 i$ j! {$ u9 [ - IIC_wait_ACK();% F" E, k* S& @2 ]
- IIC_SendByte(0x2C);
* P* Q4 T4 H6 @ - IIC_wait_ACK();% f" w" z$ F% y) y
- IIC_SendByte(0x06);
4 G: T# x# A$ I! f9 W; h8 D - IIC_wait_ACK();! `3 Q* w% o, g/ V( G& ~
- IIC_Stop();2 J9 u4 R* O2 c; m% r& m7 H' k
- delay_ms(50);7 K4 Y, ~2 P5 V0 ~9 Z2 H; G
- IIC_Start();0 c5 @5 I" E' S; z& D9 K
- IIC_SendByte(addr<<1 | read);//写7位I2C设备地址加0作为写取位,1为读取位
& ^( j" M8 i& P, V/ K - if(IIC_wait_ACK()==0); \: }; ?" I7 F
- {
* `1 d$ Q* t2 k" Z n! q4 q - buff[0]=IIC_RcvByte();; I3 L- t8 N* Z0 F8 Z/ \5 K
- IIC_ACK();
' ]. Z1 Z1 h* }$ A - buff[1]=IIC_RcvByte();6 |: ^3 T) |" N5 [2 K/ o+ N4 |
- IIC_ACK();, V8 D- A; Z- c+ m3 t
- buff[2]=IIC_RcvByte();
# s1 A/ P. ^, O" P* ~ - IIC_ACK();; z& {- L2 { H
- buff[3]=IIC_RcvByte();
5 Z6 d$ l3 S' B6 v* j( w. v - IIC_ACK();+ p9 G& N3 ~( V( T2 F
- buff[4]=IIC_RcvByte();
8 E( w6 u7 S3 r4 v7 T, P0 z7 V& n - IIC_ACK();5 x) g9 y9 f# ]4 \0 {! n
- buff[5]=IIC_RcvByte();
; `0 y8 R5 l. A5 E0 q: q - IIC_NACK();
I/ E6 h' V( S3 [. V - IIC_Stop();5 `! q, Z/ S1 F9 g3 O. y! u* ~
- }+ Z0 q% Y" @1 f# @( r$ L
-
) T2 R' t+ b: z1 t& z t4 @ - tem = ((buff[0]<<8) | buff[1]);//温度拼接+ R6 p& m6 b' f% T: I1 v
- hum = ((buff[3]<<8) | buff[4]);//湿度拼接
9 p% ]% b2 K D* h - ' p7 p$ z+ N6 C
- /*转换实际温度*/
& a5 R# e6 l# t; S' O - Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)
! e9 q0 \' {5 a1 W - Humidity= (100.0*(float)hum/65535.0);// RH = hum*100 / (2^16-1)
5 R4 `( \* A: Q" q - ; ~" Q1 f6 |; t, L4 J
- if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据
% k4 m: {: h. l) O% F- X - {- J: F' v1 h( I" M. q
- // humiture[0]=Temperature;
0 b& _2 R$ B" q, |1 i2 v# n. v9 N9 { - // humiture[2]=Humidity;
' J) l% z$ ~: a- ?/ v& A - sprintf(humiture_buff1,"%6.2f*C %6.2f%%",Temperature,Humidity);//111.01*C 100.01%(保留2位小数)6 E# W8 G" z, U9 g2 |+ k( ?2 s2 N
- }
- B. r' b5 z& J: U: | - printf("温湿度:%s\n",humiture_buff1);7 E! B* f+ ^8 {+ a
- hum=0;6 ?& L/ C2 Q* R- I) f, }$ I1 ~6 P1 O
- tem=0;! o- x- J4 W& e9 l
- }4 k2 t7 \! X0 S4 a7 f
- ) [; J7 ]4 d. D& x
复制代码
2 ?2 e: B* e. I
: s# ~: E# h' @2 Ysht30.h
) P4 E( p- L* x7 P! U3 K9 s- #ifndef SHT30_H+ A3 [; i# g0 R M
- #define SHT30_H
! N( G6 B. |5 Y% n& i u; p% G - #include "delay.h"
e; e. f. c$ A6 o+ E - #include "sys.h"
2 y3 S1 M" T0 i2 o/ C8 Y6 p4 m - #include "stdio.h"/ o( Z+ j, z7 |# G1 G0 ^- b: m8 `
- #include "usart.h"6 f6 X/ j/ ]' \+ R5 x, w- R
- #include "string.h"& m( `3 b6 W* O1 N0 \
-
! G3 a' `, P, W' ~" l - extern u8 humiture_buff1[20];" R2 M- S; R" q* ^; V2 G
- 6 ?2 A* g- a$ @ n9 E [
- void SHT30_Init(void);; S& t; b# V% p0 o1 g2 q: n, ]
- void IIC_ACK(void);: i- e9 n3 }7 Y/ Z7 t/ G+ A5 g! M x
- void IIC_NACK(void);- J A1 I0 x7 r8 m5 ?3 }
- u8 IIC_wait_ACK(void);
$ r: M0 Q8 c# f- V% ~2 I( U+ p5 q - void IIC_Start(void);/ p5 U0 U1 _- s& T5 K2 ~4 Q# `! k
- void IIC_Stop(void);
0 L ?8 c+ i; E - void IIC_SendByte(u8 byte);* @: e" O0 e( \6 M1 q
- u8 IIC_RcvByte(void);
H* q M: y" q& h - void SHT30_read_result(u8 addr);
7 R1 y+ C' D$ u( C7 B- J! x -
- l2 F! [6 r" P& L% f# C* d - #endif
& R" {0 H3 k' z6 y. j5 q - 8 t4 f$ d; U" Q6 O0 Y
复制代码 $ ]' m W. X: T# c0 l
' Q l' j7 Q% g9 o
主函数(while循环可以写个测试的printf)
, z5 J5 w) h4 z9 U% \! U- #include "delay.h"
$ t% ], v! u- u& F - #include "sys.h"0 Y2 ~3 L5 V: [1 E5 x; D: ^
- #include "usart.h"
# [+ W( H1 D" j- P6 Y% E - #include "SHT30.h") z8 E2 ]6 O& z$ G5 e! B4 Y
- ; S- J, a' r: ?" A
% v0 y1 r2 N/ [/ i- int main(void)3 X9 {! O" `9 Q8 l4 b9 J5 w3 \
- {
5 I( C! g' _0 O y8 E - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2# I1 z, t% G" ^3 P8 T0 _* v' M
- delay_init(); //延时函数初始化
1 ]4 A, G( c% y# f7 X) I0 z# W2 u3 f, f - uart_init(9600); //串口初始化为9600
* @+ B2 J9 [- D) ^! F3 g _ - SHT30_Init();& m- C' Z% M; z$ g
- while(1)
7 n+ X, }* Y9 B0 C6 f; ~+ J - {$ L$ P9 p, a5 ]2 w
- //printf("123456");. e3 Y9 g7 [& m6 S; g0 \- E6 o
- SHT30_read_result(0x44);4 T) C% e% q6 \
- delay_ms(300);
: G. b6 }' J/ ?, ]) j6 m M, {5 @ - ( p3 X4 j# e" W& u' }
- }
6 t( I7 r) b1 s: j: M( H4 W - }9 g) y/ n7 F2 g7 ^% K! L9 F, u
复制代码
P( n, c, a) d- b# a
4 c6 ^. U. ]! X% h& b7 u1 }代码实测能用 ,直接复制即可, 但是如果想改端口继续往下看。* e0 j% z- j: s& r: Z6 j
- c; l1 q, Y& o3 X7 z) n6 \
8 i2 ?! K# |: q% [& k& \7 ]; k4 {. G
6 j; {! V3 _7 F# L C$ e9 k" ?上图红色框选的是换端口所有需要改变的地方 这里漏框了上面的几个宏定义, 上面几个也要改。
; ~3 T2 ?# p9 |$ R8 P; [/ O6 i) W
# N. ~+ j' ~. Z" d- @+ b( w; T' u
( a2 o1 y( `& Y
: z) b/ @' O5 {GPIOA->CRL&=0XF0FFFFFF;理解为 清零了32位数据中的4位
4 ]4 C% q1 @! B( b' f3 [GPIOA->CRL|=8<<24;理解为置位了32位中的(24,25,26,27)的值
8 ~& k4 F# m: i( N7 T* }" Z# F' D S9 l5 E# b( D
+ ?0 u, E6 D/ y9 M! A5 d6 k( ]
! p7 w- c+ e7 o8 [1 z2 }; V
0 }) }- M5 [( D7 k, [
0 ]( N( J1 T H
$ C, Z9 G) b3 Y" T. g2 M p/ n
: d/ m# U! P7 [0 [* K5 z C
上面两副图来自stm32中文手册 ,意思很明了, 有两个寄存器用来配置io口模式,CRL配置GPIO0-7, CRH配置GPIO8-15,第三副图是教你具体怎么配置,按照手册就可以选择配置你想用的端口了。
1 [( w( S% l' m2 K$ ]9 ?————————————————
6 E9 Y& v" \7 k+ ^, d' N; X版权声明:文某9
4 @8 ?0 s: o& L& P如有侵权请联系删除% O6 _$ W6 N9 p2 q; b8 g9 b
( E- m" d' ]: x$ J7 ?
4 |+ D8 O9 q/ P/ k. ~
3 ]! m% Z3 b' ?( Z |