温湿度设计V1.0——代码设计

前言

  1. 代码部分主要是两部分,HS3003的驱动代码和OLED显示屏的驱动代码。
  2. 程序基于标准库函数编写。

HS3003

简述

  1. HS3003数字传感器,可精准测量相对湿度和温度。通过标准I2C输出提供完全校正的相对湿度和温度值,内部带有校正和补偿,无需用户校准输出数据。
  2. 高精度,测量响应时间快,MEMS传感器具有专有的传感器级保护功能,确保高可靠性和长期稳定性。
  3. 相关参数
    在这里插入图片描述
  4. 芯片端口
    在这里插入图片描述
  5. 推荐操作性能
    HS300x系列传感器经过优化,可分别在10°C至50°C和20%RH至80%RH这两个更常见的温度和湿度范围内发挥最佳性能。如果在这些条件之外长时间运行,特别是在高湿度水平下,传感器可能会出现偏移。大多数情况下,这种偏移是暂时的,一旦传感器恢复到正常的温度和湿度条件,这种偏移就会逐渐消失。偏移量和偏移的持续时间取决于暴露的持续时间和相对湿度和温度条件的严重程度。
  6. 传感器从属地址
    HS300x系列的默认12C地址是44Hex。设备将只对这个7位地址作出响应。

芯片唤醒

  1. 出厂时,HS300x工厂编程运行在睡眠模式。在睡眠模式下,传感器在进行测量之前会等待来自主机的命令,仅在接收到测量请求命令(MR)时执行转换,否则始终处于断电状态。
  2. 当我们发送下面请求给芯片时,芯片就会被唤醒。
    在这里插入图片描述
//HS3003开始工作
int8_t HS3003_IIC_Start(uint8_t i2c_addr)
{   
	IIC_Start();  	
	IIC_Send_Byte(i2c_addr);  
	if(IIC_Wait_Ack()) 
        return -1;
	IIC_Stop( );
    return 0;
}
也就是我们发送 HS3003_IIC_Start(0x88); 即可唤醒芯片

读取数据

在这里插入图片描述

  1. 前8位是 7bit的设备地址位0x44读/写位,然后等待设备回应。
  2. 返回数据的第一个字节的两个MSB是状态位,也就是图片上的15和14,它反映检测数据是否是有效的还是过时的。 0表示数据采集完成,1表示没有完成有效采集。
  3. 注意:默认采样精度为14bit,这里不做修改。默认精度下的采样时间为33ms左右,所以在测量请求发出之后,需要等待33毫秒之后在读取。
    在这里插入图片描述
  4. 后面是14位的湿度数据,最后是14位的温度数据。对数据进行解析即可获取温湿度数据。
//数据读取
s_Hs300xDataType Hs300x_ReadData(void)
{
 
    uint8_t data[4];  
    uint32_t data_u32;
    s_Hs300xDataType humi_temp_t;
 
	HS3003_IIC_Read_Data(0x89,data,4);	//这里读取数据设备地址和读写位读取数据

    data_u32 = (uint32_t)((data[0] << 24U) | 
 
                          (data[1] << 16U) | 
 
                          (data[2] << 8U) | 
 
                          (data[3]));	//数据拆分
 
    // Read the temperature and hunidity
    (void)Hs300x_DataConvert(data_u32, &humi_temp_t);	//数据转换

    return humi_temp_t;	//返回数据
}

//数据转换用到的定义
#define HS300x_I2C_SLAVE_ADDR_7BIT           (0x44U)	//设备地址
#define HS300X_DATA_VALID                    (0x00U)	//有效数据状态位
#define HS300X_DATA_STALE                    (0x01U)	//无效数据状态位
//提取数据运算使用
#define HS300X_STATUS_MASK                   (0xC0000000U)	
#define HS300X_STATUS_POS                    (30U)
#define HS300X_DATA_MASK                     (0x3FFFFFFCU)
#define HS300X_HUMI_DATA_MASK                (0x3FFF0000U)
#define HS300X_HUMI_DATA_POS                 (16U)
#define HS300X_TEMP_DATA_MASK                (0x0000FFFCU)
#define HS300X_TEMP_DATA_POS                 (2U)

/* calculation formula, 2^14 - 1 */ 
#define HS300X_DATA_FACTOR                   (16383U)

//数据转换
static uint8_t Hs300x_DataConvert(uint32_t read_data, s_Hs300xDataType *cal_result)
{
    uint32_t humi_data;
    uint32_t temp_data;
    
    if (((read_data & HS300X_STATUS_MASK) >> HS300X_STATUS_POS) == HS300X_DATA_VALID)
    {
        // 提取状态位,表示数据有效
        humi_data = (read_data & HS300X_HUMI_DATA_MASK) >> HS300X_HUMI_DATA_POS;
        temp_data = (read_data & HS300X_TEMP_DATA_MASK) >> HS300X_TEMP_DATA_POS;

        // 计算湿度: humi_data/(2^14-1) * 100
        cal_result->humi = (double)humi_data/(double)(HS300X_DATA_FACTOR) * 100.0;
        // 计算温度: temp_data/(2^14-1) * 165 - 40
        cal_result->temp = (double)temp_data/(double)(HS300X_DATA_FACTOR) * 165.0 - 40;
        
        return 1;
    }
    else
    {
        return 0;
    }
}
  1. 最后运行显示函数
void HS3003_Run(void)
{
	Hs300x_StartSample();		//唤醒芯片
	delay_ms(40);				//循环采集时,必须要等到足够的时间才能采到有效数据
	humi_temp= Hs300x_ReadData();
	show();						//显示数据
}

OLED屏

  1. OLED显示屏使用0.96寸,4线的OLED。
  2. 使用硬件I2C驱动,因为上面采集芯片时使用的是模拟I2C,所以随便写一个硬件I2C。
//OLED.c
#include "oled.h"
#include "delay.h"
#include "codetab.h"
#include <stdio.h>
#include <string.h>

void I2C_Configuration(void)
{
	I2C_InitTypeDef  I2C_InitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure; 

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

	/*STM32F103C8T6芯片的硬件I2C: PB6 -- SCL; PB7 -- SDA */
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//I2C必须开漏输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	I2C_DeInit(I2C1);//使用I2C1
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主机的I2C地址,随便写的
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = 400000;//400K

	I2C_Cmd(I2C1, ENABLE);
	I2C_Init(I2C1, &I2C_InitStructure);
}

void I2C_WriteByte(uint8_t addr,uint8_t data)
{
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
	
	I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/

	I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	I2C_SendData(I2C1, addr);//寄存器地址
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_SendData(I2C1, data);//发送数据
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	
	I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
}

void WriteCmd(unsigned char I2C_Command)//写命令
{
	I2C_WriteByte(0x00, I2C_Command);
}

void WriteDat(unsigned char I2C_Data)//写数据
{
	I2C_WriteByte(0x40, I2C_Data);
}

void OLED_Init(void)
{
	I2C_Configuration();
	delay_ms(100); //这里的延时很重要
	
	WriteCmd(0xAE); //display off
	WriteCmd(0x20);	//Set Memory Addressing Mode	
	WriteCmd(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8);	//Set COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //亮度调节 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	WriteCmd(0xa6); //--set normal display
	WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	WriteCmd(0xd3); //-set display offset
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	WriteCmd(0xd9); //--set pre-charge period
	WriteCmd(0x22); //
	WriteCmd(0xda); //--set com pins hardware configuration
	WriteCmd(0x12);
	WriteCmd(0xdb); //--set vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--set DC-DC enable
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel
	OLED_CLS();
}

void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{ 
	WriteCmd(0xb0+y);
	WriteCmd(((x&0xf0)>>4)|0x10);
	WriteCmd((x&0x0f)|0x01);
}

void OLED_Fill(unsigned char fill_Data)//全屏填充
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		WriteCmd(0xb0+m);		//page0-page1
		WriteCmd(0x00);		//low column start address
		WriteCmd(0x10);		//high column start address
		for(n=0;n<128;n++)
			{
				WriteDat(fill_Data);
			}
	}
}

void OLED_CLS(void)//清屏
{
	OLED_Fill(0x00);
}

//--------------------------------------------------------------
// Prototype      : void OLED_ON(void)
// Calls          : 
// Parameters     : none
// Description    : 将OLED从休眠中唤醒
//--------------------------------------------------------------
void OLED_ON(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X14);  //开启电荷泵
	WriteCmd(0XAF);  //OLED唤醒
}

//--------------------------------------------------------------
// Prototype      : void OLED_OFF(void)
// Calls          : 
// Parameters     : none
// Description    : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X10);  //关闭电荷泵
	WriteCmd(0XAE);  //OLED休眠
}

//--------------------------------------------------------------
// Prototype      : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
// Calls          : 
// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16)
// Description    : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
//--------------------------------------------------------------
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
	unsigned char c = 0,i = 0,j = 0;
	switch(TextSize)
	{
		case 1:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 126)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
					WriteDat(F6x8[c][i]);
				x += 6;
				j++;
			}
		}break;
		case 2:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 120)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i]);
				OLED_SetPos(x,y+1);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i+8]);
				x += 8;
				j++;
			}
		}break;
	}
}

//--------------------------------------------------------------
// Prototype      : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
// Calls          : 
// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引
// Description    : 显示codetab.h中的汉字,16*16点阵
//--------------------------------------------------------------
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
	OLED_SetPos(x,y + 1);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
}

//--------------------------------------------------------------
// Prototype      : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
// Calls          : 
// Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
// Description    : 显示BMP位图
//--------------------------------------------------------------
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
	unsigned int j=0;
	unsigned char x,y;

  if(y1%8==0)
		y = y1/8;
  else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
		{
			WriteDat(BMP[j++]);
		}
	}
}

char ch1[20]={};
char ch2[20]={};
char ch1_E[]={"C"};
char ch2_E[]={"%"};
void show(void)
{
	memset(ch1,0,sizeof(ch1));
	sprintf(ch1,"%.2f",humi_temp.temp);
	strncat(ch1,ch1_E,1);
	memset(ch2,0,sizeof(ch2));
	sprintf(ch2,"%.2f",humi_temp.humi);
	strncat(ch2,ch2_E,1);
	
	/* 温度报警系统 */
    OLED_ShowCN(16,0,2);OLED_ShowCN(32,0,3);OLED_ShowCN(48,0,4);OLED_ShowCN(64,0,41);OLED_ShowCN(80,0,42);
	/* 当前温度 */	
	OLED_ShowCN(0,2,47); OLED_ShowCN(16,2,48);OLED_ShowCN(32,2,2);OLED_ShowCN(48,2,4); OLED_ShowStr(72,2,(unsigned char *)ch1,2);
	/* 当前湿度 */
	OLED_ShowCN(0,4,47); OLED_ShowCN(16,4,48);OLED_ShowCN(32,4,3);OLED_ShowCN(48,4,4); OLED_ShowStr(72,4,(unsigned char *)ch2,2);
}
//OLED.h
#ifndef __OLED_H
#define __OLED_H

#include "stm32f10x.h"
#include "HS3003.h"

#define OLED_ADDRESS	0x78 //通过调整0R电阻,屏可以0x78和0x7A两个地址 -- 默认0x78

extern s_Hs300xDataType humi_temp;

void I2C_Configuration(void);
void I2C_WriteByte(uint8_t addr,uint8_t data);
void WriteCmd(unsigned char I2C_Command);
void WriteDat(unsigned char I2C_Data);
void OLED_Init(void);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char fill_Data);
void OLED_CLS(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize);
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);
void OLED_progress_bar(unsigned char y0,unsigned char q);
void show(void);
#endif

  • 19
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值