CCS811二氧化碳传感器详解(STM32)

目录

一、介绍

二、传感器原理

1.原理图

2.引脚描述

3.工作原理介绍 

三、程序设计

main.c文件

ccs811.h文件

ccs811.c文件

四、实验效果 

五、资料获取

项目分享


一、介绍

        CCS811模块是一种气体传感器,可以测量环境中TVOC(总挥发性有机物质)浓度和eCO2(二氧化碳)浓度,作为衡量空气质量(IAQ)的指标。它内部还集成了MCU,使得这款传感器具有了板载处理能力,在无需主机干预的情况下,即可提供等效二氧化碳等级或总挥发性有机化合物(TVOc)指标。

以下是二氧化碳传感器的参数:

型号

CCS811

工作电压

1.8~3.6V(推荐3.3V

工作电流

20mA

工作温度

-5~50

存储温度

-40~125

检测范围

400~5000ppm

通信接口

IIC

哔哩哔哩视频:

CCS811二氧化碳传感器详解(STM32)

(资料分享见文末) 

二、传感器原理

1.原理图

这里需要说明一下,SDASCL大家都比较熟悉,但是INTWAK就少见了,在这款模块中,INT相当于复位引脚,CCS811芯片内部集成的单片机程序跑飞之后可以将该引脚接地复位,同时需要WAK为低电平的时候SDASCL才能正常通信

2.引脚描述

引脚名称

描述

VCC

供给电压DC 3.3V

GND

地线

SCL

IIC时钟线

SDA

IIC数据线

WAK

低电平使能

INT

中断

RST

复位

ADD

地址选择位

3.工作原理介绍 

    CCS811-811是一种低功耗的数字气体传感器,集成了CCS801传感器和8MCU(带模数转换器(ADC)),用来检测室内的空气质量,包括二氧化碳(Co2)和广泛的挥发性有机化合物气体(VOCs,产品的低功耗特性可用在环境监测设备上,灵敏度高,智能算法计算TVOC/eCO2数值并输出IIC信号可直接与单片机通信。模块的主要特点:检测室内空气质量的金属氧化物(MOX)传感器,集成了8MCU用于运算第一级算法,集成了12ADC用于传感器读数和数字化转换,IIC从属接口可直接接入主控系统复位/中断控制。

三、程序设计

1.使用STM32F103C8T6读取CCS811二氧化碳传感器采集的数据,通过串口发送至电脑

2.将读取得到信息数据同时在OLED上显示

CCS811_SCL

PB6

CCS811_SDA

PB7

CCS811_WAK

PB5

OLED_SCL

PB11

OLED_SDA

PB10

串口

串口1

main.c文件

#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "ccs811.h"

/*****************辰哥单片机设计******************
											STM32
 * 项目			:	CCS811二氧化碳传感器实验                     
 * 版本			: V1.0
 * 日期			: 2024.8.28
 * MCU			:	STM32F103C8T6
 * 接口			:	参看ccs811.h							
 * BILIBILI	:	辰哥单片机设计
 * CSDN			:	辰哥单片机设计
 * 作者			:	辰哥 

**********************BEGIN***********************/

float co2;
u8 buff[30];//参数显示缓存数组


int main(void)
{ 
	
  SystemInit();//配置系统时钟为72M	
	delay_init(72);
	LED_Init();
	LED_On();
	CCS811_Init();
	USART1_Config();//串口初始化
	
	OLED_Init();
	printf("Start \n");
	delay_ms(1000);
	
	OLED_Clear();
	//显示“二氧化碳:”
	OLED_ShowChinese(0,0,0,16,1);
	OLED_ShowChinese(16,0,1,16,1);
	OLED_ShowChinese(32,0,2,16,1);
	OLED_ShowChinese(48,0,3,16,1);
	OLED_ShowChar(64,0,':',16,1);

  while (1)
  {
		LED_Toggle();
		co2 = CCS811_GetData();

		OLED_ShowNum(40,20,co2,4,16,1);
		OLED_ShowString(80,20,"ppm",16,1);
		delay_ms(50);	//延时50ms

  }
}

ccs811.h文件

#ifndef __CCS811_H
#define	__CCS811_H
#include "stm32f10x.h"
#include "delay.h"
#include "sys.h"

/*****************辰哥单片机设计******************
											STM32
 * 文件			:	CCS811二氧化碳传感器h文件                   
 * 版本			: V1.0
 * 日期			: 2024.8.28
 * MCU			:	STM32F103C8T6
 * 接口			:	见代码							
 * BILIBILI	:	辰哥单片机设计
 * CSDN			:	辰哥单片机设计
 * 作者			:	辰哥

**********************BEGIN***********************/


/***************根据自己需求更改****************/
// CCS811 GPIO宏定义

#define		CCS811_IIC_CLK										RCC_APB2Periph_GPIOB
#define 	CCS811_IIC_PORT										GPIOB
#define 	CCS811_IIC_SDA_PIN								GPIO_Pin_7	
#define 	CCS811_IIC_SCL_PIN								GPIO_Pin_6	
#define   CCS811_WAK_PORT										GPIOB
#define		CCS811_WAK_PIN										GPIO_Pin_5

//IO操作函数	 
#define CCS811_IIC_SCL    PBout(6) 		//SCL
#define CCS811_IIC_SDA    PBout(7) 		//SDA	 
#define CCS811_READ_SDA   PBin(7) 		//输入SDA 


/*********************END**********************/

//CCS811
#define CCS811_Add  0x5A<<1
#define STATUS_REG 0x00						//状态寄存器
#define MEAS_MODE_REG 0x01				//测量模式和条件寄存器
#define ALG_RESULT_DATA 0x02			//算法结果。最高有效 2 个字节包含等效 CO2 (eCO2) 水平的 ppm 估计值,最低有效 2 个字节包含总 VOC 水平的 ppb 估计值
#define ENV_DATA 0x05
#define NTC_REG 0x06
#define THRESHOLDS 0x10
#define BASELINE 0x11
#define HW_ID_REG 0x20						//硬件 ID 值为 0x81
#define ERROR_ID_REG 0xE0					//错误 ID。当状态寄存器报告错误时,它的源位于此寄存器中
#define APP_START_REG 0xF4
#define SW_RESET 0xFF
#define CCS_811_ADDRESS 0x5A
#define GPIO_WAKE 0x5
#define DRIVE_MODE_IDLE 0x0
#define DRIVE_MODE_1SEC 0x10
#define DRIVE_MODE_10SEC 0x20
#define DRIVE_MODE_60SEC 0x30
#define INTERRUPT_DRIVEN 0x8
#define THRESHOLDS_ENABLED 0x4

void CCS811_Init(void);
void ON_CCS811(void);
void CCS811_EN(void);
void OFF_CCS811(void);

u16 CCS811_GetData(void);


u8 CCS811_Single_WriteI2C_byte(u8 Slave_Address,u8 REG_Address,u8 data);
u8 CCS811_Single_MWriteI2C_byte(u8 Slave_Address,u8 REG_Address,u8 const *data,u8 length);
u8 CCS811_Single_ReadI2C(u8 Slave_Address,u8 REG_Address,u8 *REG_data,u8 length);

#endif

ccs811.c文件

#include "ccs811.h"


/*****************辰哥单片机设计******************
											STM32
 * 文件			:	CCS811二氧化碳传感器c文件                   
 * 版本			: V1.0
 * 日期			: 2024.8.28
 * MCU			:	STM32F103C8T6
 * 接口			:	见代码							
 * BILIBILI	:	辰哥单片机设计
 * CSDN			:	辰哥单片机设计
 * 作者			:	辰哥

**********************BEGIN***********************/
u8 MeasureMode,Status,Error_ID;
u8 Information[10];
u8 BUF[12];

typedef struct {
u16 eco2;
u16 tvoc;
u8 status;
u8 error_id;
u16 raw_data;
} ccs811_measurement_t;
ccs811_measurement_t CCS;


u16 car_num;


 void CCS811_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(CCS811_IIC_CLK,ENABLE);//先使能外设IO PORTB时钟 
		
  GPIO_InitStructure.GPIO_Pin = CCS811_IIC_SDA_PIN|CCS811_IIC_SCL_PIN;	 // 端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
  GPIO_Init(CCS811_IIC_PORT, &GPIO_InitStructure);					 //根据设定参数初始化GPIO 
	
	CCS811_IIC_SCL = 1;
	CCS811_IIC_SDA = 1;
	
	CCS811_EN();
	CCS811_Single_ReadI2C(CCS811_Add,0x00,&Status,1);
	 CCS811_Single_ReadI2C(CCS811_Add,0xE0,&Error_ID,1);
	 CCS811_Single_ReadI2C(CCS811_Add,0x02,BUF,8);
	 CCS811_Single_ReadI2C(CCS811_Add,0x20,Information,1);  //Read CCS's information  ,ID
}

//CCS811引脚输出模式控制
void CCS811_IIC_SDA_OUT(void)//SDA输出方向配置
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	
	GPIO_InitStructure.GPIO_Pin=CCS811_IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//SDA推挽输出
	GPIO_Init(CCS811_IIC_PORT,&GPIO_InitStructure); 						

}

