最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了
% ? h# F, s, @ v% S; f l( j" m所以拿出来分享给大家。
/ l2 _6 t( A2 v. k1 `1 Q r8 @7 u1 `( i1 C7 X7 u% Y: t: y
sht30外观
% w6 z. L1 q5 c6 L* ? V
: I; c# U/ ?) [& M0 \$ i1 M% e
8 _4 |; t* f5 ]# p5 w0 t: r8 N1 m4 z6 n! O5 E5 z0 b/ q: k) k
驱动不是自己写的, 是采用CSDN上的一位朋友的 ,这里贴出来的代码不是本文的主旨, 重要是教会大/ k, w) o; }- N5 d
) _5 W0 c- K& W
家如何配置各个端口(因为是模拟iic 所以大多数引脚都模拟为SCLK和DATA)。/ F4 t& O% Z# r: ~
/ ?. C, f! C! N1 X% M$ B" C" y- a
串口输出图7 F# o; p* A, s1 A1 `
% v/ k; n' X6 r# m9 z6 @. J
! _( r- f9 g! }9 M3 Q: Y, m& E: f
4 R) M& i3 b) t
# o F9 m3 `3 v0 t* f7 e8 e5 s驱动代码, l5 O+ ?8 v0 w! s" j
8 j+ S% v. ^1 S0 y. Q1 T2 b4 K
; V. ~* e7 C4 @$ V" `sht30.c
5 ?3 i* K- ~7 |- #include "SHT30.h" & A# k$ l0 c) ~7 ?1 H3 ~: Q
- 0 J8 _" m! _7 s! K( M
- #define write 0
, M# V/ y |* d4 d - #define read 14 c8 c0 b2 j! b2 w: s9 n
- ' k% r: I7 e, E$ s
- //IIC总线接口定义
( P/ u# C& }5 r - #define SCL PAout(5)
f/ {, R! e' D1 b0 }1 O4 Y - #define SDA_OUT PAout(6)
/ d1 i0 E' Y) L9 A9 ]& j- T - #define SDA_IN PAin(6)
2 D( F8 c# s4 X8 ?- c/ _ - #define IIC_INPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=8<<24;}
0 {" d, d0 P% I. N8 O7 g# W - #define IIC_OUTPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=3<<24;}
. [0 C$ v7 r2 P$ S3 ~ - 1 a B# t$ [2 C- q; e( t$ f
- % V* e4 H% T; x7 e- d9 X
- float humiture[4];/ O7 G( w+ i( C0 ~- O# _3 g/ r
- u8 humiture_buff1[20];5 |4 |) ~! \, z7 X
4 g% U+ f7 g5 ]6 O: l& i- void SHT30_Init(void)
) M7 q5 {8 W' l- k( Q D9 T - {; d0 p! J$ |; _' Y: P
- GPIO_InitTypeDef GPIO_InitStructure; @0 E# I Z0 p: n4 w* u
- //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟 3 ~/ b3 {! j( t
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
U: V) c2 B# |( ~0 A6 K - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;
$ z0 u8 H2 n4 |( W" L& l - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
' @. v' y! z) E+ A0 m. n9 D5 N2 Q - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
$ l5 f8 K- o8 y( i* R/ @! } - GPIO_Init(GPIOA, &GPIO_InitStructure);
& C$ q& n+ o8 o6 X( ^ B! T% |! Q - SCL=1;
0 {3 O( U' E5 Y- _' A - SDA_OUT=1;- S# g/ N) b9 V1 ^
- } 2 _, [& O% c0 |- S2 x/ {
- /*主机发送ACK*/6 K$ d! Q$ f! \* r+ x
- void IIC_ACK(void)
9 H1 r$ v: V _0 ?4 w+ o/ u. ~, f - {
- l( u }5 f* h, S: T- K - IIC_OUTPUT_MODE_SET();
/ R$ ^) a8 B# ?* K ], k% v3 Z% O - SCL=0;& A' Q' L; f+ M9 R4 ^ u r* s/ I+ r, ]
- delay_us(2);
4 c! X4 W/ }% ~0 @1 q) l- d - SDA_OUT=0;, ~* O0 j8 r8 s. [
- delay_us(2);
) o. H; R3 R7 T4 I1 u! H - SCL=1;
" p4 `/ R; M3 A. c9 g - delay_us(2); - x$ g1 G% ?4 v, U, M
- SCL=0; ) `% m% W* c3 F8 [
- delay_us(1); * \ P0 u' T# } l. }7 u7 _, Z
- }
, c" |. G: q" p% s6 `) n - /*主机不发送ACK*/* O7 [; g. b% i' H% N* V* Z0 _
- void IIC_NACK(void)
; `& B* d8 Z+ M( U3 q3 H1 z - {# U% }3 U! L9 k( u- q
- IIC_OUTPUT_MODE_SET();& d3 a/ {" R! ]/ M
- SCL=0; R+ w* |! d# T! V2 Z' x3 s
- delay_us(2);
9 l; x1 r- W% @0 r4 t) R/ l - SDA_OUT=1;8 e. b) ], y1 H/ N, v0 f2 y- |
- delay_us(2);
8 A' |8 P+ i* Y+ u7 O - SCL=1;3 Z5 ]4 ~1 D: h- f* U
- delay_us(2); " _7 g5 m E3 O5 l
- SCL=0; 3 u; n: m V, h5 }2 d% Q
- delay_us(1);
$ ~) q J0 _$ [# Z8 R/ a - }
- ~3 {3 M) A: I0 K - /*主机等待从机的ACK*/$ m3 L9 q6 i5 R1 O7 f0 u4 G
- u8 IIC_wait_ACK(void)" h7 T+ k/ k( P8 L0 S* \9 b$ o8 N
- {
W; @+ j u$ V+ F - u8 t = 200;! R, {/ w$ |9 R8 `# t: {
- IIC_OUTPUT_MODE_SET();
. J/ K# }+ i) j% k - SDA_OUT=1;//8位发送完后释放数据线,准备接收应答位 . u7 W) o9 y4 T, q, D+ n8 Y
- delay_us(1);, \$ s; n% b; E
- SCL=0;: @4 O! a3 H. r& B+ a
- delay_us(1); % ~. Y8 o& g( g4 h& b; t: c- L6 ?
- IIC_INPUT_MODE_SET();
7 e% |8 ~, t' l" s ~7 _0 k g - delay_us(1);
# B/ R: a! _3 O: _6 M2 A" t& ] - while(SDA_IN)//等待SHT30应答
9 X& z1 S; y* d1 Z3 p9 F - {
2 \- I8 `1 }9 C7 s% p, h; v - t--;
, Q7 e$ h, r( R; J5 Y - delay_us(1); ' N+ o5 A( A9 C" D, D) i
- if(t==0). f' h9 X* J& ]% Y' `% [# k# e) h
- {
+ _* }2 t9 n& O7 D9 _ - SCL=0;
6 W5 |. t3 \$ X3 P& W1 \+ | - return 1;6 X; G- o: C6 O9 l% h
- }9 _& s) X$ [. J/ X2 F1 I r: ^9 v
- delay_us(1); ' o9 i2 y; Z- |+ G- U" v8 v/ Z
- }1 p# q4 \$ \% j' e
- delay_us(1);
, r+ l1 y9 @! x' {) Q! e( F - SCL=1;) U# r$ C( \) y( k: s
- delay_us(1);8 L- c' W6 N' b9 v# d3 W' Y) l+ A
- SCL=0;
- q! O8 V/ x/ Y' { - delay_us(1); 1 V# X, m' Q; I" u
- return 0;
7 K: }6 K f3 ]* M5 l& O6 F' n) a! Z - }
& ]4 p5 M5 d7 N7 ^$ E" U- { - /*******************************************************************( U+ k3 i: }- Q
- 功能:启动I2C总线,即发送I2C起始条件. ) ]- U, S4 a0 U2 ^& a( t5 r# X
- ********************************************************************/
% G2 x8 k7 x' U - void IIC_Start(void)
& t" e% a/ J" X - {( M5 V* K$ @- z2 c+ w9 u2 H
- IIC_OUTPUT_MODE_SET();8 _- i3 v2 J7 ~* n3 a, ~
- SDA_OUT=1;
5 C+ B3 r W0 {- G - SCL=1;
2 F8 v! G" H. d% f( Z; P - delay_us(4);
" S7 a5 T, K" S! A+ @# i x - SDA_OUT=0;( ~, X ]3 M/ G
- delay_us(4);
, D% K# a, o" ~( M3 J - SCL=0;
/ r# N [' u6 ]$ Q3 k. v" l: k* n - }- w- z" u$ x! N8 g Q
-
, q* g+ U3 T' o7 p" [& m- b5 u - /*******************************************************************8 |% x+ O$ t- K$ z$ P$ e6 ]
- 功能:结束I2C总线,即发送I2C结束条件.
( G3 {' g# F8 h5 T+ {- ]* h" j - ********************************************************************/
% p0 t* l- f6 g! _ - void IIC_Stop(void)) j, d/ X6 ~0 q% N3 i
- {$ L8 I+ ^+ P9 ?$ [: r5 Z, e5 g
- IIC_OUTPUT_MODE_SET();
\$ d$ p& s9 A+ d, v W7 {4 b - SCL=0;- A0 j* h* Z2 J6 h% L$ o. Z8 \
- SDA_OUT=0;
3 K# k4 }9 M6 G9 `. z+ K) v0 r - delay_us(4);
. Q) ]3 ~/ I* e+ k9 N5 ~/ E# V - SCL=1;
3 R1 Q0 L' l5 {9 I6 A3 @ - delay_us(4);( Z, V+ H3 ^0 j% ]2 z3 J. N
- SDA_OUT=1;
: {/ G) g! A$ g5 o - delay_us(4);6 N5 n, O2 a& I. m% B
- }
" K& Z; n* a' _" o3 w5 D -
: U* y1 J! r8 i) ]3 h# ] - /*******************************************************************
, y2 ]9 ^7 S) u2 U# l% O - 字节数据发送函数
; f& J( B+ |2 I5 s8 j% `3 ?' Y - 函数原型: void SendByte(UCHAR c);- C( y8 H! d" z# i0 A
- 功能:将数据c发送出去,可以是地址,也可以是数据
- \. B* k- z6 H( M4 ~2 q$ Z- x" d - ********************************************************************/
3 U. ?5 P) O C7 u, | - void IIC_SendByte(u8 byte)# _# a9 K3 r1 }! J5 {$ d
- {4 g3 t) U7 g) r/ Y: s
- u8 BitCnt;
& X% Y. {: U+ L0 H4 v- a* k' ` - IIC_OUTPUT_MODE_SET();
1 k M. P Q7 Q* A. L. T; E: j - SCL=0;6 z0 c0 g/ w. {# i e$ q5 K" N, j
- for(BitCnt=0;BitCnt<8;BitCnt++)//要传送的数据长度为8位; k+ Q5 [; C) K9 |8 W+ b2 H8 c
- {
$ |# H; t0 Y' A0 {! s2 [ - if(byte&0x80) SDA_OUT=1;//判断发送位
( l5 q5 L/ {# ]3 b- U% B3 N - else SDA_OUT=0;
0 Z5 t8 C p7 G' r( Y - byte<<=1;
% g4 A5 [5 {$ L0 [) y. Q* Z - delay_us(2); ; Q; x# s ^* y$ t' G
- SCL=1;
) b% R5 \) i# U# D4 ]' i - delay_us(2);
9 m& P: p9 X( a - SCL=0;+ ?% B. s Z0 \* V
- delay_us(2);8 w Q( {) D: ]3 B
- }9 d4 i8 O- ?6 m
- }
3 I b9 V6 H% d0 H$ d" } - /*******************************************************************, Q+ G1 X$ H0 g' O2 {
- 字节数据接收函数
. h2 W: F) R) Z- k% q B, t - 函数原型: UCHAR RcvByte();) u- K8 f# }# B' v4 p; E
- 功能: 用来接收从器件传来的数据
) W% O3 E0 f9 }+ f0 D8 Z3 P - ********************************************************************/ / @4 ~! ?, g) ~: Z5 Q
- u8 IIC_RcvByte(void)
+ _ o7 G+ X4 j/ t* {( [ - {# y( l2 X* x+ v, |
- u8 retc;
4 Z- w$ _; k* d; e' K: t, x - u8 BitCnt;
( F7 _/ r( C y! f) Y b; B0 l, T - retc=0; & T0 a# O. p+ C# T" c
- IIC_INPUT_MODE_SET();//置数据线为输入方式
: u6 @: l8 b; Y9 u; ?0 T o - delay_us(1); 0 n5 c- }( |* R3 Y
- for(BitCnt=0;BitCnt<8;BitCnt++): Z9 x5 S& j* c! c
- {
# u- K/ E% A s - SCL=0;//置时钟线为低,准备接收数据位6 C4 E9 t; \6 c: C/ l7 a- }' w+ e
- delay_us(2); . a9 {* r* i' \5 U! }, a
- SCL=1;//置时钟线为高使数据线上数据有效
( \0 U2 j; D+ ? - retc=retc<<1;
- R# _$ ?6 ] D3 ?& O6 O4 M" c - if(SDA_IN) retc |=1;//读数据位,接收的数据位放入retc中
: Z8 |" h( N# p: ^, x$ Z! N. W) p& W a - delay_us(1);
/ B! H3 Y7 E& ]5 U) `) X* b - }
8 [5 V% i- \7 K - SCL=0;
" F; b8 p) f- E6 @ m g - return(retc);
; _4 S2 ?8 s2 i - }
5 {1 B& p0 J' A* ? - /*******************************************************************0 c0 q3 _ x0 e. f
- 温湿度获取函数
" m% W( b7 e0 T/ V6 ~5 E# s+ A' F3 ^ - 函数原型: SHT30_read_result(u8 addr);1 a/ l' f7 ]$ ]* T! j
- 功能: 用来接收从器件采集并合成温湿度
4 R5 W( Z6 x# y1 ~, v" J9 i8 I6 h& ^ - ********************************************************************/
5 `9 D% M: C+ E5 o8 t - void SHT30_read_result(u8 addr)* U3 G9 Z7 V2 v- `( G
- {
9 A2 y! ?! x* X& G8 P - u16 tem,hum;
$ V! H |# ~1 I - u16 buff[6];
! W8 i; H) z& X/ U! C7 D2 ~ - float Temperature=0;
) B& C6 @ d8 ?# Q( O - float Humidity=0;
* N6 n" w* g4 Y* e0 Y8 p -
% _: l* H! V% b$ ? - IIC_Start();6 W J- D; v1 {9 M I+ m& ?7 s
- IIC_SendByte(addr<<1 | write);//写7位I2C设备地址加0作为写取位,1为读取位
& T" f8 U! ~) l" ]# A, h - IIC_wait_ACK();
5 ]- I* K+ k; r" o( z - IIC_SendByte(0x2C);' ]& A# a& T, T q) W, S F
- IIC_wait_ACK();
% L6 `/ |. G B) L9 Z' E; ? - IIC_SendByte(0x06);
1 h6 |& h6 a7 j+ x - IIC_wait_ACK();# e9 K2 L; A! K' D
- IIC_Stop();
I' J' V$ b9 U: z4 R - delay_ms(50);* |6 j% Z8 n4 @" V0 s
- IIC_Start();' p T0 p2 W* O2 Z% Q- o. }' q
- IIC_SendByte(addr<<1 | read);//写7位I2C设备地址加0作为写取位,1为读取位
/ i7 C2 U% F, D - if(IIC_wait_ACK()==0)8 [- l6 @+ E9 @) _, B# X4 m
- {
l. q: L1 n& u! ?) N* z - buff[0]=IIC_RcvByte();; H: S! C* J5 u2 t( x
- IIC_ACK();# w. a: q4 w! M8 U1 C+ i
- buff[1]=IIC_RcvByte();
+ G" F$ r+ o D; D2 p( X+ ] - IIC_ACK();
t9 K) R% A: D' a. i - buff[2]=IIC_RcvByte();
( n; C7 A2 \3 Z/ a' @. D+ C - IIC_ACK();' ]/ k9 L- C6 \. L! F
- buff[3]=IIC_RcvByte();1 B. T: C3 i2 N9 V6 R1 s1 b5 G
- IIC_ACK();
" }. B) Y% @/ {5 N6 n2 a - buff[4]=IIC_RcvByte();
: ]9 z1 I1 B* x2 A7 q% o - IIC_ACK();8 d& C7 e7 W6 ~) m
- buff[5]=IIC_RcvByte();! p7 E# D: v" K% A0 l3 n
- IIC_NACK();
6 r, B+ K+ q5 O1 q) q9 _! U - IIC_Stop(); K% O& p1 Q$ R# I0 l4 j, j; p6 r9 T
- }
- n7 T' c7 ~: P! a - 4 @; y! b# r1 F8 P: T
- tem = ((buff[0]<<8) | buff[1]);//温度拼接
; D# @4 ?! R( {6 [ T. X - hum = ((buff[3]<<8) | buff[4]);//湿度拼接
; M4 J+ t5 L2 h# A3 Z6 A& v6 M" c8 y& M -
~& h" M# _& S, H( X - /*转换实际温度*/
7 L ?5 V" Z, B$ y+ y. X - Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)8 y; p+ G6 \! e0 w" q$ t. A
- Humidity= (100.0*(float)hum/65535.0);// RH = hum*100 / (2^16-1)0 F0 q0 `" y: v
-
% v" C3 y1 v: {" @2 [9 s3 f# v - if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据
9 [7 H' D) q* Q* M- d - {& `6 Y# |2 A1 _. J, n
- // humiture[0]=Temperature;) H4 y. w: Z# l0 @- n B, y
- // humiture[2]=Humidity;
5 |# u4 l7 j) k: o/ q - sprintf(humiture_buff1,"%6.2f*C %6.2f%%",Temperature,Humidity);//111.01*C 100.01%(保留2位小数)- L* K/ c, x- W
- }
, v; V7 G: ?' T1 t - printf("温湿度:%s\n",humiture_buff1);2 k& b$ q! ~9 S! N5 N: Q/ H
- hum=0;8 ?7 n7 v( ^, w$ @* ^3 Y* Y
- tem=0;
3 y7 k* k+ H! G - }; \0 W% X% s1 N- V' d v
- 6 S1 |! k2 t3 b8 T
复制代码
2 g; B S; z# d; H; j) f. O, G2 p4 K
sht30.h4 p+ {# G/ L( R. D
- #ifndef SHT30_H
; D/ ? K- _9 c6 y! y - #define SHT30_H
$ b8 `* @- w4 ~8 d) n8 H+ ]6 z5 |4 G; F - #include "delay.h"
; B! ~6 g( J0 h - #include "sys.h" F9 C& x/ s2 @$ u
- #include "stdio.h"* i3 o$ N7 X; k7 p7 u
- #include "usart.h"
2 f9 P4 C6 `0 g4 E% q9 @+ S - #include "string.h"5 r: }8 Q" [8 s$ h
-
0 b1 U' O, d( S/ f: T - extern u8 humiture_buff1[20];3 s( j8 O% @8 e3 j3 q8 I
- ( F5 n2 x- q+ x/ f* @: ~
- void SHT30_Init(void);2 k, V3 G- [1 _5 s
- void IIC_ACK(void);; M) Y* m0 K2 Y, k' N* S* T% X
- void IIC_NACK(void);
; A( O- Q `& ^% i- z: t - u8 IIC_wait_ACK(void);. B d4 Z2 E8 _1 h% Q* l
- void IIC_Start(void);- Q i) B! t7 M* b( [! d$ q8 h
- void IIC_Stop(void);3 S `) K5 e4 m% O% n6 Q
- void IIC_SendByte(u8 byte);
9 M7 ~9 o5 U0 N+ s# P/ g/ y( i - u8 IIC_RcvByte(void);0 D# M# r3 I" @; f! v
- void SHT30_read_result(u8 addr);
" v _" W5 V1 d4 d7 K* z - / i# U" a+ `6 n& U7 O9 _
- #endif
) C/ _: n* D W& P4 Y
$ b) Z8 _" H; b5 U. K4 \5 m: Z$ D
复制代码 : t+ B! m7 u! L, [' `- |% G* t% x7 k
( e" T. p) R) b! D$ e% _) p" T主函数(while循环可以写个测试的printf)
9 B9 m# K, p" K8 W& \8 z) l$ g- #include "delay.h"% N( y3 J1 \" l0 S
- #include "sys.h"
" m% f. V- ~0 ^. D4 G2 ? - #include "usart.h"# ~3 M7 G3 [! A: o
- #include "SHT30.h"0 @/ J/ U9 y3 l& r& C, v) k4 f
- 8 D, T+ z: z" H
- " O% F6 h& q$ d' m/ H9 q
- int main(void)* H+ D! u8 y' L0 X# x$ C# c
- { |# l8 q/ w! d: W1 F) g
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
- j! `2 c, O. K1 s1 `% o: y - delay_init(); //延时函数初始化 " ~- [" Z! U& X4 |, p
- uart_init(9600); //串口初始化为9600
( x# a7 s/ k5 H! j6 c - SHT30_Init();9 d3 l. b4 `- |# w
- while(1)
1 x4 [; _+ g. F5 f - {
" ~/ n: ^* ]/ N, ~3 N, D3 c - //printf("123456");4 @) b0 N0 V3 i% X5 _
- SHT30_read_result(0x44);5 s7 e. Z# V: D! t
- delay_ms(300); , ?" T& a" H3 I' W1 w4 ~
- 3 [9 ]; A8 y9 K9 y8 H1 s) a
- }9 o/ _) r% O6 r0 F2 l; @$ a& [
- }% E; o8 B# ~9 V3 f K& ?
复制代码 g) [; E" u2 D. S7 A
5 H. O4 ?: f b# v0 g6 s; e! F
代码实测能用 ,直接复制即可, 但是如果想改端口继续往下看。! r2 d! q% B2 p" T
, R6 [% y6 `7 O0 D6 L4 X% d
, m- ]. s& A2 b' _0 n3 f
* Y, a. y* ^; f7 f9 T/ E' p' B/ ~
% y* d9 {3 C( |上图红色框选的是换端口所有需要改变的地方 这里漏框了上面的几个宏定义, 上面几个也要改。4 [9 R' B3 Y% ?6 h8 i3 Z, f7 n
1 p1 W0 [6 t' c8 p [1 o
: i: L7 \, z3 `8 ]
6 Y( n% H$ P: B c, d& tGPIOA->CRL&=0XF0FFFFFF;理解为 清零了32位数据中的4位
! L. d! E" }5 D8 ]GPIOA->CRL|=8<<24;理解为置位了32位中的(24,25,26,27)的值
2 y* A5 o. v# h$ D3 _( ? b" M0 e7 _4 l3 _( e
: B1 o4 F8 U, j* }! ]3 A8 S3 q
; z% v2 _/ m2 t H7 N% V
5 q3 f5 R) S! y( J; c" }
9 [0 [5 o9 r" \4 t3 T# T
) T4 P: p( V v2 ?1 g4 ]% T' |6 a# p
/ U4 ?3 u# _/ x: j% n* m上面两副图来自stm32中文手册 ,意思很明了, 有两个寄存器用来配置io口模式,CRL配置GPIO0-7, CRH配置GPIO8-15,第三副图是教你具体怎么配置,按照手册就可以选择配置你想用的端口了。; @# ^! ]6 Q. ~' h' X
————————————————* w7 e6 T# _2 w3 a
版权声明:文某9
/ o/ g$ }7 ?/ t# [( G- d如有侵权请联系删除! n1 u _$ [/ t4 [1 N: B" t
+ x( g g4 ]- |5 O' P. i# w- \
9 J1 q% g2 j' H- {3 J" }7 G) M; ~. S' r+ m& R9 _
|