STM32HAL库驱动 GZP6816D压力芯片

GZP6816D 是一款具有高精度和低电流消耗的小型化数字式大气压力传感器,兼具压力和温度测 量两种特点。内部信号处理器将压力和温度传感器的输出分别转换为 24 位、16 位数据。每个压力 传感器已单独校准并且包含校准系数,在应用中使用系数将测量结果转换成真实的压力和温度值, 传感器测量和校准系数可通过串行 I 2C 接口获得。

以下是C代码:

#include "XGZP6816D.h"
//#include "delay.h"
//#include "usart.h"
#include <math.h>




#define ADC_FULL_SCALE  16777216UL    // 24位ADC满量程值 (2^24)
// 定义最小气压值为30.0
#define PMIN 30.0f
// 定义最大气压值为110.0
#define PMAX 110.0f
// 定义数字输出的最小值为1677721.0
#define DMIN  (ADC_FULL_SCALE * 0.10f)
// 定义数字输出的最大值为15099949.0
#define DMAX  (ADC_FULL_SCALE * 0.90f)


// // 定义温度换算参数
// #define TMIN -50.0f  // 温度下限
// #define TMAX 150.0f  // 温度上限
// #define TEMP_MAX 16777216  // ADC 温度最大值

#define I2C_address 0x78

unsigned char GZP6816D_IsBusy(void)
{
	unsigned char status;
	I2C_ReadData(I2C_address , &status, 1);
    // printf("stusta = %02X\r\n",status );
	status = (status >> 5) & 0x01;

	return status;
}
  unsigned char buffer[6] = {0};
	
long int pressure_AD1; 
long int temperature_AD1; 
float pressure_kpa1;
float pressure1;
float temperature1;	
void read_XGZP6816D(void) {


    buffer[0] = 0xAC;//0XAC和0XB0-BF命令一样只是设置不同的过采样率
                     // 温度过采样率  0:4x 1:8x
                     // 压力过采样率  000:128x  001:64x  010:32x  011:16x  100:8x  101:4x  110:2x  111:1x
	  I2C_WriteData(I2C_address, buffer, 1);
     while (1){
		if (GZP6816D_IsBusy()){
            HAL_Delay(5);

		}
		else
			break;
	   }
    I2C_ReadData(I2C_address, buffer, 6);
    pressure_AD1 = (unsigned long)((((unsigned long)buffer[1]) << 16) | (((unsigned int)buffer[2]) << 8) | ((unsigned char)buffer[3]));
    temperature_AD1 = ((unsigned int)buffer[4] << 8) | (buffer[5] << 0);
    pressure_kpa1 = (float) ((PMAX-PMIN)/(DMAX-DMIN)*(pressure_AD1-DMIN)+PMIN);	 //单位:KPa
    pressure1 = (double) (pressure_kpa1 * 1000.0);
	  temperature1= ((float)temperature_AD1/ 65536 * 19000 - 4000) / 100.0;
}



由于上述调用了IIC的读取函数,所以还需要调用IIC,为了照顾到大家,博主没有用硬件IIC而是采用了模拟IIC.以下为博主为大家整理的HAL库模拟iic的代码,.c文件如下:

#include "myiic.h"


#define CPU_FREQUENCY_MHZ    24		// STM32????
void delay_us(__IO uint32_t delay)
{
    int last, curr, val;
    int temp;

    while (delay != 0)
    {
        temp = delay > 900 ? 900 : delay;
        last = SysTick->VAL;
        curr = last - CPU_FREQUENCY_MHZ * temp;
        if (curr >= 0)
        {
            do
            {
                val = SysTick->VAL;
            }
            while ((val < last) && (val >= curr));
        }
        else
        {
            curr += CPU_FREQUENCY_MHZ * 1000;
            do
            {
                val = SysTick->VAL;
            }
            while ((val <= last) || (val > curr));
        }
        delay -= temp;
    }
}

 


// 初始化IIC
void IIC_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA15 */
  GPIO_InitStruct.Pin = GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB3 */
  GPIO_InitStruct.Pin = GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
}

void SDA_READ(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
	
  GPIO_InitStruct.Pin = GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void SDA_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
	
  GPIO_InitStruct.Pin = GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}