void CCS811_IIC_SDA_IN(void)//SDA输入方向配置
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	
	GPIO_InitStructure.GPIO_Pin=CCS811_IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//SCL上拉输入
	GPIO_Init(CCS811_IIC_PORT,&GPIO_InitStructure);
	
}

u16 CCS811_GetData(void)
{
	int car;
	//CCS811  CO2数据采集
	 ON_CCS811(); 					   	//nWAKE pin is asserted at least 50μs before the transaction and kept asserted throughout,nWAKE pin is active low     
	 CCS811_Single_ReadI2C(CCS811_Add,0x00,&Status,1);
	 CCS811_Single_ReadI2C(CCS811_Add,0xE0,&Error_ID,1);
	 CCS811_Single_ReadI2C(CCS811_Add,0x02,BUF,8);
	 CCS811_Single_ReadI2C(CCS811_Add,0x20,Information,1);  //Read CCS's information  ,ID
	 OFF_CCS811(); 
	 CCS.eco2= (u16)BUF[0]*256+BUF[1];
	 CCS.tvoc= (u16)BUF[2]*256+BUF[3];
	 Information[0]=0;
	 car=(float)CCS.eco2;  //二氧化碳
	 
	 return car;
}



IIC起始函数//
/*
IIC起始:当SCL处于高电平期间,SDA由高电平变成低电平出现一个下降沿,然后SCL拉低
*/
u8 CCS811_IIC_Start(void)
{
	
	  CCS811_IIC_SDA_OUT();
		CCS811_IIC_SDA = 1; 
		delay_us(5);	//延时保证时钟频率低于40K,以便从机识别
		CCS811_IIC_SCL = 1;
		delay_us(5);//延时保证时钟频率低于40K,以便从机识别
		//if(!CCS811_READ_SDA) return 0;//SDA线为低电平则总线忙,退出
		CCS811_IIC_SDA = 0;   //SCL处于高电平的时候,SDA拉低
		delay_us(5);
	  //if(CCS811_READ_SDA) return 0;//SDA线为高电平则总线出错,退出
		CCS811_IIC_SCL = 0;
	  delay_us(5);
	  return 1;
}
//**************************************
//IIC停止信号
/*
IIC停止:当SCL处于高电平期间,SDA由低电平变成高电平出现一个上升沿
*/
//**************************************
void CCS811_IIC_Stop(void)
{
		CCS811_IIC_SDA_OUT();
    CCS811_IIC_SDA = 0;
		CCS811_IIC_SCL = 0;
		delay_us(5);
		CCS811_IIC_SCL = 1;
		delay_us(5);
		CCS811_IIC_SDA = 1;//当SCL处于高电平期间,SDA由低电平变成高电平             //延时
}
//**************************************
//IIC发送应答信号
//入口参数:ack (0:ACK 1:NAK)
/*
应答:当从机接收到数据后,向主机发送一个低电平信号
先准备好SDA电平状态,在SCL高电平时,主机采样SDA
*/
//**************************************
void CCS811_IIC_SendACK(u8 i)
{
		CCS811_IIC_SDA_OUT();
    if(1==i)
			CCS811_IIC_SDA = 1;	             //准备好SDA电平状态,不应答
    else 
			CCS811_IIC_SDA = 0;  						//准备好SDA电平状态,应答 	
	  CCS811_IIC_SCL = 1;                    //拉高时钟线
    delay_us(5);                 //延时
    CCS811_IIC_SCL = 0 ;                  //拉低时钟线
    delay_us(5);    
} 
///等待从机应答
/*
当本机(主机)发送了一个数据后,等待从机应答
先释放SDA,让从机使用,然后采集SDA状态
*/
/
u8 CCS811_IIC_WaitAck(void) 	 //返回为:=1有ACK,=0无ACK
{	
	uint16_t i=0;
	CCS811_IIC_SDA_IN();
	CCS811_IIC_SDA = 1;delay_us(1);	        //释放SDA
	CCS811_IIC_SCL = 1;delay_us(1);         //SCL拉高进行采样
	while(CCS811_READ_SDA)//等待SDA拉低
	{
		i++;      //等待计数
		if(i==500)//超时跳出循环
		break;
		
	}
	if(CCS811_READ_SDA)//再次判断SDA是否拉低
	{
		CCS811_IIC_SCL = 0; 
		return RESET;//从机应答失败,返回0
	}
  delay_us(5);//延时保证时钟频率低于40K,
	CCS811_IIC_SCL = 0;
	delay_us(5); //延时保证时钟频率低于40K,
	CCS811_IIC_SDA_OUT();
	return SET;//从机应答成功,返回1
}
//**************************************
//向IIC总线发送一个字节数据
/*
一个字节8bit,当SCL低电平时,准备好SDA,SCL高电平时,从机采样SDA
*/
//**************************************
void CCS811_IIC_SendByte(u8 dat)
{  u8 i;
	CCS811_IIC_SDA_OUT();
	CCS811_IIC_SCL = 0;//SCL拉低,给SDA准备
  for (i=0; i<8; i++)         //8位计数器
  {
		if(dat&0x80)//SDA准备
		CCS811_IIC_SDA = 1;  
		else 
		CCS811_IIC_SDA = 0;
    CCS811_IIC_SCL = 1;                //拉高时钟,给从机采样
    delay_us(5);        //延时保持IIC时钟频率,也是给从机采样有充足时间
    CCS811_IIC_SCL = 0;                //拉低时钟,给SDA准备
    delay_us(5); 		  //延时保持IIC时钟频率
		dat <<= 1;          //移出数据的最高位  
  }
	delay_us(10);
}
//**************************************
//从IIC总线接收一个字节数据
//**************************************
u8 CCS811_IIC_RecvByte()
{
    u8 i;
    u8 dat = 0;
		CCS811_IIC_SDA_IN();
    CCS811_IIC_SDA = 1;//释放SDA,给从机使用
    delay_us(5);         //延时给从机准备SDA时间            
    for (i=0; i<8; i++)         //8位计数器
    { 
		  dat <<= 1;
			
      CCS811_IIC_SCL = 1;                //拉高时钟线,采样从机SDA
     
		  if(CCS811_READ_SDA) //读数据    
		   dat |=0x01;      
       delay_us(5);     //延时保持IIC时钟频率		
       CCS811_IIC_SCL = 0;           //拉低时钟线,处理接收到的数据
       delay_us(5);   //延时给从机准备SDA时间
    } 
    return dat;
}
//**************************************
//向IIC设备写入一个字节数据
//**************************************
u8 CCS811_Single_WriteI2C_byte(u8 Slave_Address,u8 REG_Address,u8 data)
{
	  if(CCS811_IIC_Start()==0)  //起始信号
		{CCS811_IIC_Stop(); return RESET;}           

    CCS811_IIC_SendByte(Slave_Address);   //发送设备地址+写信号
 	  if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop(); return RESET;}
   
		CCS811_IIC_SendByte(REG_Address);    //内部寄存器地址,
 	  if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop(); return RESET;}
   
		CCS811_IIC_SendByte(data);       //内部寄存器数据,
	  if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop(); return RESET;}
		
		CCS811_IIC_Stop();   //发送停止信号
		
		return SET;
}

