最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了2 J2 S% {9 K# X' t: t
所以拿出来分享给大家。
1 r q( X' K5 y7 }8 `& t- O9 `) J" w w) m4 i6 \+ }
sht30外观
/ E# P6 z) [+ L) F! K5 E% q4 ~4 [ m* j4 i
) Z% f$ ]0 M @1 o6 V% [" |2 b# H$ l
4 j0 o1 ^" \; y1 z6 L1 k& {驱动不是自己写的, 是采用CSDN上的一位朋友的 ,这里贴出来的代码不是本文的主旨, 重要是教会大7 }3 S2 {: Y, L5 ^9 r( K- ?( p
1 d; Z- [5 I& U2 S; m! g4 n家如何配置各个端口(因为是模拟iic 所以大多数引脚都模拟为SCLK和DATA)。8 w3 Q- ~9 _( g- f
& L: c: U; A6 U% G
串口输出图& A1 [) I0 y+ s9 [/ Z
. u) `0 n, U% E* h1 c }: H
$ @# R; H& B) L! r6 r. s
- c6 Q3 n Q, u$ a, W! C& A6 t
( A; C0 Q& W2 J8 l! H$ z. I驱动代码
3 m) ?: c) k5 p0 p' l
; W3 t" U. v' V! |' |9 p e3 _7 B6 e S9 L8 P7 G
sht30.c
& }# u9 [, X1 Q% s4 p- #include "SHT30.h" % Y! g0 x4 U/ |& q( d! e
9 r4 k+ Q1 L5 [, X* g- #define write 0
" j* A" I1 S& Y; | - #define read 1: W9 q( ~. a# r" X
- 6 F) y7 `8 X% L
- //IIC总线接口定义( o5 x% _0 R4 e
- #define SCL PAout(5)! c: l- D( \ U9 X
- #define SDA_OUT PAout(6): P7 o. l& b& G& z+ O' e C
- #define SDA_IN PAin(6)
5 i3 I: d7 ^7 ?1 ~. ^3 N - #define IIC_INPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=8<<24;}
3 K- e! q- T, e; N - #define IIC_OUTPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=3<<24;}, _* X7 U+ c j% j) o5 Q3 K
. C# ]" s7 p9 d$ ]% w# Y2 Y: v0 f# \-
6 e! x+ n8 b9 r) r4 t9 r - float humiture[4];- ?0 N3 i! H: |& p- k
- u8 humiture_buff1[20];
! @! z8 p- g# V# Q# t/ |
* T) y/ T0 N' ~ I- void SHT30_Init(void)
0 V4 i# ]( t6 H$ a* x* p - {
- |* l6 v6 c. G/ ?3 V - GPIO_InitTypeDef GPIO_InitStructure;. m( a+ Z5 l# d/ r' D2 a
- //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟
6 E; ~2 p/ Z) j1 J0 G% z4 [$ L$ t - RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); 9 B3 p; G( V9 D9 Q
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;% @" F$ X$ U7 I+ Q7 Z: A" N
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出3 A+ {& r8 n i ~
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;1 ^% O& _; @/ [, {# X/ a& k; ^
- GPIO_Init(GPIOA, &GPIO_InitStructure);1 y j9 l8 |& u( D4 ~1 V/ w
- SCL=1;" ~* h: l: v& Z: e' o, q) B9 G
- SDA_OUT=1;
7 T$ e- _1 E; h - } ) ^+ q* U( J2 L/ s3 P, ~; }
- /*主机发送ACK*/$ E: ]* S4 b/ f# q# r
- void IIC_ACK(void)0 n% K/ [1 O4 x( U5 L" [8 Y
- {1 g4 ]8 e5 n8 D3 U/ @
- IIC_OUTPUT_MODE_SET();
0 L9 \- O6 i6 n7 d9 L" S4 V9 _, q - SCL=0;
5 y8 d% G+ w8 C2 r: _ - delay_us(2);
) S% O" _& t* D; Q, B9 S - SDA_OUT=0;! x1 W1 ?% f. y
- delay_us(2);
& ^( Y# W) ~( r5 p. l) }% a - SCL=1;2 K8 b5 f, ~2 h4 H0 o
- delay_us(2);
. q1 j4 K$ X( d - SCL=0;
- R1 e$ }& S/ a2 F, H' @ - delay_us(1);
$ T5 L, ^- D( L5 ~ G- v - }# T& k4 W* o- V# [2 C* }$ o2 l3 ^
- /*主机不发送ACK*/) }$ f" T: o8 R
- void IIC_NACK(void)
% A( _; n. m. R! b - {
! {7 T+ x# p+ S- w/ e - IIC_OUTPUT_MODE_SET();. F% }' T d& O* T1 A
- SCL=0;
/ ? a6 q: D. j. r - delay_us(2); 3 }" D. U% g0 N4 Y( m
- SDA_OUT=1;
3 J# \2 a# K3 F0 v r - delay_us(2);
( `- G9 j" B( H; {0 D7 e$ { - SCL=1;
4 u1 ~- g# L4 o* z0 N - delay_us(2);
1 i/ r7 o/ p# L - SCL=0; / L2 E, y9 U s q4 B+ }7 x/ |# b: E
- delay_us(1); 6 W$ H+ w+ [ w! @: ^( u# M
- }+ e7 D9 z3 H( O5 @
- /*主机等待从机的ACK*/
- \* q1 `; {& ^5 F - u8 IIC_wait_ACK(void)( t8 L5 z( n9 \8 |" S) }
- {0 B+ k" n1 W" j2 d! [) s2 b" P0 F
- u8 t = 200;
* a* f0 U8 t% C- u5 i( T. i - IIC_OUTPUT_MODE_SET();" \: O/ C7 d5 {, P
- SDA_OUT=1;//8位发送完后释放数据线,准备接收应答位 1 c8 N' F7 L" O9 \' x
- delay_us(1);' |# F/ n p, {! J5 C7 R
- SCL=0;: m2 ^* m. ?# T1 e, I% U* V% M
- delay_us(1);
# w T5 u( F* b; B# w" ?7 z - IIC_INPUT_MODE_SET();- i% y* y ] p$ ~2 |6 B( M5 O' a
- delay_us(1);
# w9 |0 r r& _1 G - while(SDA_IN)//等待SHT30应答
0 I1 ~4 y. X9 I" }. Q# S - {. l# Y! ]9 q2 X1 n" F1 Y. |5 O; i
- t--;+ C- k3 v1 n! ~ w# H) d0 u- n9 _
- delay_us(1); 3 o& C; I, ^" x' F
- if(t==0)
3 [+ z( L& _. Y5 G1 K9 t - {
8 a6 F+ y7 g/ D: F2 R - SCL=0;
+ p+ Y0 O' p5 d- ^ k- K - return 1;
3 U. q3 d" q+ Z1 E$ [. I - }' t. a" R2 C9 y* U( b% ?
- delay_us(1); b$ t5 K- w# g7 g q; F) v
- }1 t/ O5 K. z/ Z7 C! Y t
- delay_us(1);
: N9 H" i# T( w* R - SCL=1;
~2 @5 l, K+ ~2 q2 w4 S - delay_us(1);
! b$ Z: I9 p. C: o( |* N3 X2 Y1 R Z - SCL=0;
5 H; v5 x( e% Y' q C - delay_us(1);
# L6 ?5 X; `9 e7 V1 ~ - return 0; . Z3 w0 b& p, d8 |0 u; v
- }* b% L0 @. e4 o" c1 n
- /*******************************************************************5 g! J+ C8 d4 G- v8 ]3 ?" d6 c
- 功能:启动I2C总线,即发送I2C起始条件. ' l. e( _* r9 s4 A) ] Q
- ********************************************************************/: s" h8 y3 h: o) @6 s: ^% P
- void IIC_Start(void)
. ?; u9 s: o/ w* o/ ~ - {
% j: U8 n$ ?' D2 I, m! e3 ^ \. C - IIC_OUTPUT_MODE_SET();
$ X+ }6 t( |9 v4 y; Q - SDA_OUT=1;( S3 C# U F8 G5 u: i
- SCL=1;
2 I# l9 I5 r% h$ v - delay_us(4);
% g* M. ^5 c( j6 z$ Z - SDA_OUT=0;0 p$ S' ^5 ~: E( l
- delay_us(4);
' _; U# b8 ]* q# U4 l% f - SCL=0;
. F5 t3 r3 ?+ ~( f( X - }* B0 D9 [! {, f
-
+ s H7 F( m) D5 B5 G( o - /*******************************************************************
0 @) h0 l9 `* ]& r% d1 M+ Q* ^' n - 功能:结束I2C总线,即发送I2C结束条件. # Q" s2 T9 ^2 Y5 S
- ********************************************************************/
0 l$ D' z" B! U" d2 F2 s2 d' |2 Q - void IIC_Stop(void)! N6 B H* M$ T! x2 Q
- {
; t. i& y$ I- }7 t5 y- g - IIC_OUTPUT_MODE_SET();
4 b) C! s g: b, ~ - SCL=0;
# G2 G- u; ~$ r" G2 t! u, V - SDA_OUT=0; 0 g4 \% V; z) }
- delay_us(4); ) m# d& a9 T( F* S
- SCL=1;
0 ^8 b' m& T# g5 S, \' V" R' V% x - delay_us(4);
/ r+ a6 y! J, { n* E. j - SDA_OUT=1;1 z8 Y; @) P. y
- delay_us(4);
0 I# M9 P* ]' F8 G. d0 Z - }
% O& b9 Q- K& v; O2 O - 0 S' c- Y* |* ~. ` v9 y
- /*******************************************************************$ }* v9 x9 ~: p+ h
- 字节数据发送函数 * T/ H: M$ K, O7 @- p6 U7 O- J
- 函数原型: void SendByte(UCHAR c);
; X/ T9 m: q" A/ y5 [9 w - 功能:将数据c发送出去,可以是地址,也可以是数据
# j* \. ]7 m) y5 t: S - ********************************************************************/
; I8 w9 @! p) k5 \& g2 v1 Z - void IIC_SendByte(u8 byte)
2 E8 k* f3 H" ^; q6 V9 f - { d2 ^; k f+ @: F: G, N
- u8 BitCnt;2 X* z1 @& c2 w7 P, X
- IIC_OUTPUT_MODE_SET();, I+ y- G6 y O4 L+ |
- SCL=0;% |3 @+ j$ F7 k- c5 o9 h* c
- for(BitCnt=0;BitCnt<8;BitCnt++)//要传送的数据长度为8位
* S# l7 @5 V; _( j8 ~1 J/ r - {# s5 C$ ]2 V+ G- c+ M7 u- Z' D
- if(byte&0x80) SDA_OUT=1;//判断发送位
" s% D; `/ f: l - else SDA_OUT=0;
6 ^+ r$ l, T8 i* [* J8 r, C - byte<<=1;
; l: c% j. _& s4 H9 p7 r/ C - delay_us(2); % y+ {+ {! s# H# I
- SCL=1;8 D! \* |: W% U- f
- delay_us(2);3 b* f+ c" \& H6 w2 Y0 p) u$ n
- SCL=0;: }5 R% F! r, [0 E
- delay_us(2);
) K& ^) x% W( Z - }
& [$ A7 x. u T! H& ~( t8 X - }/ Y% ~8 L. A `2 }" I2 i0 P/ e
- /*******************************************************************- o6 q2 l$ e& T# u9 `- p+ f7 Q, G2 Z
- 字节数据接收函数
[0 e. S: p! p" W3 ? - 函数原型: UCHAR RcvByte();
- i7 P8 M* z, N8 e$ _ - 功能: 用来接收从器件传来的数据
8 J2 e. n2 @2 C% e - ********************************************************************/
: l1 y/ b1 {. @, i! ^1 C- e0 p - u8 IIC_RcvByte(void)" m, ^, _ ] o& c
- {
' A, d: r7 w p6 q2 i# O5 T1 D( F9 } - u8 retc;* G( c8 B7 y, d8 J0 G
- u8 BitCnt;8 B% V. Q# D2 k! v5 \6 J
- retc=0;
3 J9 \9 A! a% X8 b- m, q* p - IIC_INPUT_MODE_SET();//置数据线为输入方式- D$ M5 R2 q1 A) \( Z& g
- delay_us(1);
/ b4 \& n2 s8 s7 e1 m - for(BitCnt=0;BitCnt<8;BitCnt++)
# ]1 D* P7 ^' f4 S" x' u - {
4 L3 T$ x: f# t6 `1 {9 d7 t/ f - SCL=0;//置时钟线为低,准备接收数据位
' l( _- \$ {1 N8 G3 } - delay_us(2); 6 B" s. Y2 W# A
- SCL=1;//置时钟线为高使数据线上数据有效
2 t! @( C" H& }4 v" f- F - retc=retc<<1;
+ `& k% K$ f# L; m2 P7 i3 O6 e - if(SDA_IN) retc |=1;//读数据位,接收的数据位放入retc中 - T. y" y2 a. r7 x; T
- delay_us(1);
4 `3 ^! q- x2 Y- E. ~+ ? - }
9 E; `' L7 C/ r5 Y+ M3 b - SCL=0;
$ _9 l/ ^6 q; m1 H - return(retc);
, u! g- m+ g y - }
* F1 ?2 J+ \1 }) @+ g* \ - /*******************************************************************- k+ |. R3 F0 ~4 C" i, Q
- 温湿度获取函数 3 u* G, t% Z2 a" m3 N
- 函数原型: SHT30_read_result(u8 addr);) w. g d8 n2 T; @! p9 C' U
- 功能: 用来接收从器件采集并合成温湿度
% q* k9 V% \- y+ a6 K, ~ - ********************************************************************/ : W: d5 n- M% |& G+ s! `
- void SHT30_read_result(u8 addr)
7 w" ^" _( g4 O8 X4 r; V r - {
& n. {' F8 X2 J6 }8 p9 w) t - u16 tem,hum;
7 ^: E! |' R, o. h - u16 buff[6];. V, K" W5 b# u+ {
- float Temperature=0;4 f2 E5 T5 c5 z, L
- float Humidity=0;. w# _5 Y! c/ l$ ?
-
2 H% e% L8 H6 B2 D' A( r( S - IIC_Start();* t9 [( a7 ?. x( K- S! ?6 w/ ?
- IIC_SendByte(addr<<1 | write);//写7位I2C设备地址加0作为写取位,1为读取位6 z0 ]' x* o& r# Q( o: @
- IIC_wait_ACK();* `! d$ T& i* O# I7 N, Z( N
- IIC_SendByte(0x2C);0 q, S9 F/ n" b- G: y
- IIC_wait_ACK();
& H" I n# k# ^% k: `8 a+ |, _ - IIC_SendByte(0x06);
+ [4 Z1 W/ ]+ E& x7 w$ \9 _ - IIC_wait_ACK();3 B! l' B1 y$ o. I: ?& K0 [
- IIC_Stop();
$ c4 Q3 l2 ~- w+ Z6 e - delay_ms(50);' c5 c, T+ `. }. }: f% W+ |
- IIC_Start();% ~! y3 A4 }: b) l
- IIC_SendByte(addr<<1 | read);//写7位I2C设备地址加0作为写取位,1为读取位
% ~7 i2 A* z! A) O3 p - if(IIC_wait_ACK()==0)
/ @5 o/ t- s7 D6 }9 o - {
" { s+ G) g, } - buff[0]=IIC_RcvByte();) f. d9 n2 X9 Y! O
- IIC_ACK();
( r" a/ X) j# i$ ? - buff[1]=IIC_RcvByte();
/ ^. M- n% q) a- i - IIC_ACK(); K3 e/ z- t! T$ m( Z" L- N
- buff[2]=IIC_RcvByte();" I3 o" m, G6 N) n$ a+ ^! T
- IIC_ACK();
7 B- U: R2 V. L" M" w( n! p% J9 j - buff[3]=IIC_RcvByte();
6 [+ x" H* E7 H2 U! T: y1 y - IIC_ACK();
0 x2 J9 ~, [* _9 M/ d) [5 a - buff[4]=IIC_RcvByte();
0 U; @) l; M- [" ? - IIC_ACK();9 a, s% s& O$ w3 h- v! T1 Q0 ?
- buff[5]=IIC_RcvByte();; {* l- |, N3 s7 m7 ?
- IIC_NACK();5 K5 B% X |: a2 ~
- IIC_Stop();. _1 o) X* H+ s3 Q! q1 ~' W
- }- T$ y5 K7 B o7 t0 c
-
1 B- P& ?+ G8 B x - tem = ((buff[0]<<8) | buff[1]);//温度拼接* ^/ f2 b* G9 Z4 s
- hum = ((buff[3]<<8) | buff[4]);//湿度拼接
7 l2 n1 [* z* Q X! ^0 i - - s* O, C Z+ K
- /*转换实际温度*/
, @( j& ^" R7 q - Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1); `3 n. s! |8 t# o
- Humidity= (100.0*(float)hum/65535.0);// RH = hum*100 / (2^16-1)
8 h: ]$ I' I3 [- o4 {6 K - ) p# U$ W& c A/ n* M/ C5 H
- if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据& Z0 J3 i% I, B6 {: m: Z a
- {
* S' ?/ G3 `6 A% I3 t - // humiture[0]=Temperature;& b( |! O0 V$ j3 r4 w- k
- // humiture[2]=Humidity;8 x7 G1 G/ w2 j( v2 S
- sprintf(humiture_buff1,"%6.2f*C %6.2f%%",Temperature,Humidity);//111.01*C 100.01%(保留2位小数)6 \2 g9 c& B: U3 F3 p
- }3 z0 v5 q/ o7 m0 u. l) j
- printf("温湿度:%s\n",humiture_buff1);
- G9 Z! y% N* o: ~6 j - hum=0;3 w2 W& O% \% a3 g. s! d0 D# @( h
- tem=0;
2 F' p h3 ?0 b/ Z, ^1 J. r - }: I; d3 H" g5 @. _( Q: ?$ Q
- & h8 j! V6 {- v1 u' }# S) B
复制代码
! z- m* Q0 i s, Q$ t; V0 [( Y! i. _" }' B( E9 r' R
sht30.h
& k4 E- j2 v6 _. {+ Q& Q- #ifndef SHT30_H# A6 }' H. V& T" v
- #define SHT30_H
' Z- b; {: T" @ - #include "delay.h"6 v0 H- U# v! ?7 u0 r
- #include "sys.h"
" p8 ~' K; r( M$ X) k+ }$ o - #include "stdio.h"6 N8 @, Z( u( f! E7 t( k. q
- #include "usart.h"
! b g/ Z6 x; u. c4 Q% e - #include "string.h"
3 j% p2 e5 Q1 N6 h# p -
V/ C. n |! a- w' i8 ?4 L* U - extern u8 humiture_buff1[20];7 L) ^) M6 x" s+ ~) B
5 C2 h: i+ [! M! x- void SHT30_Init(void);
( e3 ]) b) e! ] - void IIC_ACK(void);- b5 Q, e2 V5 J& t* r3 z( A8 p* `. V
- void IIC_NACK(void);
8 h6 f- v' \* v" L - u8 IIC_wait_ACK(void);( L; N: W8 I! e; g8 O
- void IIC_Start(void);
) G) L: C6 v* G( \& `+ i% b - void IIC_Stop(void);) ]1 W5 I+ A5 f
- void IIC_SendByte(u8 byte);6 o" S6 S- X. w1 _3 C& |3 d
- u8 IIC_RcvByte(void);8 P* L& i- G3 {
- void SHT30_read_result(u8 addr);
: P2 Q( i, ?* S& N( c8 T% ? - + U' W) z" r- U; a2 o
- #endif6 f, Y3 r0 e3 C
- _$ `# Z. _2 |. H% ^4 J
复制代码
( N- g4 n" j6 `# a9 _/ m3 y- `1 i5 N$ R( h0 ^8 w! H w
主函数(while循环可以写个测试的printf)
, |) J* Y7 ]" [/ d9 P- #include "delay.h" u! B! Q$ Z6 h& z, ~
- #include "sys.h"
& M, h+ j" w# p4 _) g: f- z - #include "usart.h"* d3 V! ^5 j1 S
- #include "SHT30.h"
6 G0 A# j7 A1 H- X+ Y7 S$ y) b -
- {% F* |9 d# X% U
1 X0 K7 |) v& }: T5 H* X _( V- int main(void)
. V4 ?* u" c0 y0 R - { K. B- _" a0 i( D% m/ }
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
7 u) ]6 m, {; g5 i - delay_init(); //延时函数初始化
! C8 d; H3 b" I: _1 b0 _ - uart_init(9600); //串口初始化为9600
: ]2 o3 d" a; ~5 d. i2 U - SHT30_Init();
! q- x7 H$ t" n+ V/ \5 }9 d0 D - while(1)
g# z- a7 J. f) e, c) P1 Z: k - {
% D/ p; r) r! N8 h; ` - //printf("123456");
! @4 E. A7 v2 x9 W" d" X9 A! o - SHT30_read_result(0x44);, `0 x1 U2 b$ ]9 P$ w; N
- delay_ms(300);
( |4 G& }+ ^5 Z6 T7 { - + X3 M' p2 {! f) E. S) B5 }
- }" \2 H7 S4 h7 {: u/ p3 n' q
- }
$ m2 S R+ S: T
复制代码
8 e+ G1 v; l4 o- m* D
2 T8 i" z0 U6 V [' `代码实测能用 ,直接复制即可, 但是如果想改端口继续往下看。
; \% Z. V' h& i v4 N( i$ L- O/ T& Z+ ^3 i7 W4 T
' V+ \5 g, k {: C- A
3 F8 i9 P# ]+ E+ A5 k
7 _ w9 K8 L2 e1 x6 n8 {* _) k上图红色框选的是换端口所有需要改变的地方 这里漏框了上面的几个宏定义, 上面几个也要改。 p' M( ^0 \) r! k |. J
7 X0 f" d8 S; x0 _
* W5 f, R- v" v0 q3 ?, J" g5 k2 O8 f" |$ ~
GPIOA->CRL&=0XF0FFFFFF;理解为 清零了32位数据中的4位# d- F1 Q! d0 ]+ b9 v+ a
GPIOA->CRL|=8<<24;理解为置位了32位中的(24,25,26,27)的值! {+ P! g' l$ x; S$ Y- P8 S
' M4 s$ u) \6 u
3 L% Y0 r9 l- f9 v- a8 S
; Q r* V9 r% M5 y' ?* x
0 |, _' t! q; ^0 d2 D
2 n9 D# S0 l' g. r! y' ]$ ^
* x3 V. x4 G) t0 i4 X( m6 A2 `( J' j0 i! ?% Q7 _' @
上面两副图来自stm32中文手册 ,意思很明了, 有两个寄存器用来配置io口模式,CRL配置GPIO0-7, CRH配置GPIO8-15,第三副图是教你具体怎么配置,按照手册就可以选择配置你想用的端口了。
& ^' l3 v) F' u————————————————) Y S% u/ y1 q7 R8 H) V( C
版权声明:文某9# X8 a& u: u2 R- s
如有侵权请联系删除
7 {1 g) }, f# }
; O- n3 L) X9 E! }; b( K! ^4 ~
/ z N4 w4 k1 B1 a% S9 f: K
- B9 U$ S# }) L% x |