datasheet

使用STM32F103采集Si7021温湿度传感器数据

2019-07-11来源: eefocus关键字:STM32F103  Si7021  温湿度传感器

一、传感器电路连接


Si7021的外围电路非常简单,如图1所示:

图1    Si7021传感器外围电路


Si7021采用的是IIC接口,最高支持400KHz的通信速率,0~100%RH的湿度量程和最大-40℃~+125℃的温度量程,150μA低功耗,超小体积。可提供精确,低功耗,工厂校准的数字解决方案,适用于测量湿度,露点和温度,适用于从HVAC / R和资产跟踪到工业和消费者平台的各种应用。


二、时序和协议分析


首先看看Si7021的IIC通信时序,图2展示了Si7021的IIC时序图和各个时序时间的参数表。



图2    传感器IIC通信时序


其实这个IIC时序我个人认为没啥特别的,感觉就是一个比较常见的通信时序。


不过,这个传感器在读写协议上有个比较特殊的也是我有点搞不懂的地方。它的IIC读写其实是有两个模式的,一个叫保持主模式(Hold Master Mode),另一个叫无保持主模式(No Hold Master Mode),这两种模式又分别有两种测量指令相对应。


按照数据手册的说法,无保持主模式下在从机应答了测量指令后,主机要重新发送一次起始信号Sr,然后连续发送三次从机地址之后开才始读取数据;而在保持主模式下,传感器应答主机的读指令之后从机会把时钟线SCL强制拉高,直到温湿度转换完成。图3和图4分别为Si7021无保持主模式和保持主模式下的IIC读写协议。



图3    无保持主模式读写协议



图4    保持主模式读写协议


这个读写协议我就有点看不懂了,而且最尴尬的是,按照手册上的无保持主模式读写根本读不出数据,全是0xFF,而且不知道是不是我的驱动有问题,用保持主模式的时候拿逻辑分析仪测信号,发现SCL也并没有强制拉高。最后实在没办法,就用了无保持的测量指令,然后在STM32等到ACK之后延时20ms再读数据,才正常的。但是这样又跟数据手册说的完全不一样了。


反正当时真是把我给搞懵逼了,还请各位大佬能点拨指导一下。


三、测量程序编写


既然已经能读到数据了,那就直接开始编写测量程序好了。我的测量代码的底层IIC驱动代码是借鉴的正点原子的例程,温湿度计算部分参考了这篇博客:家庭IOT监测之温湿度SI7021及上传ONENET


首先是IO口的初始化,我使用了PB8(SCL)和PB9(SDA)。


void IIC_Init(void)//IIC初始化

{      

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;//PB8->SCL, PB9->SDA

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

 

IIC_SCL=1;//初始电平设为高

IIC_SDA=1;

}

 


然后是多字节读取传感器函数:


 


//函数名称:Multiple_read_Si7021

//函数功能:多字节读取传感器

//参数描述:

//返 回 值:

void Multiple_read_Si7021(u8 REG_address, u16 *value)

{

u8 Si7021_BUF[2]={0};//缓存数组定义

IIC_Start();//IIC起始信号

IIC_Send_Byte((SLAVE_ADDR<<1)|0);//将7位器件地址左移一位再加上一位写操作

IIC_Wait_Ack();//等待应答

IIC_Send_Byte(REG_address);

IIC_Wait_Ack();//等待应答

delay_ms(19);//等待温湿度转换完成,至少应该大于18ms

IIC_Start();

IIC_Send_Byte((SLAVE_ADDR<<1)|1);//将7位器件地址左移一位再加上一位读操作

IIC_Wait_Ack();

Si7021_BUF[0] = IIC_Read_Byte(1);//读传感器高8位数据并发送应答信号

Si7021_BUF[1] = IIC_Read_Byte(0);//读传感器低8位数据并发送非应答信号

IIC_Stop();//停止信号

*value=((Si7021_BUF[0]<<8)+Si7021_BUF[1]);//将高低8位数据合成为16位数据

}

