赞
踩
本文实现了对于甲醛浓度的监测,用的是SGP30模块,可同时监测甲醛浓度和二氧化碳的浓度。
#include "SGP30.H" //延时约1ms void I2Cdelay_ms(int ms) { uint a,b,c; for(a=ms;a>0;a--) for(b=10;b>0;b--) for(c=85;c>0;c--); } //模拟IIC用的短延时 us void I2CDelay (uchar t) { while(t--); } //I2C起始信号 void I2CStart(void) { SDA = 1; //发送起始条件的数据信号 SCL = 1; I2CDelay(50); //起始条件建立时间大于4.7us,延时 SDA = 0; //发送起始信号 I2CDelay(50); //起始条件锁定时间大于4μs SCL = 0; //钳住I2C总线,准备发送或接收数据 I2CDelay(50); } //I2C停止信号 void I2CStop(void) { SDA = 0; //发送结束条件的数据信号 SCL = 0; I2CDelay(50); SCL = 1; //发送结束条件的时钟信号 I2CDelay(50); //结束条件建立时间大于4μs SDA = 1; //发送I2C总线结束信号 I2CDelay(50); } //I2C写一个字节数据,返回ACK或者NACK uchar I2C_Write_Byte(uchar Write_Byte) //Sendbyte { uchar i; SCL=0; I2CDelay(10); for(i=0; i<8; i++) //要传送的数据长度为8位 { if(Write_Byte&0x80) //判断发送位 { SDA = 1; } else { SDA = 0; } I2CDelay(5); SCL=1; //输出SDA稳定后,拉高SCL给出上升沿,从机检测到后进行数据采样 I2CDelay(5); //保证时钟高电平周期大于4μs SCL=0; I2CDelay(5); Write_Byte <<= 1; } I2CDelay(1); SDA = 1; //8位发送完后释放数据线,准备接收应答位-ZLG I2CDelay(40); SCL = 1; //MCU告知SHT2X数据发送完毕,等待从机的应答信号 I2CDelay(40); /*以下是判断I2C总线接收应到应答信号是ACK还是NACK*/ if(SDA==1) //SDA为高,收到NACK { I2CDelay(40); SCL=0; return NACK; } else //SDA为低,收到ACK { I2CDelay(40); SCL=0; return ACK; } } //I2C读一个字节数据,入口参数用于控制应答状态,ACK或者NACK uchar I2C_Read_Byte(uchar AckValue)//receivebyte { uchar i,RDByte=0; SCL=0; //置时钟线为低,准备接收数据位 I2CDelay(40); SDA = 1; //释放总线,置数据线为输入方式 for (i=0; i<8; i++) { SCL = 1; //SCL高电平期间,采集SDA信号,并作为有效数据 //置时钟线为高使数据线上数据有效 I2CDelay(20); RDByte <<= 1; //移位 if(SDA==1) //采样获取数据 { RDByte |= 0x01; } else { RDByte &= 0xfe; } I2CDelay(10); SCL = 0; //下降沿,从机给出下一位值 I2CDelay(60); } /*以下是I2C总线发送应答信号ACK或者NACK*/ SDA = AckValue; //应答状态 I2CDelay(30); SCL = 1; I2CDelay(50); //时钟低电平周期大于4μs SCL = 0; //清时钟线,钳住I2C总线以便继续接收 I2CDelay(150); return RDByte; } //初始化IIC接口 void SGP30_Init(void) { SGP30_Write(0x20,0x03); // SGP30_ad_write(0x20,0x61); // SGP30_ad_write(0x01,0x00); } void SGP30_Write(uchar a, uchar b) { I2CStart(); I2C_Write_Byte(SGP30_write); //发送器件地址+写指令 I2C_Write_Byte(a); //发送控制字节 I2C_Write_Byte(b); I2CStop(); I2Cdelay_ms(100); } 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(); return(dat); }
#ifndef __SGP30_H #define __SGP30_H #include "reg52.h" #define uchar unsigned char #define uint unsigned int #define ulong unsigned long #define SGP30_read 0xb1 //SGP30的读地址 #define SGP30_write 0xb0 //SGP30的写地址 #define ACK 0 //应答信号 #define NACK 1 //非应答信号 sbit SCL = P1^2; //SGP30的SCL引脚定义 sbit SDA = P1^3; //SGP30的SDA引脚定义 //I2C起始信号 void I2CStart(void); //I2C停止信号 void I2CStop(void); //I2C写一个字节数据,返回ACK或者NACK uchar I2C_Write_Byte(uchar Write_Byte); //I2C读一个字节数据,入口参数用于控制应答状态,ACK或者NACK uchar I2C_Read_Byte(uchar AckValue); //初始化SGP30 void SGP30_Init(void); //向SGP30写数据 void SGP30_Write(uchar a, uchar b); //从SGP30读数据 ulong SGP30_Read(void); void I2Cdelay_ms(int ms); #endif
SGP30模块采用的是IIC的通信方式,需要占用两个引脚,其中SCL引脚连接至单片机的P12引脚,SDA引脚连接至单片机的P11引脚。
首先需要在main函数文件里面调用sgp30.h文件,在void main里面进行如下的初始化:
unsigned int TVOCData;//定义TVOC浓度变量 unsigned long sgp30_dat; SGP30_Init(); //初始化SGP30 I2Cdelay_ms(100); SGP30_Write(0x20,0x08); sgp30_dat = SGP30_Read();//读取SGP30的值 TVOCData = sgp30_dat & 0x0000ffff; //SGP30模块开机需要一定时间初始化,TVOC为0ppd且恒定不变,上电后每隔500ms读取一次 //SGP30模块的值,如果CO2浓度为400ppm,TVOC为0ppd,则屏幕闪烁显示“正在检测中...”,直到SGP30模块初始化完成。 while(TVOCData == 0) { SGP30_Write(0x20,0x08); sgp30_dat = SGP30_Read();//读取SGP30的值 TVOCData = sgp30_dat & 0x0000ffff; //取出TVOC值 OLED_ShowString(32,3,"Init...",16); I2Cdelay_ms(400); OLED_ShowString(32,3," ",16); I2Cdelay_ms(100); }
调用的时候只需要通过SGP30_Write函数和SGP30_Write函数进行数据的读取即可。
//检测TVO值
SGP30_Write(0x20,0x08);
sgp30_dat = SGP30_Read();//读取SGP30的值
TVOCData = sgp30_dat & 0x0000ffff; //取出TVOC值
接下来也会继续分享这一段时间做的设计,希望能够帮助到大家,无偿分享,码字不易大家多多点赞收藏支持哦!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。