一、简介
GZP6877D 型压力传感器采用 SOP6 封装形式,倒钩管的设计可以保证安装的密封性。内有封装的压力传感器与信号调理芯片,对传感器的偏移、灵敏度、温漂和非线性进行数字补偿。采用 24 位 ADC,并且调理芯片内置温度传感器,可以输出高精度的压力值和温度值。同时提供 IIC 通讯协议接口,抗干扰能力强。所有测量数据都经过充分校准和温度补偿。
- 测量范围-100kPa…0~0.5kPa…1000kPa
- 表压型、气嘴带防脱结构
- 电源电压: 2.5V~5.5V
- 适用于无腐蚀性的气体
- IIC 输出
I2C 总线使用 SCL 和 SDA 作为信号线,这两根线都通过上拉电阻(典型值 4.7K)连接到 VDD,不通信时都保持为高电平。I2C 设备地址为 0x6D。
GZP6877D芯片数据手册:https://atta.szlcsc.com/upload/public/pdf
二、寄存器操作
1.寄存器描述
(1)Reg0x06—Reg0x08:压力数据寄存器
(2)Reg0x09—Reg0x0A:温度数据寄存器
(3)Reg0x30:测量命令寄存器
Bit:<2:0>
000:单次温度采集模式。
001:单次传感器压力信号采集模式。(使用此模式之前需要先读取温度,以获取温度校准系数,否则读数不准)
010:组合采集模式(一次温度采集后立即进行一次传感器压力信号采集)。
011,休眠工作模式(定期的执行一次组合采集模式,间隔时间由‘sleep_time’决定)
Sco:<3>:数据采集完成标志位。1–开始数据采集;0–采集结束(休眠工作模式除外)。
Sleep_time<7:4>:0001:62.5ms, 0010:125ms … 1111: 1s, 0000:无意义。(仅在休眠工作模式下有效)
(4)Reg0xA5:
Aout_config<7:4>:模拟输出配置(建议保留默认配置)
LDO_config:内部 LDO 配置。0,配置成 1.8V;1,配置成 3.6V
Unipolar:0,ADC 原始数据以有符号数格式输出;1: ADC 原始数据以无符号格式输出。
Data_out_control:0,输出校准数据;1,输出 ADC 原始数据(默认配置为 0)
Diag_on:0,关闭诊断功能;1,开启诊断功能(默认开启)
(5)Reg0xA6
Input Swap:在传感器内部交换差分信号极性。
Gain_P<5:3>:采集传感器信号时 PGA 增益,000:增益=1X。001:增益=2X。010:增益=4X。011:增益=8X。100: 增益=16X。101:增益=32X。110: 增益=64X。111:增益=128X。
OSR_P<2:0>:采集传感器信号时的过采样,000:1024X, 001:2048X, 010:4096X, 011:8192X,100:256X, 101:512X,110:16384X, 111:32768X。
2.工作模式说明
(1)组合数据采集模式:设置‘measurement_control’=010 和‘sco’=1 进入组合数据采集模式。
芯片上电后先后进行一次温度数据采集和一次传感器数据采集,完成后回到待机模式,并自动将‘sco’置 0。在组合采集模式下,“Data_out_control”寄存器必须设置为 0,校准后的温度数据储存在 0x09~0x0A 寄存器,压力数据储存在 0x06~0x08 寄存器。
组合模式读取数据按照如下指令顺序进行操作:
- 发送指令 0x0A 到 0x30 寄存器进行一次温度采集,一次压力数据采集。
- 读取 0x30 寄存器地址,若Sco位为0代表采集结束,可以读取数据。或等待延迟10ms。
- 读取 0x06、0x07、0x08 三个寄存器地址数据构成 24 位 AD 值(压力数据 AD 值),读取 0x09、0x0A 两个寄存器地址数据构成 16 位 AD 值(温度数据 AD 值)
- 按以下公式换算成实际压力、温度值。
(2)休眠数据采集模式
设置‘measurement_control’=011 和‘sco’=1 进入休眠数据采集模式。芯片上电后,以一定的时间间隔进行一次温度数据采集和一次传感器数据采集,间隔时间由’sleep_time’ 设置,范围为 62.5ms 到 1s。除非手动将‘sco’置 0,不然不会停止采集。在休眠数据采集模式下‘Data_out_control’必须设置为 0,校准后的温度数据储存在 0x09~0x0A 寄存器,压力数据储存在 0x06~0x08 寄存器。
3.温度和压力值换算公式
(1)最高位为“0”代表正压/正温度:
压力:Pressure = Pressure_ ADC / k
温度:Temperature = Temp_ ADC / 256
(2)最高位为“1”代表负压/负温度:
压力:Pressure = (Pressure_ADC - 16777216) / k
温度:Temperature = (Temp_ADC - 65536) / 256
PS:传感器校准后的输出可视为当前实际压力值(±1%Span);传感器校准后的输出:单位 Pa(默认),若要显示其他单位,可在换算公式里输入相应的系数进行换算;
关于上述压力 ADC 换算公式中 k 值的选取可参照下表:
量程 P 为测量区间的最大值,比如,测量-30~80kpa,P=80kpa,k 值为 64。
三、硬件IIC通信
一般硬件IIC的通信速率更快,更简单,大部分可以选择使用硬件IIC,如果由于硬件IIC不够使用,可以使用软件IIC进行替代。
1.初始化配置
(1)需要先打开图形界面配置的I2C驱动:
(2)在board.h中添加一下代码进行初始化。
/** if you want to use i2c bus(soft simulate) you can use the following instructions.
*
* STEP 1, open i2c driver framework(soft simulate) support in the RT-Thread Settings file
*
* STEP 2, define macro related to the i2c bus
* such as #define BSP_USING_I2C1
*
* STEP 3, according to the corresponding pin of i2c port, modify the related i2c port and pin information
* such as #define BSP_I2C1_SCL_PIN GET_PIN(port, pin) -> GET_PIN(C, 11)
* #define BSP_I2C1_SDA_PIN GET_PIN(port, pin) -> GET_PIN(C, 12)
*/
/*#define BSP_USING_I2C1*/
#ifdef BSP_USING_I2C1
#define BSP_I2C1_SCL_PIN GET_PIN(port, pin)
#define BSP_I2C1_SDA_PIN GET_PIN(port, pin)
#endif
#define BSP_USING_I2C2
#ifdef BSP_USING_I2C2
#define BSP_I2C2_SCL_PIN GET_PIN(F, 1)
#define BSP_I2C2_SDA_PIN GET_PIN(F, 0)
#endif
(3)在board.c中添加:void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)来初始化IIC。
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (hi2c->Instance == I2C2)
{
__HAL_RCC_GPIOF_CLK_ENABLE();
/**I2C2 GPIO Configuration
PF0 ------> I2C2_SDA
PF1 ------> I2C2_SCL
*/
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C2_CLK_ENABLE();
}
}
(4)在是他们2fxxx_hal_conf.h中添加如下的宏定义
(5)GZP6877.h文件
#ifndef APPLICATIONS_GZP6877_H_
#define APPLICATIONS_GZP6877_H_
#include <drv_common.h>
#include <stdio.h>
/**====================================================###### 宏定义 ######==================================================*/
#define GZP6877_WRITE_BIT 0x00 // 硬件I2C写标志
#define GZP6877_READ_BIT 0x01 // 硬件I2C读标志
#define GZP6877_SLAVE_ADDR 0x6D // 设备地址
#define GZP6877_WRITE_ADDR ((GZP6877_SLAVE_ADDR << 1) | GZP6877_WRITE_BIT)
#define GZP6877_READ_ADDR ((GZP6877_SLAVE_ADDR << 1) | GZP6877_READ_BIT)
#define GZP6877_DATA_MSB_ADDR 0x06 // 气压高地址
#define GZP6877_DATA_CSB_ADDR 0x07 // 气压中地址
#define GZP6877_DATA_LSB_ADDR 0x08 // 气压低地址
#define GZP6877_TEMP_MSB_ADDR 0x09 // 温度高地址
#define GZP6877_TEMP_LSB_ADDR 0x0A // 温度低地址
#define GZP6877_CMD_ADDR 0x30 // 测量命令寄存器
#define GZP6877_ONE_TEMP_CMD 0x08 // 单次温度采集模式
#define GZP6877_ONE_PRESS_CMD 0x09 // 单次采集传感器压力信号
#define GZP6877_COMBINED_COM 0x0A // 组合采集模式
#define GZP6877_PRE_LIMIT 8388606 // 气压界限
#define GZP6877_PRE_ADJUST 16777216 // 气压校准值
#define GZP6877_K_VALUE 8 // 气压K值
#define GZP6877_TEMP_LIMIT 32768 // 温度界限
#define GZP6877_TEMP_ADJUST 65536 // 温度校准值
#define GZP6877_TEMP_K 256 // 温度K值
I2C_HandleTypeDef hi2c2;
extern void GZP6877_I2C2_Init(void);
extern void GZP6859D_ReadSingleModePressureData(uint32_t *pPressure);
extern void GZP6859D_ReadSingleModeTempData(float *pTemperature);
extern void GZP6859D_ReadCombinedModeData(float *pTemperature, uint32_t *pPressure);
/**====================================================####### END #######=================================================*/
#endif /* APPLICATIONS_GZP6877_H_ */
(6)GZP6877.c文件
#include "GZP6877.h"
/**
* @breif GZP6877的I2C初始化
*/
void GZP6877_I2C2_Init(void)
{
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed = 100000;
hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief 单次模式读取压力数据
* @param pPressure -[out] 压力值,单位为Pa
*/
void GZP6859D_ReadSingleModePressureData(uint32_t *pPressure)
{
uint8_t cmd = GZP6877_ONE_PRESS_CMD;
uint8_t result = 0;
uint8_t pressArr[3] = {0};
uint32_t press = 0;
// 进行单次传感器压力信号采集模式
HAL_I2C_Mem_Write(&hi2c2, GZP6877_WRITE_ADDR, GZP6877_CMD_ADDR, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 10);
// 采集结束
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_CMD_ADDR, I2C_MEMADD_SIZE_8BIT, &result, 1, 10);
rt_kprintf("result:0x%02X ", result);
// 获取压力数据AD值
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_DATA_MSB_ADDR, I2C_MEMADD_SIZE_8BIT, &pressArr[0], 1, 10);
rt_kprintf("0x%02X ", pressArr[0]);
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_DATA_CSB_ADDR, I2C_MEMADD_SIZE_8BIT, &pressArr[1], 1, 10);
rt_kprintf("0x%02X ", pressArr[1]);
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_DATA_LSB_ADDR, I2C_MEMADD_SIZE_8BIT, &pressArr[2], 1, 10);
rt_kprintf("0x%02X ", pressArr[2]);
// 压力计算公式
press = ((pressArr[0] << 16) + (pressArr[1] << 8) + pressArr[2]);
if (press > GZP6877_PRE_LIMIT)
{
press = press - GZP6877_PRE_ADJUST;
}
// 单位为Pa
press = press / GZP6877_K_VALUE;
*pPressure = press;
rt_kprintf("press:%d Pa\r\n", press);
}
/**
* @brief 单次模式读取温度数据
* @param pTemperature -[out] 温度值,单位为℃
*/
void GZP6859D_ReadSingleModeTempData(float *pTemperature)
{
uint8_t cmd = GZP6877_ONE_TEMP_CMD;
uint8_t result = 0;
uint8_t tempArr[3] = {0};
float temp = 0;
// 进行单次传感器温度信号采集模式
HAL_I2C_Mem_Write(&hi2c2, GZP6877_WRITE_ADDR, GZP6877_CMD_ADDR, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 10);
// 采集结束
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_CMD_ADDR, I2C_MEMADD_SIZE_8BIT, &result, 1, 10);
rt_kprintf("result:0x%02X ", result);
// 获取温度数据AD值
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_TEMP_MSB_ADDR, I2C_MEMADD_SIZE_8BIT, &tempArr[0], 1, 10);
rt_kprintf("0x%02X ", tempArr[0]);
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_TEMP_LSB_ADDR, I2C_MEMADD_SIZE_8BIT, &tempArr[1], 1, 10);
rt_kprintf("0x%02X ", tempArr[1]);
// 温度计算公式
temp = ((tempArr[0] << 8) + tempArr[1]);
if (temp > GZP6877_TEMP_LIMIT)
{
temp = temp - GZP6877_TEMP_ADJUST;
}
// 单位为℃
temp = temp / GZP6877_TEMP_K;
*pTemperature = temp;
printf("temp:%.2f C\r\n", temp);
}
/**
* @brief 组合模式读取数据
* @param pTemperature -[out] 温度值
* @param pPressure -[out] 压力值
*/
void GZP6859D_ReadCombinedModeData(float *pTemperature, uint32_t *pPressure)
{
uint8_t cmd = GZP6877_COMBINED_COM;
uint8_t result = 0;
uint8_t tempArr[4] = {0};
float temp = 0;
uint8_t pressArr[4] = {0};
uint32_t press = 0;
// 进行组合模式读取数据
HAL_I2C_Mem_Write(&hi2c2, GZP6877_WRITE_ADDR, GZP6877_SLAVE_ADDR, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 10);
// 采集结束
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_SLAVE_ADDR, I2C_MEMADD_SIZE_8BIT, &result, 1, 10);
rt_kprintf("0x%02X ", result);
// 获取温度数据AD值
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_TEMP_MSB_ADDR, I2C_MEMADD_SIZE_8BIT, &tempArr[0], 1, 10);
rt_kprintf("0x%02X ", tempArr[0]);
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_TEMP_LSB_ADDR, I2C_MEMADD_SIZE_8BIT, &tempArr[1], 1, 10);
rt_kprintf("0x%02X ", tempArr[1]);
// 温度计算公式
temp = ((tempArr[0] << 8) + tempArr[1]);
if (temp > GZP6877_TEMP_LIMIT)
{
temp = temp - GZP6877_TEMP_ADJUST;
}
// 单位为℃
temp = temp / GZP6877_TEMP_K;
*pTemperature = temp;
printf("temp:%.2f C\r\n", temp);
// 获取压力数据AD值
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_DATA_MSB_ADDR, I2C_MEMADD_SIZE_8BIT, &pressArr[0], 1, 10);
rt_kprintf("0x%02X ", pressArr[0]);
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_DATA_CSB_ADDR, I2C_MEMADD_SIZE_8BIT, &pressArr[1], 1, 10);
rt_kprintf("0x%02X ", pressArr[1]);
HAL_I2C_Mem_Read(&hi2c2, GZP6877_READ_ADDR, GZP6877_DATA_LSB_ADDR, I2C_MEMADD_SIZE_8BIT, &pressArr[2], 1, 10);
rt_kprintf("0x%02X ", pressArr[2]);
// 压力计算公式
press = ((pressArr[0] << 16) + (pressArr[1] << 8) + pressArr[2]);
if (press > GZP6877_PRE_LIMIT)
{
press = press - GZP6877_PRE_ADJUST;
}
// 单位为Pa
press = press / GZP6877_K_VALUE;
*pPressure = press;
rt_kprintf("press:%d Pa\r\n", press);
}
(7)main.c
#include <rtthread.h>
#include <drv_common.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "GZP6877.h"
int main(void)
{
int count = 1;
GZP6877_I2C2_Init();
float temperature;
uint32_t pressure;
GZP6859D_ReadCombinedModeData(&temperature, &pressure); //先以组合模式读取温度,以获取温度校准系数,否则读数不准
while (count)
{
GZP6859D_ReadSingleModePressureData(&pressure);
GZP6859D_ReadSingleModeTempData(&temperature);
printf("P:%d Pa T:%.2f C\r\n", pressure, temperature);
rt_thread_mdelay(1000);
}
return RT_EOK;
}
四、模拟IIC通信
1.gzp6877.c文件
#include "gzp6877d.h"
/*======================================================### 静态函数调用 ###==================================================*/
/**
* @brief IIC的us延时函数
* @param us: 延时时间
*/
static void IIC_Delay_us(rt_uint32_t us)
{
rt_hw_us_delay(us);
}
/**
* @brief IIC的起始信号
*/
static void IIC_Start(void)
{
GZP6877_SDA_OUT_MODE;
GZP6877_SDA_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SDA_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
}
/**
* @brief IIC的停止信号
*/
static void IIC_Stop(void)
{
GZP6877_SDA_OUT_MODE;
GZP6877_SDA_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SDA_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
}
/**
* @brief IIC等待应答
* @return 1:等待超时 0:得到应答
*/
static uint8_t IIC_Wait_ACK(void)
{
uint8_t outTime = 0;
GZP6877_SDA_INPUT_MODE;
GZP6877_SDA_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
while (rt_pin_read(GZP6877_SDA_PIN))
{
outTime++;
if (outTime >= ACK_OUT_TIME)
{
IIC_Stop();
return RT_ERROR;
}
}
GZP6877_SCL_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
return RT_EOK;
}
/**
* @brief 没有超时时间的应答函数
*/
void IIC_ACK(void)
{
GZP6877_SCL_LOW;
GZP6877_SDA_OUT_MODE;
GZP6877_SDA_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SDA_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
}
/**
* @brief IIC无应答
*/
void IIC_NACK(void)
{
GZP6877_SCL_LOW;
GZP6877_SDA_OUT_MODE;
GZP6877_SDA_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
}
/**
* @brief IIC发送一个字节数据
*/
static void IIC_Send_Byte(uint8_t data)
{
GZP6877_SDA_OUT_MODE;
GZP6877_SCL_LOW;
for (int i = 0; i < 8; ++i)
{
if (data & (0x01 << (7 - i)))
{
GZP6877_SDA_HIGH;
}
else
{
GZP6877_SDA_LOW;
}
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
}
GZP6877_SCL_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SDA_HIGH;
IIC_Delay_us(IIC_DELAY_TIME);
}
/**
* @brief 接收一个字节的数据
* @return 返回接收到的数据
*/
static uint8_t IIC_Read_Byte(void)
{
uint8_t recv = 0;
GZP6877_SDA_INPUT_MODE;
for (int i = 0; i < 8; ++i)
{
GZP6877_SCL_LOW;
IIC_Delay_us(IIC_DELAY_TIME);
GZP6877_SCL_HIGH;
IIC_Delay_us(IIC_DELAY_TIME / 2);
recv <<= 1;
if (rt_pin_read(GZP6877_SDA_PIN))
{
recv++;
}
IIC_Delay_us(IIC_DELAY_TIME / 2);
}
GZP6877_SDA_HIGH;
return recv;
}
/**
* @brief GZP6877写入一个字节的数据
* @return 1: 异常 0:读取正常
*/
static uint8_t GZP6877_Write_One_Byte(uint8_t address, uint8_t data)
{
uint8_t ack;
IIC_Start();
IIC_Send_Byte(GZP6877_WRITE_ADDR);
ack = IIC_Wait_ACK();
if (ack == RT_ERROR)
{
return RT_ERROR;
}
IIC_Send_Byte(address);
ack = IIC_Wait_ACK();
if (ack == RT_ERROR)
{
return RT_ERROR;
}
IIC_Send_Byte(data);
IIC_Wait_ACK();
if (ack == RT_ERROR)
{
return RT_ERROR;
}
IIC_Stop();
return RT_EOK;
}
/**
* @brief GZP6877读一个字节的数据
* @param address:读书数据的地址
* @return 0:应答错误
*/
static uint8_t GZP6877_Read_One_Byte(uint8_t address)
{
uint8_t data, ack;
IIC_Start();
IIC_Send_Byte(GZP6877_WRITE_ADDR);
ack = IIC_Wait_ACK();
if (ack != RT_EOK)
{
return 0;
}
IIC_Send_Byte(address);
ack = IIC_Wait_ACK();
if (ack != RT_EOK)
{
return 0;
}
IIC_Start();
IIC_Send_Byte(GZP6877_READ_ADDR);
ack = IIC_Wait_ACK();
if (ack != RT_EOK)
{
return 0;
}
data = IIC_Read_Byte();
IIC_Stop();
return data;
}
/*=====================================================####### END #######=================================================*/
/*======================================================##### 外部调用 #####==================================================*/
/**
* @brief IIC的GPIO引脚初始化
*/
void GZP6877_GPIO_Init(void)
{
GZP6877_SDA_OUT_MODE;
GZP6877_SCL_OUT_MODE;
GZP6877_SDA_HIGH;
GZP6877_SCL_HIGH;
}
/**
* @brief GZP6877模块等待可读压力和温度
* @return 0:可读 1:不可读
*/
uint8_t GZP6877_Wait(void)
{
uint8_t ack, data, status;
ack = GZP6877_Write_One_Byte(GZP6877_CMD_ADDR, GZP6877_COM);
if (ack)
{
return RT_ERROR;
}
data = GZP6877_Read_One_Byte(GZP6877_CMD_ADDR);
if (!data)
{
return RT_ERROR;
}
status = data & 0x08;
if (status)
{
rt_thread_delay(20);
}
return 0;
}
/**
* @brief GZP6877模块读取压力
* @return 返回气压值
*/
int GZP6877_Read_Pressure(void)
{
int pressure = 0;
uint8_t pressure_H, pressure_M, pressure_L;
pressure_H = GZP6877_Read_One_Byte(GZP6877_DATA_HSB_ADDR);
pressure_M = GZP6877_Read_One_Byte(GZP6877_DATA_MSB_ADDR);
pressure_L = GZP6877_Read_One_Byte(GZP6877_DATA_LSB_ADDR);
pressure |= (int)pressure_H << 16;
pressure |= (int)pressure_M << 8;
pressure |= (int)pressure_L << 0;
/* 超过 8388606(0x800000) 为负压值 */
if (pressure > GZP6877_PRE_LIMIT)
{
pressure = (pressure - GZP6877_PRE_ADJUST) / GZP6877_PRE_K;
}
else
{
pressure /= GZP6877_PRE_K;
}
return pressure;
}
/**
* @brief GZP6877模块读取温度
* @return 返回温度值
*/
float GZP6877_Read_Temperature(void)
{
uint8_t temp_H, temp_L;
float temp = 0;
temp_H = GZP6877_Read_One_Byte(GZP6877_TEMP_MSB_ADDR);
temp_L = GZP6877_Read_One_Byte(GZP6877_TEMP_LSB_ADDR);
temp = (float)(temp_H << 8) + (float)(temp_L << 0);
if (temp > GZP6877_TEMP_LIMIT)
{
temp = (temp - GZP6877_TEMP_ADJUST) / GZP6877_TEMP_K;
}
else
{
temp /= GZP6877_TEMP_K;
}
return temp;
}
/**
* @brief 打印气压和温度
*/
void GZP6877_Read_Data(void)
{
int pres = 0;
float temp = 0;
pres = GZP6877_Read_Pressure();
temp = GZP6877_Read_Temperature();
printf("pres: %d Pa, temp: %.3f C\n", pres, temp);
}
/*=====================================================####### END #######=================================================*/
2.gzp6877.h文件
#ifndef APPLICATIONS_GZP6877D_H_
#define APPLICATIONS_GZP6877D_H_
#include <rtthread.h>
#include <drv_common.h>
/**=====================================================###### 宏定义 ######==================================================*/
#define GZP6877_WRITE_BIT 0x00 // 硬件I2C写标志
#define GZP6877_READ_BIT 0x01 // 硬件I2C读标志
#define GZP6877_SLAVE_ADDR 0x6D // 设备地址
#define GZP6877_WRITE_ADDR ((GZP6877_SLAVE_ADDR << 1) | GZP6877_WRITE_BIT)
#define GZP6877_READ_ADDR ((GZP6877_SLAVE_ADDR << 1) | GZP6877_READ_BIT)
#define GZP6877_COM 0x0A // 测量一次数据指令
#define GZP6877_DATA_HSB_ADDR 0x06 // 气压高地址
#define GZP6877_DATA_MSB_ADDR 0x07 // 气压中地址
#define GZP6877_DATA_LSB_ADDR 0x08 // 气压低地址
#define GZP6877_TEMP_MSB_ADDR 0x09 // 温度高地址
#define GZP6877_TEMP_LSB_ADDR 0x0A // 温度低地址
#define GZP6877_CMD_ADDR 0x30 // 测量命令寄存器
#define GZP6877_PRE_LIMIT 8388606 // 气压界限
#define GZP6877_PRE_ADJUST 16777216 // 气压校准值
#define GZP6877_PRE_K 8 // 气压K值
#define GZP6877_TEMP_LIMIT 32786 // 温度界限
#define GZP6877_TEMP_ADJUST 65536 // 温度校准值
#define GZP6877_TEMP_K 256 // 温度K值
#define IIC_DELAY_TIME 60 // IIC延时时间
#define ACK_OUT_TIME 250 // 应答信号超时时间
#define GZP6877_SDA_PIN GET_PIN(F, 0) // PF0数据总线
#define GZP6877_SCL_PIN GET_PIN(F, 1) // PF1时钟总线
#define GZP6877_SCL_OUT_MODE rt_pin_mode(GZP6877_SCL_PIN, PIN_MODE_OUTPUT); // SCL输出模式
#define GZP6877_SDA_OUT_MODE rt_pin_mode(GZP6877_SDA_PIN, PIN_MODE_OUTPUT); // SDA输出模式
#define GZP6877_SDA_INPUT_MODE rt_pin_mode(GZP6877_SDA_PIN, PIN_MODE_INPUT); // SDA输出模式
#define GZP6877_SDA_HIGH rt_pin_write(GZP6877_SDA_PIN, PIN_HIGH); // 设置SDA为高
#define GZP6877_SDA_LOW rt_pin_write(GZP6877_SDA_PIN, PIN_LOW); // 设置SDA为高
#define GZP6877_SCL_HIGH rt_pin_write(GZP6877_SCL_PIN, PIN_HIGH); // 设置SCL为高
#define GZP6877_SCL_LOW rt_pin_write(GZP6877_SCL_PIN, PIN_LOW); // 设置SCL为高
/**====================================================####### END #######=================================================*/
/**==================================================##### 函数及变量声明 #####===============================================*/
extern void GZP6877_GPIO_Init(void); // IIC的GPIO引脚初始化
extern uint8_t GZP6877_Wait(void); // GZP6877模块等待可读压力和温度
extern int GZP6877_Read_Pressure(void); // GZP6877模块读取压力
extern float GZP6877_Read_Temperature(void); // GZP6877模块读取温度
extern void GZP6877_Read_Data(void); // 打印气压和温度
/**====================================================####### END #######=================================================*/
#endif /* APPLICATIONS_GZP6877D_H_ */
3.main.c
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "gzp6877d.h"
int main(void)
{
int count = 1;
GZP6877_GPIO_Init();
while (count)
{
if (GZP6877_Wait())
{
continue;
}
GZP6877_Read_Data();
rt_thread_mdelay(500);
}
return RT_EOK;
}
五、测试验证
通过软件IIC和硬件IIC进行通信,都可以实现温度和气压的读取,实现的效果如下所示: