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内核的单片机上.
100

被折叠的 条评论
为什么被折叠?



