最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了
4 Z3 i6 I1 V; c# d, O8 b# v所以拿出来分享给大家。
8 Q3 f. ^: ?4 [8 V0 n1 q/ J7 @2 p* B, v( ]* m$ A; U5 t
sht30外观) w$ I2 u- w; n/ V
5 |9 n& Z" B4 L; O
7 k9 P$ K$ E# A
8 k0 {0 k- F" T: {驱动不是自己写的, 是采用CSDN上的一位朋友的 ,这里贴出来的代码不是本文的主旨, 重要是教会大
9 q9 L0 M8 t2 C. j) F: \
# Y7 o0 j' n) ~& Y+ o家如何配置各个端口(因为是模拟iic 所以大多数引脚都模拟为SCLK和DATA)。 e& ]( s. U2 y
7 _8 f) U1 C% m) `串口输出图
1 S4 H. v& T7 x% u4 J3 U8 K1 Z" [: e' @
+ Z% ?, x- s4 k. d2 S% q$ V' k3 D8 m* o2 m# R0 B
6 U( I/ P4 i5 e8 J驱动代码/ T3 I* ~ Y8 a
0 ^; i, Q: {& W6 `0 l
. t: p5 i! L* Y/ X0 e9 xsht30.c
) q( O0 z: \# [- #include "SHT30.h" 5 p% @2 ~$ W8 ?: N
( }( O v2 F6 X0 c1 m) I9 |/ p- #define write 0
: H! M1 I) i1 P3 L( ]4 W$ g - #define read 1
- S' v3 l, K/ J t
+ E' X D7 V: `3 w# ]$ C# Q- //IIC总线接口定义/ D( t' T3 _# @9 ?
- #define SCL PAout(5) A- n7 K( _) I0 B; }
- #define SDA_OUT PAout(6): A/ l6 [$ W6 K$ D
- #define SDA_IN PAin(6)' L9 F5 W( S% K" N
- #define IIC_INPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=8<<24;}2 M6 L# G9 a8 D' P ]4 W
- #define IIC_OUTPUT_MODE_SET() {GPIOA->CRL&=0XF0FFFFFF;GPIOA->CRL|=3<<24;} C+ g: N& X _& Y$ s' J6 X
- 5 M( N4 Z2 Q& k5 h+ D
-
2 X1 c. L' a4 S4 v3 v- v4 ^' m - float humiture[4];3 Q4 R) x1 [9 b( O& V
- u8 humiture_buff1[20];, P3 c4 ^- C" f& L6 O9 L
- $ x" J! k$ {0 d3 I! N
- void SHT30_Init(void)% Z% j6 I) M+ c& u; i
- {+ O2 j% d% t' z4 c
- GPIO_InitTypeDef GPIO_InitStructure;; c( o& v1 C7 v/ S
- //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟 $ _: u$ r# b: V- W, K, A4 _
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); N8 x% f4 U3 r
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;
# c5 \1 Q- P# ]0 v" B1 s; u - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出0 s A" [$ S: w% s! }! s/ P
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;! C+ C% }0 P$ {" w% M8 w m
- GPIO_Init(GPIOA, &GPIO_InitStructure);
+ P% y$ X& R, n; d. j - SCL=1;
+ F1 c8 ^$ ~6 W# `0 N; O$ v1 s5 s: I - SDA_OUT=1;
/ ?( M* W9 f, E# o - } + M/ }: B# j% p; V1 M. g7 z
- /*主机发送ACK*/
* n: i% \2 X# N" j - void IIC_ACK(void)
0 w0 C3 j/ S) m9 w F. o8 b - {' [: z. ^: u" A9 n
- IIC_OUTPUT_MODE_SET();
3 n( X; \# \+ m, ] [" c - SCL=0;2 x1 \/ L# g3 }- w3 Y: Z. G3 @
- delay_us(2); 0 B Z0 w n0 Y4 B
- SDA_OUT=0;% e) M. ?* m. c% Y s( S4 C2 q( p! I
- delay_us(2); / H P% @. h7 R" M# U
- SCL=1;
/ B, m2 e6 c2 r: I - delay_us(2); ' r" e0 {; @ t n& b, F0 f+ e
- SCL=0; # E5 O1 y& l' `& L( N' J5 n6 H
- delay_us(1); 8 g) M% ^1 Y2 ~$ l8 v7 r/ W
- }9 k5 f& `" ~. x9 m
- /*主机不发送ACK*/6 ~) a; H' M2 H/ S9 B
- void IIC_NACK(void); m" r! A3 h+ a6 {
- {
5 K3 w9 Q* Q, }: x - IIC_OUTPUT_MODE_SET();
, b6 x' H( C; z4 [. a - SCL=0;
( M: I! l* _3 k9 c I# K - delay_us(2); 2 h: s! w' f) v! _
- SDA_OUT=1;
4 N! s& i. V" W/ i - delay_us(2); + b3 G7 u0 x% y' T) r6 |
- SCL=1;" B9 }) q) _7 z3 p s
- delay_us(2);
0 u8 _; {$ q4 ?( V P& |* [3 Z9 N - SCL=0;
2 r0 r* [: F% D5 h5 j. s2 C - delay_us(1);
0 j0 x% m- Z& Q7 c% o - }
# r# s1 a. _3 c; U& ~ - /*主机等待从机的ACK*/
% V0 J9 p% n; A - u8 IIC_wait_ACK(void)
% f8 }5 h& O( ]0 A3 Y" O8 g2 }# _- { - {
) U S8 l) r0 A3 ]8 Z - u8 t = 200;! e0 d/ D1 o0 l, ]/ F. ?- Z3 X8 G. Y; G
- IIC_OUTPUT_MODE_SET();
$ n3 D( `6 t, P) x* q. k6 X- L: Z - SDA_OUT=1;//8位发送完后释放数据线,准备接收应答位 / q. }6 V) v J. t; w9 M
- delay_us(1);
$ l6 y2 k% r* o o% ~! H0 d* h - SCL=0;
. d* c4 ~ l3 C- H5 c0 q" [0 D* h - delay_us(1);
3 w* v( V6 F- R& p: {" _ - IIC_INPUT_MODE_SET();" d/ l! y# j2 ?/ K- E" H
- delay_us(1); 2 }/ ]4 T- b2 M2 K0 T4 a9 f
- while(SDA_IN)//等待SHT30应答6 [: k. F! {/ ]* [
- {% f i/ b! k0 t+ k. P
- t--;
% K/ x) v$ ?( q" o - delay_us(1); 8 e& G% r1 S/ `% i0 i' X
- if(t==0)0 p5 K% ~. Z1 i
- {, p4 m4 u# ]8 r8 G5 u" i
- SCL=0;
+ ?' a! F, ?, o' F7 d - return 1;6 z, ^7 f1 a* [" j/ |5 r# L' T- }
- }, K+ K6 P5 z1 i8 G
- delay_us(1);
" y% d- @# h B* w t, V, s6 a/ L& { - }6 {/ A+ a3 a6 [4 M1 l6 u, p
- delay_us(1);
! }; G5 x$ b! P. g0 s1 P - SCL=1;
, g: K( ^+ n3 k9 K6 N - delay_us(1);% O' V' O0 b) q0 h
- SCL=0;
7 g" \( N( F$ w - delay_us(1);
. e+ `9 j) F; z/ H6 B - return 0;
+ ]& z: m7 g8 e) T' @& T - }; E! R+ [. M6 Q6 ~8 H
- /*******************************************************************
6 R, F1 _! ^& h) M9 a% _: w# s - 功能:启动I2C总线,即发送I2C起始条件.
1 H- ]1 q$ Q: j! g5 D; S6 c - ********************************************************************/8 K# b/ s' J5 B
- void IIC_Start(void)' g8 i+ f. ]" k3 c
- {
* S! H6 V# E* `1 C - IIC_OUTPUT_MODE_SET();, `# b: ^5 U5 t! c- L
- SDA_OUT=1;5 B2 g |6 d8 _! M9 J$ U5 ]
- SCL=1;
8 X. O" q! ?7 w- }5 \) ~/ X- e - delay_us(4);
' \$ B- b& j) M D - SDA_OUT=0;
1 j7 \& X* M' A k: n/ f - delay_us(4); 0 c/ c) a3 z/ \9 x5 y! _5 z
- SCL=0;
, P1 f/ U5 Z, B& E& m" y - }) \1 x" t: q; q9 B- d
-
; P' c5 f% }; i; A" i J# y+ @ - /*******************************************************************0 L8 k% e) T" H4 C: k
- 功能:结束I2C总线,即发送I2C结束条件. 9 w/ J$ j; x7 \8 L
- ********************************************************************/
; ?4 k' O1 }4 b - void IIC_Stop(void)% U4 m0 H$ O( P, \
- {
% X. r y6 s: M; k! ^ - IIC_OUTPUT_MODE_SET();
; T u8 t+ b9 C0 K" P2 G - SCL=0;
* J; {# a' P* [" `- m3 t( a - SDA_OUT=0; ; K- z. m" V [) `
- delay_us(4); , k; \, ^0 y( y. I3 ~8 T5 _
- SCL=1;* z' i/ q2 j0 u# B
- delay_us(4);
) D8 |* P( g5 r( \: w - SDA_OUT=1;
" v$ L8 f* \& Y$ r8 s9 m/ K - delay_us(4);( d3 a I) `& M# N! y
- }5 ]! x# C* w( \( i! ]4 A ~: r
-
3 b2 O; P9 O) ~5 e' O3 m - /*******************************************************************4 ~* n: F# d1 Z6 Y* A
- 字节数据发送函数
1 j+ e7 k4 U6 ]9 R# t! d% C) L - 函数原型: void SendByte(UCHAR c);) t2 O, C9 Y6 u- T6 g
- 功能:将数据c发送出去,可以是地址,也可以是数据
8 Q! S1 G) ]9 Q; q& _+ y - ********************************************************************/
- I- H5 P( S& H) F - void IIC_SendByte(u8 byte)
9 l1 b$ |! S5 r* y7 S - {! q3 A7 h% U( x/ y' J" k+ i( m) n
- u8 BitCnt;
. Y# r& x3 Q l - IIC_OUTPUT_MODE_SET();$ H' l( y. D+ S. r: E: u
- SCL=0;
; W: v- p1 b# m {. }3 [ - for(BitCnt=0;BitCnt<8;BitCnt++)//要传送的数据长度为8位4 V$ v2 ]6 f! x% g0 F
- { H Y4 Z0 R5 u' s3 c- S2 r/ g
- if(byte&0x80) SDA_OUT=1;//判断发送位
4 ?! W( h7 Q2 W w5 o. Z i- W3 R - else SDA_OUT=0;
1 `4 E/ M W+ C" | - byte<<=1;+ l7 P( |" \, ]# o+ U
- delay_us(2);
8 p" n: x% y" W& `* ~ X4 X - SCL=1;
2 c5 M4 L8 D! H0 p' P3 | - delay_us(2);2 D/ I! G' I6 {. m
- SCL=0;
2 q" [0 g, w, j; [5 ` - delay_us(2);! _/ V8 G' e4 Z: ^
- }" K2 K, o0 `, X, Q: U3 j
- }0 m9 Q2 @/ s3 D: R
- /*******************************************************************8 j/ o$ x, [# x5 E( ~/ g
- 字节数据接收函数
3 ~6 j) l: m" K0 C6 W1 C - 函数原型: UCHAR RcvByte();4 o- }% }+ l4 s) n7 ?. l% s
- 功能: 用来接收从器件传来的数据
8 t0 E2 v' ]7 V7 B3 v" G - ********************************************************************/ . w" [7 G2 j! B8 s8 M; U( E9 B6 S1 _
- u8 IIC_RcvByte(void)0 s8 ~/ T$ u$ U5 s+ _( |) U: N
- {0 m2 w( ^6 d4 U8 _- @) @$ p
- u8 retc;* S5 y. u/ U6 c1 V l$ r
- u8 BitCnt;3 d2 t/ _5 t {5 c# @9 Y8 o
- retc=0; " V& h8 Y* @& o% G4 ~
- IIC_INPUT_MODE_SET();//置数据线为输入方式
" O# N8 x* q/ q _) b: B; f. v - delay_us(1); 2 V' @6 _, m) J7 w
- for(BitCnt=0;BitCnt<8;BitCnt++)
3 L1 C' V8 y0 K* p+ {7 Q& C0 `- x - { ' X$ P- W2 A4 j, k, o
- SCL=0;//置时钟线为低,准备接收数据位
! C, {& B/ B: Z - delay_us(2);
$ c ?& C- e7 e! W; V0 m - SCL=1;//置时钟线为高使数据线上数据有效
- z4 D* Q" n- K - retc=retc<<1;9 \1 ]* r2 T& B0 F2 t: s: E
- if(SDA_IN) retc |=1;//读数据位,接收的数据位放入retc中 5 z4 W1 I7 B/ F& d
- delay_us(1);
: d9 i" x4 \3 F1 C - }, f- c- G3 q! k6 j# g7 g$ t/ Z, Z
- SCL=0;
+ F* N: z3 }5 |9 r7 Z- x4 p - return(retc); M) S" T* h5 E8 T
- }
" p: c G/ H- z a - /*******************************************************************
, @% {% C( V( x, {% w9 K - 温湿度获取函数
' I$ w8 z$ U. |# c# S( Y* q; {' N0 w - 函数原型: SHT30_read_result(u8 addr);
/ Q, s( [# V8 A" f" F- R& z - 功能: 用来接收从器件采集并合成温湿度( R. P, `! Z- ~9 s7 _/ S
- ********************************************************************/
) e* d& k7 v: E# E u% C - void SHT30_read_result(u8 addr)
' \" D+ B ^! `, u( x - {
2 Z9 u+ u* P w6 ? - u16 tem,hum;
+ i! R! P/ g- D! }+ \9 n9 ~ - u16 buff[6];
- U; S D" d# V) a" } - float Temperature=0;1 N( B" |8 Z5 i
- float Humidity=0;2 U$ L# Y; V2 T, N4 J n
- + E/ I. L8 P- b5 ?+ Z" Q3 o
- IIC_Start();
0 N( w! E0 A {5 D4 L& t$ E - IIC_SendByte(addr<<1 | write);//写7位I2C设备地址加0作为写取位,1为读取位' f( H( K j! C: a" B s1 k
- IIC_wait_ACK();
3 k& C! t/ O e1 a1 l/ \- }0 r - IIC_SendByte(0x2C);, Q" `2 l+ ~) ?7 j- o/ O* R4 Q
- IIC_wait_ACK();. i2 {1 U: }: p% B
- IIC_SendByte(0x06);5 q; a7 v C2 ]" j4 y: [% g" h w
- IIC_wait_ACK();- m* I- f0 c, h6 ~: O* r* ^) y
- IIC_Stop();8 _% X3 {( w9 G5 x. V. j4 e7 T
- delay_ms(50);
3 ]1 t7 s8 t6 U8 e - IIC_Start();
! v+ ?, V9 y, H% B* P6 f( W - IIC_SendByte(addr<<1 | read);//写7位I2C设备地址加0作为写取位,1为读取位: m. E% ]% [ D- u2 v- \
- if(IIC_wait_ACK()==0)
4 u, s W( d& f6 P - {% y* `( d0 a$ q0 Q
- buff[0]=IIC_RcvByte();
. Y3 \% L0 A+ m, m: r( x4 H9 H1 O - IIC_ACK();
6 L0 b& u# |$ `% W0 o, X - buff[1]=IIC_RcvByte();
$ q% f0 ~1 t+ C# @) c6 F/ I8 f - IIC_ACK();0 x( i+ @. u% T3 x8 Q
- buff[2]=IIC_RcvByte();
, e0 q( B; z( z# a - IIC_ACK();
3 R& u g3 u4 ~6 V. f4 \ - buff[3]=IIC_RcvByte();4 j3 D# K! }3 n! [9 C
- IIC_ACK();
$ t9 `/ s% \ z% u: m$ d, T - buff[4]=IIC_RcvByte();
. h' s1 l6 u! m( W: b - IIC_ACK();
8 j+ `& h5 F1 {/ L7 p/ k3 c - buff[5]=IIC_RcvByte();: Z4 T" u% E; r
- IIC_NACK();% V$ P# a; }! C2 a# ~ ?
- IIC_Stop();; G" Q- C, a" S+ h t3 M% \" J7 n
- }( P# {) x# c+ \ ~ J* f
-
: K- c! P% M% k" k T - tem = ((buff[0]<<8) | buff[1]);//温度拼接& [4 |* u) ] [' C/ q
- hum = ((buff[3]<<8) | buff[4]);//湿度拼接0 ^- s4 Q* a7 W- G& [. ^% B: [
- 4 i8 r, q) R* E) a9 G& ~# X! Q3 |
- /*转换实际温度*/7 j; {1 h- Z* K& h$ w
- Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)
$ W9 y ]# h8 t# b7 o+ C - Humidity= (100.0*(float)hum/65535.0);// RH = hum*100 / (2^16-1)
. |" `6 y7 n/ E, z" o -
) P) M2 S9 q/ f% z - if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据
4 y) H( a: [2 V7 _& h - {, T* F4 d( R% w* s
- // humiture[0]=Temperature;5 O' }( l3 V9 ~& y& m# K
- // humiture[2]=Humidity;
$ d8 E; p; l" i* l - sprintf(humiture_buff1,"%6.2f*C %6.2f%%",Temperature,Humidity);//111.01*C 100.01%(保留2位小数)+ U2 C3 R P( N, D- }7 w
- }$ ~" s; h A( y2 W( s
- printf("温湿度:%s\n",humiture_buff1);' U7 f7 Q& r8 W: h1 i
- hum=0;9 j4 \2 e7 M4 c
- tem=0;1 L4 e: z1 e+ z1 `( f& G/ t
- }$ @3 z2 L- s5 U" c6 h' ?& `
- ' `) D( ^/ m7 i% o% Y1 H; |
复制代码 3 z* ^$ R1 O7 Y7 {+ h
/ s2 P2 E- t9 lsht30.h
: m) d) X+ N7 l+ z! f) { a9 Q- #ifndef SHT30_H
8 h+ I+ J9 }( \1 o$ d( C/ I: _# N - #define SHT30_H
; F u* G' K" ^/ N - #include "delay.h"" ?& ~ H8 H; {+ f% F
- #include "sys.h"
! L+ q! Y. V- R- L t - #include "stdio.h"
, _) h3 F8 z; }3 o - #include "usart.h"
( D' }0 l- n( @ - #include "string.h"7 Y0 J( h% q, @7 J' k
-
- T, c5 {$ [2 O8 Q$ z( g4 D0 j - extern u8 humiture_buff1[20]; S0 m9 ]: f* _. L" K/ f8 M. ~
& }, T+ |/ ]/ G+ ^# K& |- void SHT30_Init(void);7 j$ _+ t" q3 X' F1 k4 d: t
- void IIC_ACK(void);) n K0 ^' G- e5 M* n* L& a# L
- void IIC_NACK(void);9 {6 }( H6 ]" T7 x+ ~0 W) p
- u8 IIC_wait_ACK(void);
% c) j* I) n6 s& |; ]0 o* d2 Y - void IIC_Start(void);/ j1 i3 }3 J3 p% v6 p1 f
- void IIC_Stop(void);
7 i$ h4 _1 D# r' A0 B - void IIC_SendByte(u8 byte);
( _& e- @# P0 z6 e, I - u8 IIC_RcvByte(void);
7 f( M! V* D: b$ e9 `- g2 Z* n - void SHT30_read_result(u8 addr);+ }( @7 m1 I; F+ ?. X: }
- " p' v+ y+ Y! E B, ?* R
- #endif, ?+ s7 w. b6 ]' L! a, O. R0 V
( }3 c* z/ H, ^. M5 {6 g! Y
复制代码
, ]$ G3 z; _1 A& q' x) k
+ h! g+ T( W" V0 W. I主函数(while循环可以写个测试的printf)& H2 O" \* U2 K2 v9 ^, e' ?
- #include "delay.h"" h( i) w% @ p( m4 Z9 Q/ ] ^2 k
- #include "sys.h"
. T& q; \" W9 J8 i - #include "usart.h"# j& R% c' T& Z! J
- #include "SHT30.h"
% g! s- I3 D+ C | - 2 k6 v, [" i) ~5 f$ j* p6 _) { |
- ' P& _9 g6 i! q/ J0 v/ w# p$ c
- int main(void)3 ?5 }* k9 K3 O* Q
- { " \# @( n4 X) \6 U3 q
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2" q. a2 c2 a) O ?2 i& g9 o
- delay_init(); //延时函数初始化
4 J0 E0 Z+ f6 m7 f - uart_init(9600); //串口初始化为96003 t$ J/ U0 f5 b9 m. `/ I/ h7 z; r3 d" b
- SHT30_Init();# k! `/ a9 Z W7 b" N: S
- while(1). \& d5 ]. a$ L+ ~0 k1 M
- {
6 v3 D3 A; g# M& o# _ - //printf("123456");# v6 l/ j$ g3 m7 u7 M
- SHT30_read_result(0x44);
9 Q. |% l: b7 T& z9 o, V - delay_ms(300); 0 K4 m6 u. B- ]: j- d
- ' O% A' w5 C$ l
- }- ?& Q/ A$ \7 E$ U/ J
- }2 G% \; X+ @/ z! o6 c) r
复制代码 ) p3 b9 J) H3 A1 z% t" j
9 \8 c; U& f& `
代码实测能用 ,直接复制即可, 但是如果想改端口继续往下看。
5 [# X& O" x# S6 V
+ l+ F" K( u! k4 O2 N: N. I: p, s
& b3 U% b5 @" x7 x* m7 u# {
8 v G U/ [' ~. `8 W; w
4 L0 k8 s+ H4 s7 R' W上图红色框选的是换端口所有需要改变的地方 这里漏框了上面的几个宏定义, 上面几个也要改。# { S6 h2 r6 e5 H* H
7 L4 ?) i* u0 t7 ^* K$ a! J6 b- u# k4 a
1 D F) C0 L. ?7 I$ x! \, q
2 i( F: ]& o' P2 \# ]GPIOA->CRL&=0XF0FFFFFF;理解为 清零了32位数据中的4位
8 n+ A3 A, g4 kGPIOA->CRL|=8<<24;理解为置位了32位中的(24,25,26,27)的值
0 n1 p" l% P y4 N1 L) `/ y: U: o" X6 ?+ n- w0 {
4 p! y! [6 }, O2 T3 {, Y
0 s. C$ P6 q( h& T1 A9 d2 M
) g& o, b5 k$ m8 Y5 k( u. A; }
, O, x1 O8 e( L) w( R
+ Y+ i2 b- s0 B7 A* h; H
; C& }, R: {- k4 V! f上面两副图来自stm32中文手册 ,意思很明了, 有两个寄存器用来配置io口模式,CRL配置GPIO0-7, CRH配置GPIO8-15,第三副图是教你具体怎么配置,按照手册就可以选择配置你想用的端口了。 a* T" f1 ?+ {: y# l
————————————————
2 [$ m/ f9 W, o; q0 H- Y x版权声明:文某9
2 u" K4 |* S+ z5 `3 b如有侵权请联系删除! d, `' Y) I2 n1 c2 m
# m1 }2 G3 I9 X0 A
0 u1 K2 ? f- {9 c6 i
1 a3 V# V* _+ e# H6 n* D7 K |