接着是温湿度测量函数:


//函数名称:measure_si7021

//函数功能:NO HOLD MASTER模式下读取温湿度 

//参数描述:无

//返 回 值:无

void measure_Si7021(void)

{

//缓存变量定义

u16 TEMP,HUMI;

u8 curI;

//读取温度

Multiple_read_Si7021(TEMP_NOHOLD_MASTER,&TEMP);//NOHOLD_MASTER模式下读取温度

si7021.temp=(((((float)TEMP)*175.72f)/65536.0f) - 46.85f);//将原始温度数据计算为实际温度数据并传递给缓存区,单位 ℃

// TEMP_buf=(((((float)TEMP)*175.72f)/65536.0f) - 46.85f);

Multiple_read_Si7021(HUMI_NOHOLD_MASTER,&HUMI);//NOHOLD_MASTER模式下读取湿度

si7021.humi=(((((float)HUMI)*125.0f)/65535.0f) - 6.0f);//将原始湿度数据计算为实际湿度数据并传递给缓存区,单位 %RH

// Humi_buf=(((((float)HUMI)*125.0f)/65535.0f) - 6.0f);

//下面其实是我抄的机智云智能宠物屋温湿度测量的一个平均值滤波算法,循环储存10次的数据,调用一次measure_Si7021()就存一次

if(MEAN_NUM > si7021_filter.curI)//当MEAN_NUM==10时,完成10次读取

{

si7021_filter.tBufs[si7021_filter.curI] = si7021.temp;

si7021_filter.hBufs[si7021_filter.curI] = si7021.humi;

 

si7021_filter.curI++;

}

else

{

si7021_filter.curI = 0;

 

si7021_filter.tBufs[si7021_filter.curI] = si7021.temp;

si7021_filter.hBufs[si7021_filter.curI] = si7021.humi;

 

si7021_filter.curI++;

}

if(MEAN_NUM <= si7021_filter.curI) 

    {

        si7021_filter.thAmount = MEAN_NUM;

    }

 

//判断是否初次循环

    if(0 == si7021_filter.thAmount) 

    {

        //计算采集第10次数据之前的平均值

        for(curI = 0; curI < si7021_filter.curI; curI++)

        {

            si7021.temp += si7021_filter.tBufs[curI];

            si7021.humi += si7021_filter.hBufs[curI];

        }

 

        si7021.temp = si7021.temp / si7021_filter.curI;

        si7021.humi = si7021.humi / si7021_filter.curI; 

        

        TEMP_buf = si7021.temp;

        Humi_buf = si7021.humi;

    }

    else if(MEAN_NUM == si7021_filter.thAmount) 

    {

        //计算采集第10次数据之后的平均值

        for(curI = 0; curI < si7021_filter.thAmount; curI++) 

        {

            si7021.temp += si7021_filter.tBufs[curI];

            si7021.humi += si7021_filter.hBufs[curI];

        }

 

        si7021.temp = si7021.temp / si7021_filter.thAmount; 

        si7021.humi = si7021.humi / si7021_filter.thAmount; 

        

        TEMP_buf = si7021.temp; 

        Humi_buf = si7021.humi; 

    }

}

最后,主函数每50ms调用一次测量函数,但每隔1s才发送一次数据给串口:


#include "delay.h"

#include "sys.h"

#include "usart.h"

#include "Si7021.h"

 

int main(void)

{

    u8 i=0;

 

delay_init(); //延时函数初始化

uart_init(115200); //串口1初始化波特率为115200

IIC_Init(); //IIC初始化 

 

 

while(1)

{ //每50ms读取一次数据

measure_Si7021();

 

 

i++;

delay_ms(50);

if(i==20)

{ //串口每1s打印一次数据

printf("rnTemp:%.2frn",TEMP_buf);//打印温度数据,保留两位小数

printf("Humi:%.2frn",Humi_buf);//打印湿度数据,保留两位小数

i=0;

}

}

}

delay_init(); //延时函数初始化

uart_init(115200); //串口1初始化波特率为115200

IIC_Init(); //IIC初始化 



while(1)

{ //每50ms读取一次数据

measure_Si7021();



i++;

delay_ms(50);

if(i==20)

{ //串口每1s打印一次数据

printf("rnTemp:%.2frn",TEMP_buf);//打印温度数据,保留两位小数

printf("Humi:%.2frn",Humi_buf);//打印湿度数据,保留两位小数

i=0;

}

}

}


关键字:STM32F103  Si7021  温湿度传感器

编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic467481.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:零知开源分享- 温湿度模块DHT11的使用
下一篇:STM32驱动DHT22温湿度传感器程序

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

解决stm32f103通过stlink不能烧录程序问题

问题:   stm32(stm32f103c8T6)开发板只能通过串口烧录程序,而st—link居然不行描述:解决:st-link固件升级用stm32cubemx快速开发时没有配置好调试模式重新生成代码就可以了如果还是不行的话,就得升级一下stlink固件了,具体升级方法可百度
发表于 2019-07-19
解决stm32f103通过stlink不能烧录程序问题

STM32F4标准外设库模板工程建立与使用

<stdint.h>这个地方,然后在下面添加#include “arm_math.h”然后保存。ARM_MATH_CM4ARM_MATH_MATRIX_CHECKARM_MATH_ROUNDING__FPU_PRESENT__FPU_USED代码优化http://www.stmcu.org/module/forum/thread-603791-1-1.html网线热插拔http://blog.csdn.net/xukao5671927/article/details/77765464JTAG引脚复用STM32f1 中JTAG 引脚作为普通IO口设置方法以及STM32f4中的方法的不同在stm32f1中,我们对于不用
发表于 2019-07-19
STM32F4标准外设库模板工程建立与使用

STM32F1系列单片机USB外设相关寄存器的定义

Keil MDK网站上下载的Keil.STM32F1xx_DFP.2.2.0.pack包中的stm32f10x.h头文件里面没有USB_TypeDef的定义,只有寄存器位的定义,是不完整的头文件。没有USB的数据结构就会给访问USB寄存器带来一定的困难。虽然可以参照STM32参考手册中的USB register map自己编写出USB_TypeDef结构体,但是这样比较麻烦。不过,STM32CubeMX工具生成的STM32F103工程中的头文件stm32f103xe.h中就有完整的USB数据结构,该头文件的版本是V4.2.0,日期为31-March-2017,作者仍然是Keil里面的MCD Application Team
发表于 2019-07-19

STM32F103 DMA 通道对应的外设

今天在调试stm32f103的时候,使用串口1的RX对应DMA1通道5是正确的,但是当我调试调试到串口2的RX的时候依然在用原通道,完全忽略了芯片不同的外设所对应的DMA通道是不同的。 
发表于 2019-07-19
STM32F103 DMA 通道对应的外设

不同stm32f103芯片内部外设资源

由表可知,芯片内部的外设资源除了跟stm32f103后面的第一个字母有关外,还和flash的大小有关。上面的表中只有一部分,具体的可以参考Keil的芯片型号选择部分。下面是stm32f103c8t6的资源:  TIM1_BRK_IRQn               = 24,       TIM1_UP_IRQn                = 25,      
发表于 2019-07-19
不同stm32f103芯片内部外设资源

一种可行的STM32F103外设RTC使用方法

前言最近做的项目需要用RTC功能,记录掉上电时间。然后就开始琢磨STM32的RTC,在使用的过程中出现各种问题。搞的很是头痛。几经折腾,终于弄出一种稳定的使用方法。刚开始最大的问题就是掉电后时钟不走,代码改来该去,最后发现不管是第一次初始化还是每次上电运行,都需要打开PWR和BKP时钟。下面就把我的代码全贴出来,可以直接调用。代码#ifndef BSP_RTC_H#define BSP_RTC_H#include "stm32f10x.h"#include <time.h>//BCD码表示时间typedef struct systemtime_tag{    unsigned
发表于 2019-07-19

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved