目录
一、介绍
二、传感器原理
1.原理图
2.引脚描述
3.工作原理
三、程序设计
main.c文件
sht30.h文件
sht30.c文件
四、实验效果
五、资料获取
项目分享
一、介绍
SHT30是一种常见的温湿度传感器,是一款完全校准的线性化的温湿度数字传感器,增强了数字信号。I2C通讯频率达1MHz。具有高可靠性及高稳定性。该传感器广泛应用于各种场景,小米的温湿度传感器就是使用的SHT30,本文是已硬件IIC来驱动SHT30。
以下是SHT30温湿度传感器的参数:
型号 | SHT30 |
工作电压 | 2.4~5.5V |
接口输出 | IIC |
测量温度范围 | -40~125℃ |
测量湿度范围 | 0~100%RH |
湿度精度 | 3%RH |
温度精度 | 0.3℃ |
哔哩哔哩视频链接:
SHT30温湿度传感器(STM32)
(资料分享见文末)
二、传感器原理
1.原理图
2.引脚描述
引脚名称 | 描述 |
SDA | 数据信号 |
ADDR | 连接到高电平或低电平,不可以悬空 |
ALERT | 报警引脚,不用必须悬空 |
SCL | 时钟信号 |
VDD | 电源正极 |
nRESET | 低电平复位 |
R | 无功能,接地 |
VSS | 电源地 |
EPAD | 中间引脚与电源地相通,散热引脚 |
3.工作原理
SHT30写命令
SHT30读命令
SHT30温湿度转换方法
信号输出的转换:测量数据总是以16位值( 无符号整数)的形式传输。这些值已经线性化,并补偿了温度和电源电压的影响。 将这些原始值转换为物理标度可以使用以下公式实现。相对湿度换算公式(结果为%RH):
Srh和St表示温湿度的原始传感器输出。计算出结果为十进制数据。
三、程序设计
1.使用STM32F103C8T6读取SHT30温湿度传感器采集的数据,通过串口发送至电脑
2.将读取得到信息数据同时在OLED上显示
SHT30_SCL | PB9 |
SHT30_SDA | PB8 |
OLED_SCL | PB11 |
OLED_SDA | PB10 |
串口 | 串口1 |
main.c文件
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "sht30.h"
/*****************辰哥单片机设计******************
STM32
* 项目 : SHT30温湿度传感器实验
* 版本 : V1.0
* 日期 : 2024.9.9
* MCU : STM32F103C8T6
* 接口 : 参看sht30.h
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
u8 buff[30];//参数显示缓存数组
int Temp = 0;
uint16_t Humi = 0; //温度和湿度
int main(void)
{
SystemInit();//配置系统时钟为72M
delay_init(72);
LED_Init();
LED_On();
SHT30_Init();
USART1_Config();//串口初始化
OLED_Init();
printf("Start \n");
delay_ms(1000);
OLED_Clear();
//显示“温度:”
OLED_ShowChinese(0,0,0,16,1);
OLED_ShowChinese(16,0,2,16,1);
OLED_ShowChar(32,0,':',16,1);
//显示“湿度:”
OLED_ShowChinese(0,16,1,16,1);
OLED_ShowChinese(16,16,2,16,1);
OLED_ShowChar(32,16,':',16,1);
while (1)
{
LED_Toggle();
SHT30_Read_Humiture(&Temp,&Humi);
// sprintf((char*)buff, "%d ",Temp);
// OLED_ShowString(48,0,buff,16,1);
//
// sprintf((char*)buff, "%d ",Humi);
// OLED_ShowString(48,16,buff,16,1);
OLED_ShowNum(48,0,Temp,2,16,1);
OLED_ShowNum(48,16,Humi,2,16,1);
delay_ms(500); //延时500ms
}
}
sht30.h文件
#ifndef __SHT30_H
#define __SHT30_H
#include "stm32f10x.h"
#include "delay.h"
#include "sys.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : SHT30温湿度传感器h文件
* 版本 : V1.0
* 日期 : 2024.9.9
* MCU : STM32F103C8T6
* 接口 : 见代码
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
/***************根据自己需求更改****************/
// CSHT30 GPIO宏定义
#define SHT30_IIC_CLK RCC_APB2Periph_GPIOB
#define SHT30_IIC_PORT GPIOB
#define SHT30_IIC_SDA_PIN GPIO_Pin_8
#define SHT30_IIC_SCL_PIN GPIO_Pin_9
//IO操作函数
#define SHT30_IIC_SDA_H GPIO_SetBits(SHT30_IIC_PORT,SHT30_IIC_SDA_PIN)
#define SHT30_IIC_SDA_L GPIO_ResetBits(SHT30_IIC_PORT,SHT30_IIC_SDA_PIN)
#define SHT30_IIC_SCL_H GPIO_SetBits(SHT30_IIC_PORT,SHT30_IIC_SCL_PIN)
#define SHT30_IIC_SCL_L GPIO_ResetBits(SHT30_IIC_PORT,SHT30_IIC_SCL_PIN)
#define SHT30_READ_SDA GPIO_ReadInputDataBit(SHT30_IIC_PORT, SHT30_IIC_SDA_PIN) //输入SDA
/*********************END**********************/
#define SHT30_ADDR (uint8_t)(0x44<<1) //sht30 i2c地址,ADDR管脚接低电平时为0x44,接高电平为0x45
//SHT30命令
#define SHT30_READ_HUMITURE (uint16_t)0x2c06 //读温湿度
//CRC多项式
#define POLYNOMIAL 0x31 // X^8 + X^5 + X^4 + 1
//SHT30
void SHT30_Init(void);
void SHT30_IIC_SDA_IN(void);
void SHT30_IIC_SDA_OUT(void);
void SHT30_IIC_Init(void);
void SHT30_IIC_start(void);
void SHT30_IIC_stop(void);
uint8_t SHT30_IIC_Get_ack(void);
void SHT30_IIC_ACK(void);
void SHT30_IIC_NACK(void);
void SHT30_IIC_write_byte(uint8_t Data);
uint8_t SHT30_IIC_read_byte(uint8_t ack);
/**********************************
函数声明
**********************************/
unsigned char SHT3X_CRC(uint8_t *data, uint8_t len);
void SHT30_CMD(uint16_t cmd);
u8 SHT30_Read_Humiture(int *temp,uint16_t *humi);
#endif
sht30.c文件
#include "sht30.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : SHT30温湿度传感器c文件
* 版本 : V1.0
* 日期 : 2024.9.9
* MCU : STM32F103C8T6
* 接口 : 见代码
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
#define POLYNOMIAL_CXDZ 0x31 // X^8 + X^5 + X^4 + 1
void SHT30_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SHT30_IIC_CLK,ENABLE);
GPIO_InitStructure.GPIO_Pin = SHT30_IIC_SDA_PIN | SHT30_IIC_SCL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//
GPIO_Init(SHT30_IIC_PORT, &GPIO_InitStructure);
SHT30_IIC_SDA_H;//释放IIC总线的数据线。
SHT30_IIC_SCL_H;//释放IIC总线的时钟线。
delay_us(6);
}
//SHT30引脚输出模式控制
void SHT30_IIC_SDA_OUT(void)//SDA输出方向配置
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=SHT30_IIC_SDA_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//SDA推挽输出
GPIO_Init(SHT30_IIC_PORT,&GPIO_InitStructure);
}
void SHT30_IIC_SDA_IN(void)//SDA输入方向配置
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=SHT30_IIC_SDA_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//SCL上拉输入
GPIO_Init(SHT30_IIC_PORT,&GPIO_InitStructure);
}
/****************************************************************
通讯起始信号:当 SCL 线是高电平时 SDA 线从高电平向低电平切换,表示通讯的开始;
*****************************************************************/
void SHT30_IIC_start(void)
{
SHT30_IIC_SDA_H;//拉高
SHT30_IIC_SCL_H;
delay_us(6);
SHT30_IIC_SDA_L;
SHT30_IIC_SCL_L; //拉低时钟线,准备开始时钟
delay_us(6);
}
/****************************************************************
通讯停止信号:当 SCL 是高电平时 SDA线由低电平向高电平切换,表示通讯的停止。
*****************************************************************/
void SHT30_IIC_stop(void)
{
SHT30_IIC_SCL_H;
SHT30_IIC_SDA_L;
delay_us(6);
SHT30_IIC_SDA_H; //通讯停止
SHT30_IIC_SCL_L;
delay_us(6);
}
/****************************************************************
//接收应答信号函数
*****************************************************************/
uint8_t SHT30_IIC_Get_ack(void)
{
uint16_t CNT;
SHT30_IIC_SDA_IN();
SHT30_IIC_SCL_L; //拉低时钟线。
SHT30_IIC_SCL_H; //拉高时钟线。
delay_us(6);
while((SHT30_READ_SDA) && (CNT < 100) )
{
CNT++;
if(CNT == 100)
{
return 0;
}
}
SHT30_IIC_SCL_L; //拉低时钟线。
delay_us(6);
SHT30_IIC_SDA_OUT();
return 1;
}
/****************************************************************
//发送应答信号函数
*****************************************************************/
void SHT30_IIC_ACK(void)
{
SHT30_IIC_SDA_L; //拉低数据线,应答
SHT30_IIC_SCL_H; //产生第九个时钟信号。
delay_us(6);
SHT30_IIC_SCL_L;
delay_us(6);
}
//非应答
void SHT30_IIC_NACK(void)
{
SHT30_IIC_SDA_H; //拉高数据线,非应答
SHT30_IIC_SCL_H; //产生第九个时钟信号。
delay_us(6);
SHT30_IIC_SCL_L;
}
/****************************************************************
//向IIC总线写入一个字节的数据
*****************************************************************/
void SHT30_IIC_write_byte(uint8_t Data)
{
uint8_t i;
for(i=0;i<8;i++)//八位数据
{
if((Data & 0x80) == 0x80)
{
SHT30_IIC_SDA_H;
}
else
{
SHT30_IIC_SDA_L;
}
SHT30_IIC_SCL_H; //一个时钟信号送入数据
delay_us(6);
SHT30_IIC_SCL_L;
delay_us(6);
Data = Data << 1;//数据左移一位,把次高位放在最高位,为写入次高位做准备
}
SHT30_IIC_SDA_L; //应答处理前拉低,跳过应答
}
/****************************************************************
//从IIC总线读取一个字节的数据函数
*****************************************************************/
uint8_t SHT30_IIC_read_byte(uint8_t ack)
{
uint8_t i;
uint8_t Data = 0; //定义一个缓冲寄存器。
SHT30_IIC_SDA_IN();
SHT30_IIC_SCL_L; //先拉低时钟线
SHT30_IIC_SDA_H; //再拉高数据线
delay_us(6);
for(i = 0;i < 8;i++)
{
Data = Data<<1; //将缓冲字节的数据左移一位,准备读取数据。
SHT30_IIC_SCL_H; //拉高时钟线,开始读取下一位数据
delay_us(6);
if(SHT30_READ_SDA) //如果数据线为高平电平。
{
Data = Data|0x01; //则给缓冲字节的最低位写1。
}
SHT30_IIC_SCL_L; //拉低时钟线,一位读取完成
delay_us(6);
}
SHT30_IIC_SDA_OUT();
if (!ack)
SHT30_IIC_NACK();//发送nACK
else
SHT30_IIC_ACK(); //发送ACK
return Data; //返回读取的一个字节数据。
}
//SHT3X CRC校验
unsigned char SHT3X_CRC(uint8_t *data, uint8_t len)
{
uint8_t bit; // bit mask
uint8_t crc = 0xFF; // calculated checksum
uint8_t byteCtr; // byte counter
// calculates 8-Bit checksum with given polynomial @GZCXDZ
for(byteCtr = 0; byteCtr < len; byteCtr++) {
crc ^= (data[byteCtr]);
for(bit = 8; bit > 0; --bit) {
if(crc & 0x80) {
crc = (crc << 1) ^ POLYNOMIAL_CXDZ;
} else {
crc = (crc << 1);
}
}
}
return crc;
}
//SHT30命令函数
//addr:表示产品的序号,因为SHT30使用IIC总线的话一条线上可以挂两个
void SHT30_CMD(uint16_t cmd)
{
SHT30_IIC_start();
SHT30_IIC_write_byte(SHT30_ADDR+0); //发送设备地址,写寄存器
SHT30_IIC_Get_ack();
SHT30_IIC_write_byte((cmd>>8)&0xff); //MSB
SHT30_IIC_Get_ack();
SHT30_IIC_write_byte(cmd&0xff); //LSB
SHT30_IIC_Get_ack();
SHT30_IIC_stop();
delay_ms(50);//命令发完后需要等待20ms以上才能读写
}
//SHT30读取温湿度
//temp:温度,-400~1250,实际温度=temp/10,分辨率0.1℃,精度±0.3℃
//humi:湿度,0~1000,实际湿度=humi/10,分辨率0.1%rh,精度±3
//返回0成功,1失败
u8 SHT30_Read_Humiture(int *temp,uint16_t *humi)
{
uint8_t buff[6];
SHT30_CMD(SHT30_READ_HUMITURE);//读温湿度命令
SHT30_IIC_start();
SHT30_IIC_write_byte(SHT30_ADDR+1); //发送设备地址,读寄存器
SHT30_IIC_Get_ack();
buff[0]=SHT30_IIC_read_byte(1);//继续读,给应答
buff[1]=SHT30_IIC_read_byte(1);//继续读,给应答
buff[2]=SHT30_IIC_read_byte(1);//继续读,给应答
buff[3]=SHT30_IIC_read_byte(1);//继续读,给应答
buff[4]=SHT30_IIC_read_byte(1);//继续读,给应答
buff[5]=SHT30_IIC_read_byte(0);//不继续给停止应答
SHT30_IIC_stop();
//printf("buff=%d,%d,%d,%d,%d,%d\r\n",buff[0],buff[1],buff[2],buff[3],buff[4],buff[5]);
//CRC校验
if(SHT3X_CRC(&buff[0],2)==buff[2] && SHT3X_CRC(&buff[3],2)==buff[5])
{
*temp=(-45+(175.0*((buff[0]<<8)+buff[1])/65535.0));
*humi=100*(((buff[3]<<8)+buff[4])/65535.0);
if(*temp>12500) *temp=12500;
else if(*temp<-4000) *temp=-4000;
return 0;
}
else return 1;
}