// 发送IIC总线的起始信号
uint8_t IIC_Start(void)
{
SDA_OUT();
    SDA_HIGH();
    SCL_HIGH();
    delay_us(DELAY_TIME); // 确保总线稳定
SDA_READ();
    if (!READ_SDA()) // 检查SDA线是否为低电平
        return FAILED;
SDA_OUT();
    SDA_LOW(); // 拉低SDA线,准备生成起始信号
    delay_us(DELAY_TIME); // 确保起始信号持续时间足够

    SCL_LOW(); // 拉低SCL线,完成起始信号的发送
    delay_us(DELAY_TIME); // 确保总线稳定

    return SUCCESS;
}

// 发送IIC停止信号
void IIC_Stop(void)
{
    SDA_OUT();	
    SDA_LOW(); // 拉低SDA线
    SCL_LOW(); // 拉低SCL线
    delay_us(DELAY_TIME); // 确保信号稳定

    SCL_HIGH(); // 拉高SCL线
    delay_us(DELAY_TIME); // 确保SCL高电平期间SDA的变化可以被正确识别

    SDA_HIGH(); // 在SCL为高电平时,拉高SDA线,生成停止条件
    delay_us(DELAY_TIME); // 确保停止条件被正确发送
}

// 生成ACK确认信号
void IIC_Ack(void)
{
    SDA_OUT();
	  SDA_LOW(); // 拉低SDA线以生成ACK信号
    delay_us(DELAY_TIME); // 确保信号稳定

    SCL_HIGH(); // 拉高SCL线,通知从设备ACK信号已发送
    delay_us(DELAY_TIME); // 确保从设备可以检测到ACK信号

    SCL_LOW(); // 拉低SCL线,准备下一个操作
    delay_us(DELAY_TIME); // 确保信号稳定

    SDA_HIGH(); // 拉高SDA线,恢复默认状态
}

// 生成非确认(NAck)信号
void IIC_NAck(void)
{
    SDA_OUT();
	  SDA_HIGH(); // 拉高SDA线以生成NAck信号
    delay_us(DELAY_TIME); // 确保信号稳定

    SCL_HIGH(); // 拉高SCL线,通知从设备NAck信号已发送
    delay_us(DELAY_TIME); // 确保从设备可以检测到NAck信号

    // 等待从设备响应(可选)
    delay_us(DELAY_TIME);

    SCL_LOW(); // 拉低SCL线,准备下一个操作
    delay_us(DELAY_TIME); // 确保信号稳定

    // 确保SDA线在后续操作中保持高电平
    SDA_HIGH();
}



// 等待ACK确认信号
uint8_t IIC_Wait_Ack(void)
{
    SDA_HIGH(); // 设置SDA线为高电平
    SCL_HIGH(); // 设置SCL线为高电平
    delay_us(DELAY_TIME); // 等待数据稳定
SDA_READ();
    if (READ_SDA()) { // 如果SDA线读取为高电平,表示未收到ACK
			SDA_OUT();
        SCL_LOW(); // 设置SCL线为低电平
        return FAILED; // 返回失败
    }
SDA_OUT();
    SCL_LOW(); // 设置SCL线为低电平
    delay_us(DELAY_TIME); // 确保信号稳定
    return SUCCESS; // 返回成功
}


// IIC发送一个字节
void IIC_Send_Byte(uint8_t byte)
{
    uint8_t i = 8;
    while (i--) {
        SCL_LOW(); // 拉低SCL线
        delay_us(DELAY_TIME);

        if (byte & 0x80)
            SDA_HIGH();
        else
            SDA_LOW();

        byte <<= 1;
        delay_us(DELAY_TIME);

        SCL_HIGH(); // 拉高SCL线
        delay_us(DELAY_TIME);
    }
    SCL_LOW(); // 释放总线
    delay_us(DELAY_TIME); // 确保信号稳定
}

// IIC读取一个字节
uint8_t IIC_Read_Byte(void)
{
    uint8_t i = 8;
    uint8_t byte = 0;

    SDA_HIGH(); // 设置SDA线为高电平
    while (i--) {
			SDA_OUT();
        byte <<= 1;
        SCL_LOW(); // 拉低SCL线
        delay_us(DELAY_TIME);

        SCL_HIGH(); // 拉高SCL线
        delay_us(DELAY_TIME);
SDA_READ();
        if (READ_SDA()) {
            byte |= 0x01;
        }
SDA_OUT();				
    }
		
	SDA_OUT();	
    SCL_LOW(); // 释放总线
    delay_us(DELAY_TIME); // 确保信号稳定
    return byte;
}



/**
 * 向目标设备的目标寄存器写入数据
 * @param addr 设备地址
 * @param reg 寄存器地址
 * @param data 要写入的数据
 * @return 写入操作的结果,如果成功返回 SUCCESS,否则返回 FAILED
 */
unsigned char i2c_write(unsigned char addr, unsigned char reg, unsigned char data)
{
    // 发送起始信号,若失败则返回 FAILED
    if (IIC_Start() == FAILED)
        return FAILED;

    // 发送设备地址(写模式)
    IIC_Send_Byte(addr << 1);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送寄存器地址
    IIC_Send_Byte(reg);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送要写入的数据
    IIC_Send_Byte(data);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送停止信号,结束写操作
    IIC_Stop();

    // 返回写操作成功的状态
    return SUCCESS;
}



/**
 * 从指定设备的指定寄存器读取一个字节的数据
 * @param addr 设备地址
 * @param reg  寄存器地址
 * @return 读取到的数据,如果读取失败则返回 FAILED
 */
unsigned char i2c_read(unsigned char addr, unsigned char reg)
{
    // 发送起始信号,若失败则返回 FAILED
    if (IIC_Start() == FAILED)
        return FAILED;

    // 发送设备地址(写模式)
    IIC_Send_Byte(addr << 1);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送寄存器地址
    IIC_Send_Byte(reg);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送停止信号,结束写操作
    IIC_Stop();

    // 重新发送起始信号,若失败则返回 FAILED
    if (IIC_Start() == FAILED)
        return FAILED;

    // 发送设备地址(读模式)
    IIC_Send_Byte((addr << 1) | 0x01);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 读取一个字节的数据
    uint8_t data = IIC_Read_Byte();
    // 发送非应答信号,表示读取结束
    IIC_NAck();
    // 发送停止信号,结束读操作
    IIC_Stop();
    // 返回读取到的数据
    return data;
}


/**
 * 通过I2C读取数据
 *
 * @param address 目标设备的地址
 * @param buf 用于存储读取数据的缓冲区指针
 * @param count 要读取的字节数
 * @return 返回读取状态,0表示成功,非0表示失败
 */
unsigned char I2C_ReadData(unsigned char address, unsigned char *buf, unsigned char count)
{
    // 发送起始信号
    IIC_Start();
    // 发送设备地址
    IIC_Send_Byte((address << 1) | 0x01);

    // 等待从设备应答
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 读取数据
    while (count--) {
        *buf = IIC_Read_Byte(); // 读取一个字节的数据
        if (count > 0) {
            IIC_Ack(); // 如果不是最后一个字节,发送ACK
        } else {
            IIC_NAck(); // 如果是最后一个字节,发送NAck
        }
        buf++;
    }

    // 发送停止信号
    IIC_Stop();
    return 0;
}

/**
 * 通过I2C写入数据
 *
 * @param address 目标设备的地址
 * @param buf 要写入的数据缓冲区指针
 * @param count 要写入的字节数
 * @return 返回写入状态,0表示成功,非0表示失败
 */
unsigned char I2C_WriteData(unsigned char address, unsigned char *buf, unsigned char count)
{
    // 发送起始信号
    IIC_Start();
    // 发送设备地址
    IIC_Send_Byte((address << 1) & 0xFE);

    // 等待从设备应答
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 写入数据
    while (count--) {
        IIC_Send_Byte(*buf++);
        // 等待从设备应答
        if (IIC_Wait_Ack() == FAILED) {
            IIC_Stop();
            return 2;
        }
    }

    // 发送停止信号
    IIC_Stop();
    return 0;
}




/**
 * @brief 在IIC总线上写入多个字节的数据
 *
 * 该函数通过IIC协议向指定的从设备地址和寄存器地址写入一定长度的数据
 * 它首先启动IIC总线,然后发送从设备地址和寄存器地址,接着发送数据,最后停止IIC总线
 *
 * @param SlaveAddress 从设备地址
 * @param REG_Address 寄存器地址
 * @param len 要写入的数据长度
 * @param buf 指向要写入的数据的指针
 * @return u8 如果写入成功,返回SUCCESS;如果写入失败,返回FAILED
 */
uint8_t IIC_Write_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint8_t len, uint8_t *buf)
{
    int i;

    // 启动IIC总线
    if (IIC_Start() == FAILED)
        return FAILED;

    // 发送从设备地址
    IIC_Send_Byte(SlaveAddress<<1);
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送寄存器地址
    IIC_Send_Byte(REG_Address);
    IIC_Wait_Ack();

    // 发送数据
    for (i = 0; i < len; i++) {
        IIC_Send_Byte(buf[i]);
        if (IIC_Wait_Ack() == FAILED) {
            IIC_Stop();
            return FAILED;
        }
    }

    // 停止IIC总线
    IIC_Stop();
    return SUCCESS;
}



