SGP-30传感器IIC读取数据(基于52单片机、IO口模拟IIC)

说明:

//SGP30的SCL引脚定义

sbit SCL = P1^6; 

//SGP30的SDA引脚定义
sbit SDA = P1^7;    

SGP-30.h:

#ifndef __SGP30_H
#define __SGP30_H
#include "main.h"


#define SGP30_read  0xb1  //SGP30的读地址
#define SGP30_write 0xb0  //SGP30的写地址

#define ACK         0             //应答信号
#define NACK        1             //非应答信号

sbit SCL = P1^6;  //SGP30的SCL引脚定义
sbit SDA = P1^7;	//SGP30的SDA引脚定义



//I2C起始信号
void I2CStart(void);

//I2C停止信号
void I2CStop(void);

//I2C写一个字节数据,返回ACK或者NACK
u8 I2C_Write_Byte(u8 Write_Byte);

//I2C读一个字节数据,入口参数用于控制应答状态,ACK或者NACK
u8 I2C_Read_Byte(u8 AckValue);

//初始化SGP30
void SGP30_Init(void);

//向SGP30写数据
void SGP30_Write(u8 a, u8 b);

//从SGP30读数据
u32 SGP30_Read(void);


#endif

SGP-30.c:

#include "SGP30.H"
#include "delay.h"




//模拟IIC用的短延时 us

void I2C_Delay (u8 t)
{
  while(t--);
}

//I2C起始信号
void I2CStart(void)
{
  SDA = 1;                            //发送起始条件的数据信号 
  SCL = 1;
  I2C_Delay(50);                    //起始条件建立时间大于4.7us,延时 
  SDA = 0;                            //发送起始信号
  I2C_Delay(50);                    //起始条件锁定时间大于4μs 
  SCL = 0;                            //钳住I2C总线,准备发送或接收数据 
  I2C_Delay(50);
}

//I2C停止信号
void I2CStop(void)
{
  SDA = 0;                        //发送结束条件的数据信号 
  SCL = 0;
  I2C_Delay(50);
  SCL = 1;                        //发送结束条件的时钟信号 
  I2C_Delay(50);                //结束条件建立时间大于4μs 
  SDA = 1;                        //发送I2C总线结束信号 
  I2C_Delay(50);
}

//I2C写一个字节数据,返回ACK或者NACK
u8 I2C_Write_Byte(u8 Write_Byte)  //Sendbyte
{
  u8 i;
  SCL=0;
  I2C_Delay(10);
  for(i=0; i<8; i++)            //要传送的数据长度为8位 
  {
    if(Write_Byte&0x80)   //判断发送位 
    {
      SDA = 1;
    }
    else
    {
      SDA = 0;
    }
    I2C_Delay(5);
    SCL=1;                //输出SDA稳定后,拉高SCL给出上升沿,从机检测到后进行数据采样
    I2C_Delay(5);         //保证时钟高电平周期大于4μs 
    SCL=0;
    I2C_Delay(5);
    Write_Byte <<= 1;
  }
  I2C_Delay(1);
  SDA = 1;                      //8位发送完后释放数据线,准备接收应答位-ZLG
  I2C_Delay(40);
  SCL = 1;                      //MCU告知SHT2X数据发送完毕,等待从机的应答信号
  I2C_Delay(40);
  /*以下是判断I2C总线接收应到应答信号是ACK还是NACK*/
  if(SDA==1)                                   //SDA为高,收到NACK
  {
		I2C_Delay(40);
    SCL=0;
    return NACK;
  }
  else                                         //SDA为低,收到ACK
  {
		I2C_Delay(40);
    SCL=0;
    return ACK;

  }
}

//I2C读一个字节数据,入口参数用于控制应答状态,ACK或者NACK
u8 I2C_Read_Byte(u8 AckValue)//receivebyte
{
  u8 i,RDByte=0;
  SCL=0;                                   //置时钟线为低,准备接收数据位 
  I2C_Delay(40);
  SDA = 1;                                 //释放总线,置数据线为输入方式 
  for (i=0; i<8; i++)
  {
    SCL = 1;                          //SCL高电平期间,采集SDA信号,并作为有效数据 //置时钟线为高使数据线上数据有效 
    I2C_Delay(20);
    RDByte <<= 1;                  //移位
    if(SDA==1)                           //采样获取数据
    {
      RDByte |= 0x01;
    }
    else
    {
      RDByte &= 0xfe;
    }
    I2C_Delay(10);
    SCL = 0;                             //下降沿,从机给出下一位值
    I2C_Delay(60);
  }
  /*以下是I2C总线发送应答信号ACK或者NACK*/
  SDA = AckValue;                      //应答状态
  I2C_Delay(30);
  SCL = 1;
  I2C_Delay(50);                  //时钟低电平周期大于4μs 
  SCL = 0;                                  //清时钟线,钳住I2C总线以便继续接收 
  I2C_Delay(50);
  return RDByte;
}