u8 CCS811_Single_MWriteI2C_byte(u8 Slave_Address,u8 REG_Address,u8 const *data,u8 length)
{
	  if(CCS811_IIC_Start()==0)  //起始信号
		{CCS811_IIC_Stop();return RESET;}           

    CCS811_IIC_SendByte(Slave_Address);   //发送设备地址+写信号
 	  if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop();return RESET;}
   
		CCS811_IIC_SendByte(REG_Address);    //内部寄存器地址,
 	  if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop();return RESET;}
 
	while(length)
	{
		CCS811_IIC_SendByte(*data++);       //内部寄存器数据,
	   if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop(); return RESET;}           //应答
		length--;
	}
	//	CCS811_IIC_SendByte(*data);       //内部寄存器数据,
 	//	if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop(); return RESET;}
		CCS811_IIC_Stop();   //发送停止信号		
		return SET;
}

//**************************************
//从IIC设备读取一个字节数据
//**************************************
u8 CCS811_Single_ReadI2C(u8 Slave_Address,u8 REG_Address,u8 *REG_data,u8 length)
{
 if(CCS811_IIC_Start()==0)  //起始信号
		{CCS811_IIC_Stop();return RESET;}          
	 
	CCS811_IIC_SendByte(Slave_Address);    //发送设备地址+写信号
		if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop()	;return RESET;} 
	
	CCS811_IIC_SendByte(REG_Address);     //发送存储单元地址
 	if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop();return RESET;} 
	
	if(CCS811_IIC_Start()==0)  //起始信号
			{CCS811_IIC_Stop(); return RESET;}            

	CCS811_IIC_SendByte(Slave_Address+1);  //发送设备地址+读信号
 	if(!CCS811_IIC_WaitAck()){CCS811_IIC_Stop(); return RESET;}
	
	while(length-1)
	{
		*REG_data++=CCS811_IIC_RecvByte();       //读出寄存器数据
		CCS811_IIC_SendACK(0);               //应答
		length--;
	}
	*REG_data=CCS811_IIC_RecvByte();  
	CCS811_IIC_SendACK(1);     //发送停止传输信号
	CCS811_IIC_Stop();                    //停止信号
	return SET;
}




void CCS811_EN()
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//先使能外设IO PORTB时钟 
		
  GPIO_InitStructure.GPIO_Pin = CCS811_WAK_PIN;	 // 端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
  GPIO_Init(CCS811_WAK_PORT, &GPIO_InitStructure);					 //根据设定参数初始化GPIO 
	
	GPIO_ResetBits(CCS811_WAK_PORT,CCS811_WAK_PIN);
}

void ON_CCS811()
{
	GPIO_ResetBits(CCS811_WAK_PORT,CCS811_WAK_PIN);
}
void OFF_CCS811()
{
	GPIO_SetBits(CCS811_WAK_PORT,CCS811_WAK_PIN);
}

四、实验效果 

五、资料获取

项目分享

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值