最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了. H% ]+ J4 b2 G% n# X
所以拿出来分享给大家。4 D! s' X1 h+ a. o
9 H( v6 \( ]0 \* J% w4 B$ gsht30外观* i( g" T& g7 w
' T. W8 i+ ~1 r, N
+ N- F0 M4 D- l. h3 l
8 {* ^/ W: w+ k a7 @
驱动不是自己写的, 是采用CSDN上的一位朋友的 ,这里贴出来的代码不是本文的主旨, 重要是教会大" p/ b/ W3 w, K( F2 k
' v3 f7 A M8 w" N! Q9 `家如何配置各个端口(因为是模拟iic 所以大多数引脚都模拟为SCLK和DATA)。
1 K- s; A. O0 o: J; K9 ~% u& G% o. V
|5 X9 a& e3 ~- M& `串口输出图' J% ?) u( T3 ], D/ l! l
' F$ F4 ?- y7 r8 E5 Q
4 _( V5 _: Z* ]" k
+ i9 \% [2 H$ K* B5 \
- W; f" l% N' T/ R0 s8 p5 x6 B驱动代码/ c. `; I! \+ Y8 @
' {' s- `" e# z- V- U0 w, r
) [1 r) i& v- V4 |3 h9 F+ Msht30.c4 T) M- k C* c8 s. Y
- #include "SHT30.h"
5 T3 B; {, }9 S, Q7 ?1 G+ [ - $ V! E( \3 C4 C9 W" i) Z# D
- #define write 0+ T2 m) s4 x; D7 k. T+ v0 Q
- #define read 1
3 @$ j. u! J$ y1 ^: |
4 d$ ?7 ^+ k/ Q3 u1 t' s$ m$ R% W- //IIC总线接口定义' ^( U+ }: @+ s1 k
- #define SCL PAout(5), i1 E* V; Q1 s/ `# x( z6 n: ^1 K( e
- #define SDA_OUT PAout(6)
2 c) W0 g. u& V) M - #define SDA_IN PAin(6)
9 f+ r8 r) o/ m' Y" \" O& H - #define IIC_INPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=8<<24;}
* q$ ?0 A# \/ ^/ t& q - #define IIC_OUTPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=3<<24;}! k' f! P7 v# D9 N
- ) I7 @8 g1 K* h5 N0 |8 m1 ^
- & T; p# J/ E/ I
- float humiture[4];
# E# V7 T- r! ~, u. m8 d) c) Y - u8 humiture_buff1[20];" p# z+ ` Z1 \% R$ X$ [
3 j1 q( @! |) m- void SHT30_Init(void)
/ j! ?- g% {9 w3 p# ~' {: S - {, J8 }0 R$ J$ _% T- l
- GPIO_InitTypeDef GPIO_InitStructure;5 F- l3 p' l% V: J+ ~! [6 H1 A
- //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟 + n9 O/ F8 a, O0 D) C& |5 n
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
$ U. I+ B, D+ u4 F% o8 E9 M - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;
/ |3 n# Q, f- O, I - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出- h+ }4 H& E3 M* ]8 ^
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;- z2 p: H4 `6 a) \6 k0 y
- GPIO_Init(GPIOA, &GPIO_InitStructure);
6 ~% r: j* Y2 H3 V - SCL=1;
/ R1 k+ h4 i4 ~% _' f0 R4 ] - SDA_OUT=1;: }. x" o$ S. K) F) ]# r6 U
- } * O* O3 h, p4 C( Y2 b2 @9 d5 Z
- /*主机发送ACK*/2 O5 q/ H2 q! i6 j: B3 ?( e) \
- void IIC_ACK(void)9 m# v" f' H! v. C- l
- {4 I; d1 F8 i1 S0 i9 l2 Q3 K8 ~
- IIC_OUTPUT_MODE_SET();
5 Z( t, z9 f) Z! o& \ - SCL=0;! C6 ?$ p1 C" W* p4 V
- delay_us(2);
" ]0 [1 g, i3 d, b* K L - SDA_OUT=0;! u$ _+ e& b' ?- d2 i, l8 b2 Y# S
- delay_us(2);
0 V' s: ^; o: |9 q& ] - SCL=1;
" S) @+ f, B: t4 t! c5 I0 b! d - delay_us(2); ' A' b' h( k' c# ~/ p8 g. p
- SCL=0; ^- S1 ~1 ~1 d6 f
- delay_us(1); 4 i% v: l0 N! B6 s
- }# U4 b/ h% b3 `
- /*主机不发送ACK*/8 h4 ?5 {; r2 ^4 C }; V* I
- void IIC_NACK(void)" {3 { \( p3 F9 a! T4 y; {9 ?# ^
- {
0 T/ a( O# Z; S - IIC_OUTPUT_MODE_SET();
o W) D' _( v' m. D% K - SCL=0;
, K; Q% ^; B$ U# s* t( t3 u' ?7 N - delay_us(2); 3 ]; {# P6 z! m0 q' {5 n
- SDA_OUT=1;" g" ]; d9 L; D& y4 o! z6 o8 c
- delay_us(2);
$ T4 G4 ~6 l, \# g( h - SCL=1;, e- |& f; S. `3 w8 P. p
- delay_us(2); $ \6 F& j4 w. Y3 U p5 H6 ~# Z
- SCL=0;
% D) W$ ~" o1 N- b- J0 P% R - delay_us(1); : ^: @& d# [' @6 [4 _
- } b+ m+ s8 l$ v- ?3 r
- /*主机等待从机的ACK*/
! o1 L" C( l. v# @2 j - u8 IIC_wait_ACK(void)0 d( P# p3 ?1 V. v
- {
' C6 u* d0 M( _4 }: l - u8 t = 200;
% `" ^8 u) D0 f$ u7 M8 K) w - IIC_OUTPUT_MODE_SET();
u9 T0 C u2 q- H3 } - SDA_OUT=1;//8位发送完后释放数据线,准备接收应答位 ' l& A: ^! v5 L( D! T# }2 l1 g
- delay_us(1);9 ^1 u$ H/ F/ m$ N) ^, |7 v8 m, x
- SCL=0;& i# Y0 ?; Y; B [3 C
- delay_us(1); & T8 u0 R6 M6 ~/ L! W Y
- IIC_INPUT_MODE_SET();# w# F( E/ k* Z T' Q1 s3 L
- delay_us(1);
4 s; S) y: Y* C+ w2 C - while(SDA_IN)//等待SHT30应答7 W9 G* E" ]" y: W8 B
- {
# O- O' @7 r8 A' F9 w( ^ - t--;
8 ^/ o% P- ?9 H# d) f5 m - delay_us(1); $ A* N( Z" x5 M5 i
- if(t==0)$ d6 S, r; N6 V7 u9 Y
- {$ u8 ?1 i# s a
- SCL=0;* N {0 u5 |+ L3 F9 m' x2 n
- return 1;$ |' h- {; o% d! B( E. Z @+ I
- }- N. F0 o# B0 x/ g" P# `
- delay_us(1); ) D9 e q! |; T* e- @1 D+ K# i
- }
4 }5 ^2 m: p9 v# U4 _) _ - delay_us(1); 7 q" ]9 y& a- H: M9 s9 {
- SCL=1;
3 e, s+ O. L4 t5 w - delay_us(1);: }7 g0 s5 q, |
- SCL=0;
7 Z) o2 s8 F; O4 C. e5 `" {7 D. y - delay_us(1);
$ F- z( S# q( e - return 0; / k" L9 k" r- q9 {* ]( a6 \6 f
- }( f/ A( ?6 x/ b8 z5 R/ Y6 }9 u
- /*******************************************************************+ z/ E9 K+ O; L0 i3 l, s
- 功能:启动I2C总线,即发送I2C起始条件. : a+ a% Q3 |3 V3 S
- ********************************************************************/
# Z: C/ ^) y& E7 X4 m - void IIC_Start(void)7 R4 g7 Q2 j% ?: a( K
- {
$ u" _& f6 H$ x0 E5 V6 _ - IIC_OUTPUT_MODE_SET();' x5 D: @, _0 a$ a, j q
- SDA_OUT=1;) |6 h2 s6 l7 h
- SCL=1;
4 s( \$ S' H4 @7 B; v* U - delay_us(4);
% u8 T( r& L% Z% ?9 Q/ I# J& k - SDA_OUT=0;
* ~6 _& Q) A- z5 Q6 X1 F - delay_us(4); : k) p2 F5 V* g
- SCL=0;
" S' a/ C5 L! \1 {+ ? - }
$ s# D7 b- ?0 i }' T - 2 V" | \/ _- G; b7 u- D, L7 W" ^) j8 {
- /*******************************************************************' g% p6 G- p! w: Z8 M8 o4 f
- 功能:结束I2C总线,即发送I2C结束条件. j9 h% |$ h8 y
- ********************************************************************/0 T% Q h" O# y- `, _
- void IIC_Stop(void)5 V. A0 p+ {" n4 E# }
- {4 {5 U3 h( }2 d
- IIC_OUTPUT_MODE_SET();
6 V- \+ l$ E5 |. L& |; R. Z1 @ - SCL=0;
/ `+ U9 x3 D$ R; T# I$ ]- M - SDA_OUT=0;
0 M% U- Y- ?. k - delay_us(4);
$ t. k/ C- v4 T, _4 K - SCL=1;9 M% o* ?" s, x+ M
- delay_us(4);3 y+ P* G& R# O9 P, [. P
- SDA_OUT=1;8 Y9 H3 c& A1 A# V
- delay_us(4);
) }6 x& t- @/ _1 I- \ - }
1 Q; p/ q: y# i1 Z - + I2 U5 I. M W! j# F3 s6 K
- /*******************************************************************
/ M5 |' h* s! _5 Z& K - 字节数据发送函数
o9 |7 u, Y+ r' o/ H2 r - 函数原型: void SendByte(UCHAR c);
/ U% R l3 \) D - 功能:将数据c发送出去,可以是地址,也可以是数据8 Z! H7 B8 @" u# w& r( Y
- ********************************************************************/( v+ j' P; {, t5 K% ~" E
- void IIC_SendByte(u8 byte)
2 O0 X6 l0 ], m0 U5 u c - {9 j+ X* v6 m1 S! `9 i& E( o
- u8 BitCnt;" S1 ^$ Z* \( q$ R: H9 F! j- @
- IIC_OUTPUT_MODE_SET();
, ~/ y1 C& o/ I7 m0 N - SCL=0;
1 n2 D, _" ]" y5 Q0 @9 x - for(BitCnt=0;BitCnt<8;BitCnt++)//要传送的数据长度为8位
, ? d/ z% _8 N- K' L" u6 \5 i - {8 b' g2 Q7 l3 j2 S
- if(byte&0x80) SDA_OUT=1;//判断发送位
+ _' `, ~; F1 k6 `3 u - else SDA_OUT=0;
& h' K ]3 h! X; \4 W/ `3 V - byte<<=1;
3 l9 t+ a4 c$ F: k: _. o% d - delay_us(2); - o5 \1 j! C5 z3 u- V) t! h) w9 D
- SCL=1;
) M6 U+ S8 D( e% @8 k7 o( U - delay_us(2);
' t4 x, ?) q& s1 o& c$ c - SCL=0;( U- g+ B- F- M) U) W" k6 G: I% ^
- delay_us(2);
9 ^; Q% a7 U/ ? - }$ N' s3 D/ l8 H; i
- }
7 R4 O u2 I6 W0 {- ^0 t6 P - /*******************************************************************
3 U( s& f5 d! y0 M. h - 字节数据接收函数
/ L/ d3 `+ S1 p4 E N* z - 函数原型: UCHAR RcvByte(); U8 G/ Z* }/ t0 i
- 功能: 用来接收从器件传来的数据 1 d4 @6 S3 j; c8 z/ R
- ********************************************************************/ 5 Z! A8 m! q9 {) A4 K
- u8 IIC_RcvByte(void)$ q, c. |; L1 R+ H; K
- {3 ]2 ^& r" W( ^
- u8 retc;
. l0 f' ]+ W# `. ?6 E- a - u8 BitCnt;. l+ H9 b4 P" q" c
- retc=0; * H4 L" X1 |# S/ X9 _
- IIC_INPUT_MODE_SET();//置数据线为输入方式) [( e+ i2 {) q8 ?- s
- delay_us(1); 8 O# v, k8 O I/ w; A" N# H s B
- for(BitCnt=0;BitCnt<8;BitCnt++), l2 t+ @9 ]! F, u( Q9 y
- {
" A' n0 V# V2 ? l - SCL=0;//置时钟线为低,准备接收数据位1 V: @( Z! N1 g3 H
- delay_us(2);
0 P* G1 p9 _5 c1 R9 s" a/ K - SCL=1;//置时钟线为高使数据线上数据有效
8 a0 |1 s( T3 m: M* J/ g - retc=retc<<1;
2 c" a# V$ J x# {& j - if(SDA_IN) retc |=1;//读数据位,接收的数据位放入retc中
8 ^/ j$ t3 `2 X - delay_us(1);$ |, S) Z0 Y$ |% D A j
- }/ R) U' r/ x% T( l& b+ w* t" D
- SCL=0; q/ v% x! i( g& i( L0 m" V
- return(retc);; {5 l2 j% z3 _4 S
- }+ R8 F2 Z9 _7 j" i' k( q
- /*******************************************************************/ j$ ]. F* e1 e* q/ Q+ l3 A
- 温湿度获取函数
1 G3 o+ x) t" ~" N - 函数原型: SHT30_read_result(u8 addr);
+ r% q: h: S# {# K( N - 功能: 用来接收从器件采集并合成温湿度6 z4 U7 c2 d1 k* ~' n; \
- ********************************************************************/ % L1 e/ q5 [, S9 Y# c3 B9 p2 n
- void SHT30_read_result(u8 addr)- a* Q( n/ W( x8 z
- {6 i- ?0 |- V+ y' N5 G) Z6 u* e1 ^9 o
- u16 tem,hum;
- K: Z+ @8 |( L2 N* s - u16 buff[6];
7 W: z! [& B* N - float Temperature=0;; F7 W$ y q* i4 c4 [
- float Humidity=0;4 k+ v2 K& ], u, }/ g
- ) J k/ ]# ^: W9 Q, l( `/ I+ ^% B+ K
- IIC_Start();1 s2 N- R5 C# ]: n' C0 i
- IIC_SendByte(addr<<1 | write);//写7位I2C设备地址加0作为写取位,1为读取位
0 t. O. i- X% X, z; M6 ?! T+ w0 i - IIC_wait_ACK();0 u* u+ u1 @( [2 W
- IIC_SendByte(0x2C);" c- C$ `$ b, w/ B" \
- IIC_wait_ACK();5 ^2 B, x7 [$ J7 t- {6 i3 J1 h& j( |
- IIC_SendByte(0x06);0 ^5 \- ^ e$ Z, }4 X
- IIC_wait_ACK();
& ^* |$ ^) }7 U3 y% y - IIC_Stop();
& b) N& u1 Z: ` - delay_ms(50);- J. I/ u+ W0 ]7 N5 T6 r0 V% `
- IIC_Start();
- M6 k) r; j0 v# u, f" j4 O, T - IIC_SendByte(addr<<1 | read);//写7位I2C设备地址加0作为写取位,1为读取位
: {' h! X9 J& ^3 H" [% U$ s - if(IIC_wait_ACK()==0)1 k( r" g0 [3 G' I: _2 V+ e( a
- {
F* j& Q0 K$ O; ]$ M - buff[0]=IIC_RcvByte();
" P& z9 P' p; t: V2 _ - IIC_ACK();
6 N2 M% r0 h) a$ G - buff[1]=IIC_RcvByte();: t; C4 t2 {6 {8 o* C. T
- IIC_ACK();: u* L1 M2 |2 q+ z# U. t# h
- buff[2]=IIC_RcvByte();% \' }- m7 R$ D% ]
- IIC_ACK();
' l# _, e# [: G' a m5 J W - buff[3]=IIC_RcvByte();
- a1 o* T2 W7 l) I$ { - IIC_ACK();2 `" |5 C; c0 w7 G9 D1 l
- buff[4]=IIC_RcvByte();: n$ L! E2 o4 y0 ?- U) ^
- IIC_ACK();
' c6 \* V' y% ?" p$ _, N% \# ^ - buff[5]=IIC_RcvByte();: X2 o* \2 u1 S( f; A. G
- IIC_NACK();
1 }. ~( j* ]9 Z# E$ N9 t - IIC_Stop();
" C6 h% z/ t; J4 s1 j0 M' o - }
) K# R* d6 _: F# U -
: U' Y6 A, ^( O - tem = ((buff[0]<<8) | buff[1]);//温度拼接
% S; I& T) o! g4 E - hum = ((buff[3]<<8) | buff[4]);//湿度拼接7 T" G/ G- [5 w; A3 p
-
, t' n/ ?! d: ^- G. Y - /*转换实际温度*/
/ z" T3 x+ r4 K% ^" S/ \9 c4 _0 j* y - Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)
, N5 ]% K2 e5 @5 x - Humidity= (100.0*(float)hum/65535.0);// RH = hum*100 / (2^16-1)* h. _. p. ~/ j/ U9 i
- ! G' _9 p5 D7 q' r: k M+ Q8 e
- if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据
- q5 t7 a. }6 Y - {* ?! d( m) \/ c* s! |) o. i- Z
- // humiture[0]=Temperature;6 K6 G( {' m8 y/ n# X
- // humiture[2]=Humidity;
! o' Y$ s, Z4 Z/ ^/ H - sprintf(humiture_buff1,"%6.2f*C %6.2f%%",Temperature,Humidity);//111.01*C 100.01%(保留2位小数)
8 O* H2 m1 z7 v" r - }
' ~5 } `2 E" P* m3 B+ @+ l - printf("温湿度:%s\n",humiture_buff1);
: Q- b! J( j! Y; [! c+ J/ s" z \ - hum=0;
/ w0 }$ ]+ d$ y- C - tem=0;" g( D! a4 e3 B5 `9 T1 r* ~0 |8 T
- }
- m. G+ v' z) p0 ^! P
m' s4 F4 u! a9 v- s# J! S* Q3 c1 u! p
复制代码
& ^( ]& k/ A$ ^ M
4 R9 Z+ o% }8 x+ t$ `sht30.h
% M8 r, \. l _7 }- #ifndef SHT30_H
+ T* V% _$ U1 x/ l* J - #define SHT30_H
% [8 R/ K- B u, } - #include "delay.h"; }( c* B; B7 b" F+ n7 H
- #include "sys.h"
; j/ e' o0 m, M; N: U - #include "stdio.h"
4 K! L% Z1 Z ?, Q9 ` Z0 R - #include "usart.h"
% x- d3 |6 ]% h0 V2 E - #include "string.h"
% M2 h5 m c! v% y6 U& U" I - ! q z: q3 O3 K, I, x
- extern u8 humiture_buff1[20];
5 P* W& r3 X+ f+ I/ G
: H5 Y0 j; U. U- void SHT30_Init(void);, {* g; u& j/ M& u1 D
- void IIC_ACK(void);0 R* B, D& I9 Y% `
- void IIC_NACK(void);, q0 M+ A) E& b3 g' D# P8 b s
- u8 IIC_wait_ACK(void);
6 V6 I2 o5 f" o2 l F* N5 b- l% U - void IIC_Start(void);
. L. M' F6 X; L+ u( q - void IIC_Stop(void);" w! u! p3 t9 w/ _' C
- void IIC_SendByte(u8 byte);* P- ^+ o9 s4 G+ z$ n
- u8 IIC_RcvByte(void);" ]8 S7 z( Q' n! W2 R9 X" {
- void SHT30_read_result(u8 addr);
+ m9 u$ a# e$ \6 l0 | -
9 m- c* F. ]) ` - #endif: @, I3 K1 `, M% k; C+ b
- 1 R4 L# [# M, `# q' i' h R
复制代码 8 X- x H; ]5 `+ {
2 Q, d& @* _# i' A; T9 f: o/ B
主函数(while循环可以写个测试的printf)8 a5 C! [' r& W
- #include "delay.h"
# i/ A, i; S9 |, E5 F - #include "sys.h"
' Y9 K5 R: C9 y# S/ ]2 O. v( ^ - #include "usart.h"' ^5 I" Z( r Q
- #include "SHT30.h"
0 s0 v* A/ P4 L$ S -
4 D1 B" i8 Z# H" Y! r* A. M: x - 8 D' c7 P3 o1 q# A* h! i1 d
- int main(void)3 `6 N, ?- R& E" T+ V6 G
- { 9 n; L! t2 X& B) U5 z! }) {
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2, _. a+ _2 `+ u: I1 @' m) {& Y
- delay_init(); //延时函数初始化
) k6 e) J, f: X+ G4 M2 }) I; h - uart_init(9600); //串口初始化为9600
5 V3 }7 F( M5 U) C - SHT30_Init();6 A7 Q0 f0 h( |, k# M
- while(1)$ Q3 ~# i8 O9 v! _" Z8 \
- {/ c1 q2 a" x6 X# P/ w
- //printf("123456");! L! R0 o/ F7 P+ R, M G
- SHT30_read_result(0x44);4 q# @( ?. @8 W' M# s. ]/ O& U
- delay_ms(300);
% T1 f8 U8 z, x# }# ?1 F -
% G/ f: p. g/ t- `- I - }
; C* z0 u, _& f0 q! N9 R! Q6 A! X - }
) p( p% U; D8 _+ x0 Q
复制代码
, u# X5 H4 k, w& v2 d5 ]6 y6 j' q" K2 i2 R( J
代码实测能用 ,直接复制即可, 但是如果想改端口继续往下看。9 @! T7 g- a& f! I( m
2 I! [8 N- _ z0 m
- J* U5 p+ o9 a2 S/ H4 y" W" @; Y1 Z; w0 L- R1 v7 B a
- j8 `+ ^8 K+ W, r
上图红色框选的是换端口所有需要改变的地方 这里漏框了上面的几个宏定义, 上面几个也要改。( e, F$ t$ |$ J9 r( @) ~
/ ]) J1 X& g, s
9 T$ p( Z0 o9 f0 Y: j3 x8 y
; \$ R* q5 C8 \3 p: h% [* a) t F# V
GPIOA->CRL&=0XF0FFFFFF;理解为 清零了32位数据中的4位7 `& @' }. }, v# m" W
GPIOA->CRL|=8<<24;理解为置位了32位中的(24,25,26,27)的值
+ B. B, Q( J& |' E \5 P
6 p$ P: D9 A1 ]& P' d
7 D+ N. |) B* `# @
- s' X) j A8 P, E
, p3 {1 [: O% n8 h
3 z6 E" n) K5 i
# Q. |7 D' W$ C7 Z6 P
; B7 J0 d, h4 M. `! {% D2 d* } p
上面两副图来自stm32中文手册 ,意思很明了, 有两个寄存器用来配置io口模式,CRL配置GPIO0-7, CRH配置GPIO8-15,第三副图是教你具体怎么配置,按照手册就可以选择配置你想用的端口了。5 u9 S# W, f% n$ s: D F* t
————————————————
3 Z8 R+ i P* M& y5 p版权声明:文某9
% X5 u& s m' ~/ `# n. g3 C k如有侵权请联系删除; o' Z+ `4 \" _( `- O
2 L* K7 w2 c4 p8 y% J K' ~; Y5 g; j" d
& ^6 N, k+ o; q% m( z- t) W% I3 H1 s6 A5 {& f9 E" a1 M- I# }
|