//初始化IIC接口
void SGP30_Init(void)
{
	 SCL = 1;
  I2C_Delay(50);
	 SDA = 1;
  I2C_Delay(50);
  SGP30_Write(0x20,0x03);
//	SGP30_ad_write(0x20,0x61);
//	SGP30_ad_write(0x01,0x00);
}

void SGP30_Write(u8 a, u8 b)
{
  I2CStart();
  I2C_Write_Byte(SGP30_write); //发送器件地址+写指令
  I2C_Write_Byte(a);		//发送控制字节
  I2C_Write_Byte(b);
  I2CStop();
  delay_ms(20);
}

unsigned long SGP30_Read(void)
{
  unsigned long dat;
  int crc;
  I2CStart();
  I2C_Write_Byte(SGP30_read); //发送器件地址+读指令
  dat = I2C_Read_Byte(ACK);
  dat <<= 8;
  dat += I2C_Read_Byte(ACK);
  crc = I2C_Read_Byte(ACK); //check数据,舍去
  crc = crc;             //避免编译产生警告,这句可有可无
  dat <<= 8;
  dat += I2C_Read_Byte(ACK);
  dat <<= 8;
  dat += I2C_Read_Byte(NACK);
  I2CStop();	
	delay_ms(20);
  return(dat);
	
}








  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
以下是基于51单片机的SGP30传感器测量空气的程序: ``` #include <reg51.h> #include <stdio.h> #include <stdlib.h> sbit SCL=P2^1; // 定义I2C时钟引脚 sbit SDA=P2^0; // 定义I2C数据引脚 #define SGP30_ADDR 0x58 // 定义SGP30传感器地址 unsigned char cmd[3]={0x20, 0x08, 0x0f}; // 初始化命令 unsigned char buf[6]; // 存储传感器数据 void delay(int t) { int i,j; for(i=0;i<t;i++) for(j=0;j<120;j++); } void I2C_Start() { SDA=1; SCL=1; delay(1); SDA=0; delay(1); SCL=0; } void I2C_Stop() { SDA=0; SCL=1; delay(1); SDA=1; delay(1); } void I2C_Ack() { SDA=0; SCL=1; delay(1); SCL=0; SDA=1; } void I2C_NoAck() { SDA=1; SCL=1; delay(1); SCL=0; SDA=1; } unsigned char I2C_ReadByte() { unsigned char i, dat=0; SDA=1; for(i=0;i<8;i++) { SCL=1; delay(1); dat=dat<<1; dat|=SDA; SCL=0; delay(1); } return dat; } void I2C_WriteByte(unsigned char dat) { unsigned char i; for(i=0;i<8;i++) { SDA=(dat&0x80)>>7; dat<<=1; SCL=1; delay(1); SCL=0; delay(1); } SDA=1; SCL=1; delay(1); SCL=0; } unsigned char I2C_Read(unsigned char addr, unsigned char *buf, unsigned char len) { int i; I2C_Start(); I2C_WriteByte(addr|0x01); if(SDA) { I2C_Stop(); return 0; } for(i=0;i<len;i++) { buf[i]=I2C_ReadByte(); if(i==len-1) I2C_NoAck(); else I2C_Ack(); } I2C_Stop(); return 1; } unsigned char I2C_Write(unsigned char addr, unsigned char *buf, unsigned char len) { int i; I2C_Start(); I2C_WriteByte(addr&0xfe); if(SDA) { I2C_Stop(); return 0; } for(i=0;i<len;i++) { I2C_WriteByte(buf[i]); if(SDA) { I2C_Stop(); return 0; } } I2C_Stop(); return 1; } void SGP30_Init() { I2C_Write(SGP30_ADDR, cmd, 3); delay(1000); } unsigned char SGP30_Read(unsigned char *buf, unsigned char len) { unsigned char cmd[2]={0x20, 0x32}; // 读取数据命令 I2C_Write(SGP30_ADDR, cmd, 2); delay(100); return I2C_Read(SGP30_ADDR, buf, len); } void main() { unsigned int co2, tvoc; SGP30_Init(); while(1) { if(SGP30_Read(buf, 6)) { co2=((unsigned int)buf[0]<<8)|buf[1]; tvoc=((unsigned int)buf[3]<<8)|buf[4]; printf("CO2: %d ppm, TVOC: %d ppb\r\n", co2, tvoc); } delay(1000); } } ``` 这段程序主要通过I2C总线协议与SGP30传感器进行通信,读取传感器的CO2和TVOC浓度数据,并通过串口输出到终端显示。在程序中需要注意SGP30传感器的地址、初始化命令和读取数据命令等参数的设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隐居工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值