STM32物联网项目-SHT30温湿度采集(IIC通信)
SHT30温湿度采集(IIC通信)
SHT30数字温湿度传感器
SHT3x湿度传感器系列包括低成本版本SHT30、标准版本SHT31,以及高端版本SHT35。
SHT3x湿度传感器系列结合了多种功能和各种接口(I2C、模拟电压输出),应用友好,工作电压范围宽(2.15至5.5 V),适合各类应用。
SHT3x建立在全新和优化的CMOSens® 芯片之上,进一步提高了产品可靠性和精度规格。SHT3x提供了一系列新功能,如增强信号处理、两个独特和用户可选I2C地址、一个可编程温湿度极限的报警模式,以及高达1 MHz的通信速度。
DFN封装的占位面积为2.5 × 2.5 mm2,高度为0.9 mm。这有助于SHT3x集成到多种应用。此外,2.15至5.5 V的宽电源电压范围和多种可选接口可保证与不同集成要求的兼容性。总之,SHT3x湿度传感器系列融入了Sensirion作为行业领导者15年的经验和心血,是一款超高性价比的产品。
特点
完全校准,线性化,和温度补偿数字输出
宽电源电压范围,从2.4到5.5 V
IIC接口通信速度1 MHz和两个用户可选择的地址
典型精度2%RH(湿度)和0.3°C(温度)
非常快速启动和测量时间
小8针DFN包(封装)
32引脚既作输入又作输出
在51单片机中,引脚都叫通用输入输出引脚,是具有双向功能的,32单片机的引脚也可以
开漏输出框图
CPU往位设置寄存器写入1,则高电平1来到输出控制电路这里,N-MOS管不会导通,此时IO端口的电平状态由外部的上拉或者下拉决定,可能为高电平也可能为低电平;同时IO端口的状态可以被读取,通过虚线的电路被CPU读取,此时读取的并不一定是CPU输出的高电平1,而是外部的状态
CPU如果往位设置寄存器写入0,则低电平0来到输出控制寄存器,N-MOS管导通,IO端口与VSS导通,而VSS是电路公共地端电压,一般接GND,所以IO端口就输出低电平0;同时CPU读取时端口状态就是自己输出的低电平0
所以IO引脚配置为开漏输出就既可以作输出又可以作输入了,并不需要再配置改变IO口的工作模式
SHT30通信引脚配置
因为SHT30是IIC通信的,SCL与SDA均配置为开漏输出,总线上均有上拉电阻。因此,SDA作为输出的同时,也可以作为输入使用。与51内核的准双向口一样,作为输入使用时,需要先输出高电平,关闭内部的NMOS管。
CubeMX配置
因为IIC通信的SCL引脚接到了PG11,SDA接到了PG12,所以需要配置这两个引脚为开漏输出
PG11和PG12都配置为开漏输出,并输出高电平,因为是通信,输出速度可以选高速
其他配置如定时器6,数码管,串口,LED灯按照之前实验中配置方法就行,系统时钟72MHz
程序
IIC.c
根据IIC通信时序图编写函数,本次使用软件模拟IIC通信的方式,对IIC通信加深理解
IIC通信介绍可以参考:http://t.csdn.cn/xvYI5
/* Includes ------------------------------------------------------------------*/
#include "MyApplication.h"/* Private define-------------------------------------------------------------*/
#define SET_SCL HAL_GPIO_WritePin(SCL_GPIO_Port,SCL_Pin,GPIO_PIN_SET)
#define CLR_SCL HAL_GPIO_WritePin(SCL_GPIO_Port,SCL_Pin,GPIO_PIN_RESET)#define SET_SDA HAL_GPIO_WritePin(SDA_GPIO_Port,SDA_Pin,GPIO_PIN_SET)
#define CLR_SDA HAL_GPIO_WritePin(SDA_GPIO_Port,SDA_Pin,GPIO_PIN_RESET)#define READ_SDA HAL_GPIO_ReadPin(SDA_GPIO_Port,SDA_Pin)/* Private function prototypes------------------------------------------------*/
static void IIC_Init(void);
static void IIC_Start(void);
static void IIC_Stop(void);
static void Write_Byte(uint8_t );
static uint8_t Recive_Byte(void);
static void SendACK(ACK_Value_t );
static ACK_Value_t ReciveACK(void);
static void IIC_Delay_us(uint8_t );
/* Private variables----------------------------------------------------------*//* Public variables-----------------------------------------------------------*/
IIC_Soft_t IIC_Soft =
{IIC_Init,IIC_Start,IIC_Stop,Write_Byte,Recive_Byte,SendACK,ReciveACK
};/*
* @name IIC_Init
* @brief IIC初始化
* @param None
* @retval None
*/
static void IIC_Init()
{SET_SCL;SET_SDA;
}/*
* @name IIC_Start
* @brief 起始信号
* @param None
* @retval None
*/
static void IIC_Start()
{//SCL为高电平时,SDA的下降沿为IIC的起始信号SET_SCL;SET_SDA;IIC_Delay_us(1);CLR_SDA;IIC_Delay_us(10);CLR_SCL;IIC_Delay_us(1);
}/*
* @name IIC_Stop
* @brief 停止信号
* @param None
* @retval None
*/
static void IIC_Stop()
{ //SCL为高电平时,SDA的上升沿为IIC的停止信号CLR_SDA;SET_SCL;IIC_Delay_us(10);SET_SDA;
}/*
* @name Write_Byte
* @brief 主机发送一个字节
* @param WR_Byte:要发送的数据
* @retval None
*/
static void Write_Byte(uint8_t WR_Byte)
{uint8_t i;//传输一个字节/*SCL为低电平时,SDA准备数据,接着SCL为高电平,读取SDA数据数据按8位传输,高位在前,利用for循环逐个接收*/for(i=0;i<8;i++){CLR_SCL; //拉低SCLIIC_Delay_us(1);if((WR_Byte&BIT7) == BIT7) //如果一个字节最高位为1{SET_SDA; //往SDA上放1}else{CLR_SDA; //否则往SDA上放0}IIC_Delay_us(1);SET_SCL; //拉高SCL,从机读取数据IIC_Delay_us(10);WR_Byte <<= 1; //左移一位,发送下一位}
}/*
* @name Recive_Byte
* @brief 主机接收一个字节
* @param None
* @retval 接收到的数据
*/
static uint8_t Recive_Byte()
{uint8_t i,Re_Byte = 0x00;//释放SDA,将控制权交给从机,即SDA = 1SET_SDA;//接收一个字节for(i=0;i<8;i++){CLR_SCL; //拉低SCL,从机SDA准备数据IIC_Delay_us(10);SET_SCL; //拉高SCL,读取数据IIC_Delay_us(10);if(READ_SDA == GPIO_PIN_SET){Re_Byte|=(BIT7>>i);} }return Re_Byte;
}/*
* @name SendACK
* @brief 主机发送应答
* @param ACK_Value:ACK:应答,NACK:非应答
* @retval None
*/
static void SendACK(ACK_Value_t ACK_Value)
{CLR_SCL; //拉低SCL,主机准备发送应答信息IIC_Delay_us(1);//发送应答信息if(ACK_Value == ACK){CLR_SDA; //0表示应答 }else{SET_SDA; //1表示非应答}IIC_Delay_us(1);SET_SCL; //拉高SCL,主机发送应答IIC_Delay_us(1);//释放SDA数据线//SCL先清零,再释放SDA,防止连续传输数据时,从机错将SDA释放信号当成NACk信号CLR_SCL; //拉低SCLSET_SDA; //因为主机发送应答后,从机可能会继续发送数据,所以控制权要给到从机IIC_Delay_us(1);
}/*
* @name ReciveACK
* @brief 主机接收应答,判断从机是否应答
* @param None
* @retval 从机的应答
*/
static ACK_Value_t ReciveACK()
{uint8_t RecAck;CLR_SCL; //拉低SCLSET_SDA; //主机释放SDA,将控制权交给从机,即SDA = 1IIC_Delay_us(1);SET_SCL; //拉高SCL,读取SDA的值IIC_Delay_us(10);RecAck = READ_SDA; //读取SDA的值,0表示应答,1表示非应答CLR_SCL;IIC_Delay_us(1);return (ACK_Value_t)RecAck;
}/*
* @name IIC_Delay_us
* @brief IIC延时函数——微秒级,
* @param us:要延时的时间
* @retval None
*/
static void IIC_Delay_us(uint8_t us)
{uint16_t i;//通过示波器测量进行校准while(us--){for(i=0;i<7;i++);}
}
/********************************************************End Of File
********************************************************/
SHT30.c
根据SHT30的数据手册来编写通信函数
4.5定期数据采集模式的测量命令
在这种模式下,一个发出的测量命令会产生一个数据对流。每个数据对由一个16位温度值和一个16位湿度值(按此顺序)组成。在周期模式下,可以选择不同的测量命令。对应的16位命令如表9所示。它们在可重复性(低、中、高)和数据采集频率(每秒0.5、1、2、4和10次测量值,mps)方面存在差异。在此模式下不能选择时钟拉伸。数据采集频率和可重复性设置会影响传感器的测量持续时间和电流消耗。
根据表格下方的通信时序,主机发送起始信号,然后发送从机地址加写指令命令,等待从机应答,再发送命令的高位(MSB),等待从机应答,再发送命令的低位(LSB)
调用IIC的函数,根据通信时序,完成设置周期测量模式
//设置周期测量模式
IIC_Soft.IIC_Start();
IIC_Soft.Write_Byte(SHT30_ADDR&WRITE_CMD);
IIC_Soft.ReciveACK();
IIC_Soft.Write_Byte(0x27); //MSB,设置Repeatability为High,mps为10的测量模式
IIC_Soft.ReciveACK();
IIC_Soft.Write_Byte(0x37); //LSB
IIC_Soft.ReciveACK();
4.6周期模式下测量结果的读数
读数可以通过表10所示的命令启动。如果没有测量数据,I2C读取头用NACK而不是ACK(表10中的位9)响应,通信停止。
空白的数据块是由32发送,黑色的数据块是由SHT30发送
根据表10的通信时序,获取SHT30的温湿度数据,读数据的命令是0xE000,获取的是16位的温度值和16位的湿度值,温度和湿度后都有CRC-8校验
从SHT30读出的16位温度和16位湿度还不是真正的温湿度值,而是要根据上面这个公式来计算得到正确的温湿度值,RH是湿度,T是温度
通信时序代码
在通过公式计算温湿度值时,因为216 - 1是65535,175/65535 = 0.002670328…,结果除不尽,但浮点型float的精度为6~7位有效数字,直接计算的话相当于把小数点后7位之后的数据省略掉了,会造成计算出来的温湿度精度有些损失,所以有了这样的方法:先让公式的数值都*100,这样的话计算出来的温湿度值也会 *100,但这样计算的小数位就会多两位,精度较为准确,在赋给最后结果变量前再 *0.01,将结果变回正常值即可
//读取数据Timer6.SHT30_Measure_Timeout = 0;do{//如果2秒内没有获取到数据,则break退出if(Timer6.SHT30_Measure_Timeout >= TIMER_2s){LED.LED_Fun(LED2,LED_OFF);break;}IIC_Soft.IIC_Start();IIC_Soft.Write_Byte(SHT30_ADDR&WRITE_CMD);IIC_Soft.ReciveACK();//0xE000是向SHT30取数据的指令,主机发送该指令后开始读取SHT30的温湿度数据IIC_Soft.Write_Byte(0xE0); IIC_Soft.ReciveACK();IIC_Soft.Write_Byte(0x00);IIC_Soft.ReciveACK();//重新发送起始信号,往SHT30发送地址加读取数据指令IIC_Soft.IIC_Start();IIC_Soft.Write_Byte(SHT30_ADDR|READ_CMD);/*判断是否收到从机应答,主机收到NACK时,继续循环发送取数据指令,主机收到ACK时,不满足条件,退出,往下执行*/} while (IIC_Soft.ReciveACK() == NACK); //接收温湿度数据//判断是否是超时退出,如果不是,则有数据,进行接收;如果是则没有数据,不处理if(Timer6.SHT30_Measure_Timeout < TIMER_2s){temp_array[0] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);temp_array[1] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);temp_array[2] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);temp_array[3] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);temp_array[4] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);temp_array[5] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(NACK);IIC_Soft.IIC_Stop();//计算温度if(CRC_8(temp_array,2) == temp_array[2]) //进行CRC-8校验{temp_uint = temp_array[0]*256+temp_array[1]; //取出16位的温度值temp_float = ((float)temp_uint)*0.267032-4500; //根据手册公式计算,为了精度,计算数值先*100SHT30.fTemperature = temp_float*0.01; //再除以100,得到正常温度值}//计算湿度if(CRC_8(&temp_array[3],2) == temp_array[5]) //进行CRC-8校验{temp_uint = temp_array[3]*256+temp_array[4]; //取出16位的湿度值temp_float = ((float)temp_uint)*0.152590; //根据手册公式计算SHT30.ucHumidity = (uint8_t)(temp_float*0.01); //除以100,得到正常湿度值}LED.LED_Fun(LED1,LED_OFF); //转换完成LED1熄灭}
}
CRC-8检验函数
/*
* @name CRC_8
* @brief CRC-8校验
* @param Crc_ptr -> 校验数据首地址LEN -> 校验数据长度
* @retval CRC_Value -> 校验值
*/
static uint8_t CRC_8(uint8_t *Crc_ptr,uint8_t LEN)
{uint8_t CRC_Value = 0xFF;uint8_t i = 0,j = 0;for(i=0;i<LEN;i++){CRC_Value ^= *(Crc_ptr+i);for(j=0;j<8;j++){if(CRC_Value & 0x80)CRC_Value = (CRC_Value << 1) ^ 0x31;elseCRC_Value = (CRC_Value << 1);}}return CRC_Value;
}
System.c
系统运行函数中实现串口打印以及数码管显示温湿度值
/*
* @name Run
* @brief 系统运行
* @param None
* @retval None
*/
static void Run()
{float Temp_float = 0;uint16_t Temp_uint = 0;//调用SHT30周期检测函数SHT30.Measure_Period_Mode();//串口打印温湿度printf("温度:%.1f度\r\n",SHT30.fTemperature);printf("湿度:%d%%RH\r\n\r\n",SHT30.ucHumidity);//判断温度正负if(SHT30.fTemperature < 0){Temp_float = 0 - SHT30.fTemperature;Display.Disp_Other(Disp_NUM_4,0x40,Disp_DP_OFF);}else{Temp_float = SHT30.fTemperature;Display.Disp_Other(Disp_NUM_4,0x00,Disp_DP_OFF);}//显示温度Temp_uint = (uint16_t)(Temp_float*10); //将温度值乘以10,显示小数点后一位Display.Disp_Hex(Disp_NUM_3,Temp_uint/100,Disp_DP_OFF); //显示十位Display.Disp_Hex(Disp_NUM_2,Temp_uint%100/10,Disp_DP_ON); //显示个位,开启小数点Display.Disp_Hex(Disp_NUM_1,Temp_uint%10,Disp_DP_OFF); //显示小数点后一位//显示湿度Display.Disp_Hex(Disp_NUM_6,SHT30.ucHumidity/10,Disp_DP_OFF);Display.Disp_Hex(Disp_NUM_5,SHT30.ucHumidity%10,Disp_DP_OFF);//延时HAL_Delay(500);
}
实验效果
串口打印
数码管显示
STM32物联网项目-SHT30温湿度采集(IIC通信)相关推荐
- stm32 hal库 AS5600磁编码器IIC通信读取角度
stm32 hal库 AS5600磁编码器IIC通信读取角度 下载
- STM32物联网项目-RS485通信(Modbus协议)
RS485通信(Modbus协议) 协议介绍 RS485介绍:http://t.csdn.cn/bOuFX Modbus协议:http://t.csdn.cn/mgioX CubeMX配置 RS-48 ...
- STM32物联网项目-GPRS模块通信编程
GPRS模块通信-编程 实验目的 32单片机通过串口2发送AT指令控制SIM800C检测GPRS网络,连接TCP服务器,连接服务器成功后,通过Doit.am远程信息转发服务将上传至公网服务器的温湿度值 ...
- STM32物联网项目-通过ESP12S模块连接TCP服务器
通过ESP12S模块连接TCP服务器 可参考STC15实战的WiFi通信:http://t.csdn.cn/Aw0Uc ESP-12S模块 引脚功能定义 实验目标 STM32通过串口与ESP-12S模 ...
- STM32之IIC通讯-SHT30温湿度采集
一.实验目的:通过单片机普通IO口,模拟IIC时序,掌握IIC通讯协议. 二.实验用到的主控芯片:STM32F103RCT6,IIC通讯引脚IIC_SDA:PC11,IIC_SCL:PC12 三.SH ...
- STM32物联网项目-ADC采集实验板板温度(NTC热敏电阻)
STM32 ADC采集板载温度 STM32 ADC简介 STM32 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立使用, 也可以使用双重模 ...
- STM32物联网项目-SPI FLASH编程
SPI编程--读写Flash芯片(W25Q64JV) FLASH芯片介绍--W25Q64JV W25Q64JV的芯片手册是英文的,用软件翻译了一下,有些地方翻译得不准确,大概了解一下即可,例如芯片的工 ...
- STM32物联网项目-HMI串口屏
HMI串口屏实验 串口屏 屏幕使用的是淘晶池的串口屏,显示内容可以通过官方上位机来编辑,屏幕学习平台:http://wiki.tjc1688.com/doku.php?id=start 通信原理:屏幕 ...
- STM32物联网项目-GPRS模块介绍
GPRS模块 SIM800C模块介绍 SIM800C模块可支持4频GSM/GPRS,工作的频段为:GSM850.EGSM900.DCS1800和PCS1900 MHz. 模块的尺寸只有17.6 * 1 ...
最新文章
- shell 查看磁盘和当前文件夹所有大小
- ajax php 返回数组并父子给变量,将字符串变量从PHP发送回数组变量的ajax ...?
- adb刷入第三方recovery_橙狐Recovery一款另类功能丰富的第三方刷机工具支持MIUI OTA...
- DataTable筛选某列最大值
- MFC开发IM-第二十七篇、如何引入acl,解决Json解析问题
- BASE64Encoder
- HTTP协议详细介绍~超详细
- 不当IT民工——技术带来质的飞跃
- 攻击银行内网,黑客只要三步
- [转]Ribbon界面介绍(1)
- 计算机主板用料,【技嘉H55评测】主板供电篇——CPU辅助电源-中关村在线
- 如何快速实现微信账号的注销,福利在这里,怎样快速注销微信账号
- 怎样赚钱?互联网赚钱才是草根最好的方式!
- mysql的binlog开启方式,查看方式.三种binlog模式介绍.以及使用binlog恢复数据.删除binlog
- 英国Foresight太阳能基金卖股集资 投资200MW光伏项目
- 如何用Qt抠一个圆形头像出来
- 六十星系之23贪狼独坐辰戌
- 前端通过序列帧实现动画
- 单相全波整流电路以及子系统封装
- 阿里天池比赛快速入门