/**
 * 从指定设备的指定寄存器读取多个字节的数据
 * @param SlaveAddress 设备地址
 * @param REG_Address  寄存器地址
 * @param len          要读取的字节数
 * @param *buf         用于存储读取数据的缓冲区指针
 * @return 读取操作的结果,如果成功返回 SUCCESS,否则返回 FAILED
 */
uint8_t IIC_Read_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint8_t len, uint8_t *buf)
{
    // 发送起始信号,若失败则返回 FAILED
    if (IIC_Start() == FAILED)
        return FAILED;

    // 发送设备地址(写模式)
    IIC_Send_Byte(SlaveAddress<<1);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送寄存器地址
    IIC_Send_Byte(REG_Address);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 发送停止信号,结束写操作
    IIC_Stop();

    // 重新发送起始信号,若失败则返回 FAILED
    if (IIC_Start() == FAILED)
        return FAILED;

    // 发送设备地址(读模式)
    IIC_Send_Byte((SlaveAddress<<1)+1);
    // 等待从设备应答,若失败则停止通信并返回 FAILED
    if (IIC_Wait_Ack() == FAILED) {
        IIC_Stop();
        return FAILED;
    }

    // 读取数据
    while (len) {
        // 读取一个字节的数据到缓冲区
        *buf = IIC_Read_Byte();
        // 如果是最后一个字节,发送非应答信号
        if (len == 1)
            IIC_NAck();
        // 如果不是最后一个字节,发送应答信号
        else
             IIC_Ack();
        // 移动缓冲区指针
        buf++;
        // 减少剩余要读取的字节数
        len--;
    }

    // 发送停止信号,结束读操作
    IIC_Stop();

    // 返回读操作成功的状态
    return SUCCESS;
}


/**
 * @brief 检测指定地址的I2C设备是否存在
 *
 * @param dev_addr I2C设备地址 (7位地址,例如0x6D)
 * @return uint8_t 返回SUCCESS表示设备存在,返回FAILED表示设备不存在或通信失败
 */
uint8_t i2c_device_exists(uint8_t dev_addr)
{
    // 发送起始信号
    if (IIC_Start() != SUCCESS) {
        return FAILED;
    }

    // 发送设备地址(写模式)
    IIC_Send_Byte(dev_addr << 1); // 转换为写地址
    uint8_t ack = IIC_Wait_Ack();

    // 发送停止信号
    IIC_Stop();

    // 如果收到ACK,则设备存在
    return (ack == SUCCESS) ? SUCCESS : FAILED;
}

这是一套标准的模拟IIC代码,用在该项目只有一句读取,博主也贴出了hal库无微妙延时的函数,只需要大家根据自己的主时钟频率修改宏定义,我用的是24兆主时钟。其对应的.h文件如下所示:

#ifndef __MYIIC_H
#define __MYIIC_H

#include "main.h"


#undef SUCCESS
#define SUCCESS 0
#undef FAILED
#define FAILED  1

#define DELAY_TIME  3



#define  SDA_HIGH()      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET)
#define  SDA_LOW()       HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET)
#define  SCL_HIGH()      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET)
#define  SCL_LOW()       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET)
#define  READ_SDA()      HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define  READ_SCL()      HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)


void IIC_Init(void);                //初始化IIC的IO口
uint8_t IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(void);
void IIC_NAck(void);
uint8_t IIC_Wait_Ack(void);
void IIC_Send_Byte(uint8_t byte);
uint8_t IIC_Read_Byte(void);

unsigned char i2c_write(unsigned char addr, unsigned char reg, unsigned char data); //写一个数据
unsigned char i2c_read(unsigned char addr, unsigned char reg); //读一个数据
unsigned char I2C_WriteData(unsigned char address, unsigned char *buf, unsigned char count); //写数据
unsigned char I2C_ReadData(unsigned char address, unsigned char *buf, unsigned char count); //读数据
uint8_t IIC_Read_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint8_t len, uint8_t *buf); //读n个字节数据
uint8_t IIC_Write_nByte(uint8_t SlaveAddress, uint8_t REG_Address, uint8_t len, uint8_t *buf); //写n个字节数据
uint8_t i2c_device_exists(uint8_t dev_addr); //判断设备是否存在



#endif


上述代码为芯片HAL驱动代码。本人热衷于使用假微妙延时,这样代码方便移植到任何arm内核的单片机上.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值