简介
本项目是工作中做的一个便携式手持检测仪项目,集成了自家公司的HCHO,TVOC传感器,买的sht30温湿度传感器,基本功能是能通过集成的传感器检测温湿度信息,空气中甲醛含量,TVOC含量,能通过厂家定制的段码屏显示这些信息和电池电量,能通过按键控制屏幕亮度,短按亮度变暗,长按关闭屏幕。基本功能框图如下:
本文将分模块对相应功能进行介绍。
SHT30温湿度介绍
SHT30是I2C接口的高精度温湿度传感器
I2C
I2C是常见的通讯协议,其基本的介绍见之前写的博文I2C知识点小结,在stm32中,有通过GPIO口模拟I2C的用法,有使用库函数的硬件I2C用法(据说库函数硬件I2C有些问题),此处对模拟I2C的基本函数进行介绍,代码如下:
/*********************************I2C.h***************************************/
//IO方向设置,操控寄存器
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
//IO输出电平操作,位段操作
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
/*********************************以下是I2C.c***************************************/
1.初始化I2C,使用GPIO口PB6,PB7来模拟I2C
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 输出高
}
2.产生I2C起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
3.产生I2C停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
4.等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
5.产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
6.不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
7.IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
//IIC_SDA=(txd&0x80)>>7;
if((txd&0x80)>>7)
IIC_SDA=1;
else
IIC_SDA=0;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
- 读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
SHT30
相关函数如下
1.初始化
void SHT3X_Init(void)
{
IIC_Init();
}
2.写命令
//参数一 SHT30地址
//参数二 命令
void SHT3X_WriteCMD( u8 add ,u16 cmd)
{
IIC_Start();
IIC_Send_Byte(add);
IIC_Wait_Ack();
IIC_Send_Byte(cmd>>8);
IIC_Wait_Ack();
IIC_Send_Byte(cmd);
IIC_Wait_Ack();
IIC_Stop();
}
3.读结果
//参数一 SHT30地址
//参数二 命令
//参数三 数组,存放从SHT30读取的字节
void SHX3X_ReadResults(u8 add,u16 cmd, u8 *p)
{
IIC_Start();
IIC_Send_Byte(add); //0x8a,0x88
IIC_Wait_Ack();
IIC_Send_Byte(cmd>>8);
IIC_Wait_Ack();
IIC_Send_Byte(cmd);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(add+1);
IIC_Wait_Ack();
p[0]=IIC_Read_Byte(1);
p[1]=IIC_Read_Byte(1);
p[2]=IIC_Read_Byte(1);
p[3]=IIC_Read_Byte(1);
p[4]=IIC_Read_Byte(1);
p[5]=IIC_Read_Byte(0);
IIC_Stop();
}
4.计算温度
//参数 从SHT30读取的表示温度值的16位数据
float SHT3X_CalcTemperature(uint16_t rawValue)
{
float temp;
temp=(175 * (float)rawValue / 65535 - 45) ; // T = -45 + 175 * rawValue / (2^16-1)
return temp;
}
5.计算湿度
//参数 从SHT30读取的表示湿度值的16位数据
float SHT3X_CalcRH(uint16_t rawValue)
{
// calculate relative humidity [%RH]
float temp1 = (100 * (float)rawValue / 65535) ; // RH = rawValue / (2^16-1) * 10
return temp1;
}
6.获取温湿度
//参数 SHT30地址
void SHT_GetValue(u8 add)
{
u8 temp = 0;
u16 dat;
u8 p[3];
SHX3X_ReadResults(add ,0xE000, buffer);
p[0] = buffer[0];
p[1] = buffer[1];
p[2] = buffer[2];
if(!temp)
{
dat = ((u16)buffer[0] << 8) | buffer[1];
Tem_Value = SHT3X_CalcTemperature( dat );
}
p[0] = buffer[3];
p[1] = buffer[4];
p[2] = buffer[5];
if(!temp)
{
dat = ((u16)p[0] << 8) | p[1];
RH_Value = SHT3X_CalcRH( dat );
}
}
7main函数
int main
{
SHT3X_Init(); //SHT30初始化
SHT3X_WriteCMD(0x88,0x2236); //发送周期性读数据命令
delay_ms(100);
SHT_GetValue(0x88); //获取温湿度值
printf("%.4f",Tem_Value);
printf(" %.4f",RH_Value);
}
SHT30使用注意事项:
(1)SHT30地址
上图是数据手册关于地址的一部分内容:从手册可以看出当芯片ADDR接低电平时,表示地址字节为0x44,ADDR接高时,表示地址字节为0X45,且地址字节的高七位才是真正的地址(不知道是否是叙述问题,反正此处需要将该字节左移移位),我接的低所以地址字节为0x44,左移一位,代码里面实际用的地址字节就变成了0x88.
2.读命令
看手册知道,读取分为单次读取和周期性读取,我选择的是周期性读取,所以命令字节为0XE000
3.数据存储
从上面这个截图可以知道,读取一次返回六个字节,前两个字节表示温度,第三和第六个字节表示CRC校验,第四第五表示湿度,所以我定义了buf[6]来存放数据。
4.转换公式
温湿度转换公式从手册得来。
(未完待续。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。)