前言
- 代码部分主要是两部分,HS3003的驱动代码和OLED显示屏的驱动代码。
- 程序基于标准库函数编写。
HS3003
简述
- HS3003数字传感器,可精准测量相对湿度和温度。通过标准I2C输出提供完全校正的相对湿度和温度值,内部带有校正和补偿,无需用户校准输出数据。
- 高精度,测量响应时间快,MEMS传感器具有专有的传感器级保护功能,确保高可靠性和长期稳定性。
- 相关参数
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ce56475348611afbd8372733b5964bcf.png)
- 芯片端口
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/442de9814267c785aafc1ff1dca2b15d.png)
- 推荐操作性能
HS300x系列传感器经过优化,可分别在10°C至50°C和20%RH至80%RH这两个更常见的温度和湿度范围内发挥最佳性能。如果在这些条件之外长时间运行,特别是在高湿度水平下,传感器可能会出现偏移。大多数情况下,这种偏移是暂时的,一旦传感器恢复到正常的温度和湿度条件,这种偏移就会逐渐消失。偏移量和偏移的持续时间取决于暴露的持续时间和相对湿度和温度条件的严重程度。 - 传感器从属地址
HS300x系列的默认12C地址是44Hex。设备将只对这个7位地址作出响应。
芯片唤醒
- 出厂时,HS300x工厂编程运行在睡眠模式。在睡眠模式下,传感器在进行测量之前会等待来自主机的命令,仅在接收到测量请求命令(MR)时执行转换,否则始终处于断电状态。
- 当我们发送下面请求给芯片时,芯片就会被唤醒。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/92bdb011419968f0eb317653d007a9ad.png)
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); 即可唤醒芯片
读取数据
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/04130d900eaa442adb4c627210140e5a.png)
- 前8位是 7bit的设备地址位0x44 和 读/写位,然后等待设备回应。
- 返回数据的第一个字节的两个MSB是状态位,也就是图片上的15和14,它反映检测数据是否是有效的还是过时的。 0表示数据采集完成,1表示没有完成有效采集。
- 注意:默认采样精度为14bit,这里不做修改。默认精度下的采样时间为33ms左右,所以在测量请求发出之后,需要等待33毫秒之后在读取。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4b07f09e42a66dc0d1b152e21d5ef24e.png)
- 后面是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]));
(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)
#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;
cal_result->humi = (double)humi_data/(double)(HS300X_DATA_FACTOR) * 100.0;
cal_result->temp = (double)temp_data/(double)(HS300X_DATA_FACTOR) * 165.0 - 40;
return 1;
}
else
{
return 0;
}
}
- 最后运行显示函数
void HS3003_Run(void)
{
Hs300x_StartSample();
delay_ms(40);
humi_temp= Hs300x_ReadData();
show();
}
OLED屏
- OLED显示屏使用0.96寸,4线的OLED。
- 使用硬件I2C驱动,因为上面采集芯片时使用的是模拟I2C,所以随便写一个硬件I2C。
#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);
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;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x30;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;
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);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);
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);
}
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);
WriteCmd(0x20);
WriteCmd(0x10);
WriteCmd(0xb0);
WriteCmd(0xc8);
WriteCmd(0x00);
WriteCmd(0x10);
WriteCmd(0x40);
WriteCmd(0x81);
WriteCmd(0xff);
WriteCmd(0xa1);
WriteCmd(0xa6);
WriteCmd(0xa8);
WriteCmd(0x3F);
WriteCmd(0xa4);
WriteCmd(0xd3);
WriteCmd(0x00);
WriteCmd(0xd5);
WriteCmd(0xf0);
WriteCmd(0xd9);
WriteCmd(0x22);
WriteCmd(0xda);
WriteCmd(0x12);
WriteCmd(0xdb);
WriteCmd(0x20);
WriteCmd(0x8d);
WriteCmd(0x14);
WriteCmd(0xaf);
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);
WriteCmd(0x00);
WriteCmd(0x10);
for(n=0;n<128;n++)
{
WriteDat(fill_Data);
}
}
}
void OLED_CLS(void)
{
OLED_Fill(0x00);
}
void OLED_ON(void)
{
WriteCmd(0X8D);
WriteCmd(0X14);
WriteCmd(0XAF);
}
void OLED_OFF(void)
{
WriteCmd(0X8D);
WriteCmd(0X10);
WriteCmd(0XAE);
}
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;
}
}
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;
}
}
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);
}
#ifndef __OLED_H
#define __OLED_H
#include "stm32f10x.h"
#include "HS3003.h"
#define OLED_ADDRESS 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