CCS811二氧化碳和TVOC传感器 HAL库 模拟IIC调试成功 适用于CubeMX CubeIDE

目录app

1、硬件链接oop

2、模拟IIC测试

头文件ui

C文件spa

3、CCS811过程.net

CCS811工做流程(官方文档)3d

1. [Boot Mode] 读取硬件ID调试

2. [Boot Mode] 读取状态值code

3. [Boot Mode] 切换到APP模式orm

4. [APP Mode] 读取状态值

5. [APP Mode] 设置测量周期

6. [APP Mode] 读取传感器值

CCS811代码(改编自文献2)

头文件

参考文献

1、硬件链接

VCC - 3.3V

SCL和SDA接IIC

WAK接地(也能够由单片机引脚控制)

 

2、模拟IIC

头文件

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

void IIC_Init(void);                		 
void IIC_Start(void);				
void IIC_Stop(void);	  			
void IIC_Send_Byte(uint8_t txd);			
uint8_t IIC_Read_Byte(unsigned char ack);
uint8_t IIC_Wait_Ack(void); 				
void IIC_Ack(void);					
void IIC_NAck(void);				

#endif

C文件

#include "my_iic.h"
#include "delay.h"

#define HT_SDA GPIO_PIN_7 //B7
#define HT_SCK GPIO_PIN_6 //B6

static void SDA_IN(){
 GPIO_InitTypeDef GPIO_InitStruct = {0};

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

  /*Configure GPIO pins : PAPin PAPin */
  GPIO_InitStruct.Pin = HT_SDA;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

static void SDA_OUT(){
 GPIO_InitTypeDef GPIO_InitStruct = {0};

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

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = HT_SDA;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void SDA_HIGH(){
  HAL_GPIO_WritePin(GPIOB, HT_SDA, GPIO_PIN_SET);
}

void SDA_LOW(){
  HAL_GPIO_WritePin(GPIOB, HT_SDA, GPIO_PIN_RESET);
}

void SCL_HIGH(){
  HAL_GPIO_WritePin(GPIOB, HT_SCK, GPIO_PIN_SET);
}

void SCL_LOW(){
  HAL_GPIO_WritePin(GPIOB, HT_SCK, GPIO_PIN_RESET);
}

GPIO_PinState read_sdaval(){
   return HAL_GPIO_ReadPin(GPIOB,HT_SDA);
}

void IIC_Start(void)
{
	SDA_OUT(); 

	SDA_HIGH();
	SCL_HIGH();
	delay_us(5);
	SDA_LOW();//START:when CLK is high,DATA change form high to low
	delay_us(5);
	SCL_LOW();
	delay_us(5);
}	  

void IIC_Stop(void)
{
	SDA_OUT();

	SCL_LOW();
	SDA_LOW();//STOP:when CLK is high DATA change form low to high
 	delay_us(5);
 	SCL_HIGH();
	SDA_HIGH();
	delay_us(5);							   	
}

uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	SDA_IN(); //
	SDA_HIGH();delay_us(1);
	SCL_HIGH();delay_us(1);
	while(read_sdaval())
	{
		ucErrTime++;
		delay_us(1);
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	SCL_LOW();
	return 0;  
} 

void IIC_Ack(void)
{
	SCL_LOW();
	SDA_OUT();

	SDA_LOW();
	delay_us(20);
	SCL_HIGH();
	delay_us(5);
	SCL_LOW();
}

void IIC_NAck(void)
{
	SCL_LOW();
	SDA_OUT();

	SDA_HIGH();
	delay_us(5);
	SCL_HIGH();
	delay_us(5);
	SCL_LOW();
}					 				     

void IIC_Send_Byte(uint8_t txd)
{                        
	uint8_t t;
	SDA_OUT();

	SCL_LOW();
    for(t=0;t<8;t++)
    {              
		if((txd&0x80)>>7)
			SDA_HIGH();
		else
			SDA_LOW();
		txd<<=1; 	  
		delay_us(50);
		SCL_HIGH();
		delay_us(50); 
		SCL_LOW();
		delay_us(50); 
		
    }	 

} 	    

uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();
    for(i=0;i<8;i++ )
	{
    	SCL_LOW();
        delay_us(50);
        SCL_HIGH();
        receive<<=1;
        delay_us(25);
        if(read_sdaval())
        {
        	receive++;
        }
		delay_us(25);
    }					 
    if (!ack)
        IIC_NAck();//nACK
    else
        IIC_Ack(); //ACK
    return receive;
}

3、CCS811过程

CCS811工做流程(官方文档)

1. [Boot Mode] 读取硬件ID

判断是否是0x81 (129),若是不是则IIC逻辑问题或者电平问题(供电电压在1.8V-3.6V,以及对应匹配电阻)

2. [Boot Mode] 读取状态值

若是APP_VALID值不为1,则内部MCU的程序不对,须要烧录(通常不会出现这个问题,也有人遇到过,见

CCS811二氧化碳传感器基于Arduino的升级固件(刷机)教程

3. [Boot Mode] 切换到APP模式

从boot模式切换到APP模式才能够进行测量。只需在地址0xF4寄存器内写1Byte操做。

4. [APP Mode] 读取状态值

经过读取状态值,判断切换到APP模式是否成功。状态位为FW_MODE

5. [APP Mode] 设置测量周期

在MEAS_MODE写入参数,例如1秒测一次写0x10。注意不一样周期切换时间可能须要数十秒的时间。

6. [APP Mode] 读取传感器值

从地址0x02读取8Byte数据,其中测量结果对应Byte位见下表

CCS811代码(改编自文献2)

头文件

#ifndef CCS811_h
#define CCS811_h

#include "delay.h"
#include "my_iic.h"

#define boolean uint8_t
#define byte 	uint8_t

typedef struct {
	uint16_t eco2;
	uint16_t tvoc;
	uint8_t status;
	uint8_t error_id;
	uint8_t hw_id;
	uint16_t raw_data;
} ccs811_measurement_t;

#define CCSADDR				0x5A<<1 // when I2C_ADDR pin is LOW
// #define CCSADDR					0x5B<<1 when I2C_ADDR pin is HIGH
#define READ            	0xB5  
#define WRIT            	0xB4   
// Registers for CCS811
#define STATUS          	0x00
#define MEAS_MODE       	0x01
#define ALG_RESULT_DATA 	0x02
#define RAW_DATA			0x03
#define ENV_DATA        	0x05
#define NTC        			0x06
#define THRESHOLDS      	0x10
#define BASELINE      		0x11
#define HW_ID           	0x20
#define HW_Version 			0x21
#define FW_Boot_Version		0x23
#define FW_App_Version  	0x24
#define ERROR_ID        	0xE0
#define SW_RESET        	0xFF

#define MODE0 				0x00    
#define MODE1 				0x10	
#define MODE2 				0x20	
#define MODE3 				0x30	
#define MODE4 				0x40	

extern ccs811_measurement_t CCS;

void readStatus(void);
void readHW_ID(void);
void readErrorID(void);
void readALG_RESULT_DATA(uint8_t *data);
void app_Start(void);
	
int readTVOC(void);
int readCO2(void);
void getData(void);
void compensate(float t, float rh);
void setMode(uint8_t mode);

void reset(void);
void sleep(void);
#endif

C文件

#include "CCS811.h"

ccs811_measurement_t CCS;

#define nWAKE_HIGN() LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_5)
#define nWAKE_LOW() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_5)
#define nINT_LOW() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_4)
#define nINT_HIGN() LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_4)

//查看是否有新数据 返回值 1:有
//						  0:没有
uint8_t CheckData_Ready(void)
{
		readStatus();
	if((CCS.status&8)==1) return 1;
	else return 0;
}

//读取一个bit数据
uint8_t CCS811_ReadOneByte(uint8_t ReadAddr)
{
	uint8_t temp=0;
		nWAKE_LOW();
		delay_us(50);//必须等待50us
		IIC_Start();  						
		//addr接地,7位地址为0x5A,读地址为AB,写地址AA
		IIC_Send_Byte(WRIT);	   //发送写命令
		if(IIC_Wait_Ack()){IIC_Stop(); return 255;}
		//else nINT=0;
		IIC_Send_Byte(ReadAddr);
		if(IIC_Wait_Ack()){IIC_Stop(); return 255;}
		//if(!IIC_Wait_Ack()){nINT=1;delay_ms(200);nINT=0;delay_ms(200);}
		delay_ms(1);
		IIC_Start();
		IIC_Send_Byte(READ);
		if(IIC_Wait_Ack()){IIC_Stop(); return 255;}
		temp=IIC_Read_Byte(0); 

		IIC_Stop();
		nWAKE_HIGN();
		delay_us(50);
	return temp;
}

void CCS811_WriteOneByte(uint8_t RegAddr,uint8_t DataToWrite)
{
	nWAKE_LOW();
	delay_us(50);
	IIC_Start(); 
	IIC_Send_Byte(WRIT);	   //发送写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(RegAddr);
	IIC_Wait_Ack();
	IIC_Send_Byte(DataToWrite);
	IIC_Wait_Ack();
	IIC_Stop();
	nWAKE_HIGN();
}
//测量数据前必须开启
void app_Start(void)
{
	nWAKE_LOW();
	delay_us(50);
	IIC_Start(); 
	IIC_Send_Byte(WRIT);	   //发送写命令
	if(IIC_Wait_Ack())
	{
	IIC_Stop();return;
	}
	IIC_Send_Byte(0xF4);
	delay_us(180);			//必须等待180us以上才可以收到应答
	if(IIC_Wait_Ack()){IIC_Stop();return;}
	IIC_Stop();
	nWAKE_HIGN();

}

void readStatus(void)
{
  CCS.status=CCS811_ReadOneByte(STATUS);
}


void readHW_ID(void)
{
	CCS.hw_id=CCS811_ReadOneByte(HW_ID);
}


void readErrorID(void)
{
	CCS.error_id=CCS811_ReadOneByte(ERROR_ID);
}

void setMode(uint8_t mode)
{
//	nWAKE=0;
//	delay_us(50);
	CCS811_WriteOneByte(MEAS_MODE,mode);
//	nWAKE=1;
}
	

//一次读8bit数据,前2bit为eco2数据,接着2bit为tvoc数据
//当status第五位为1时有新数据。
void getData(void)
{
	uint8_t i,buffer[8];
	
	nWAKE_LOW();
	delay_us(50);
	IIC_Start(); 
	IIC_Send_Byte(WRIT);	   //发送写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(ALG_RESULT_DATA);
	IIC_Wait_Ack();
	IIC_Stop();
	delay_us(50);
	IIC_Start(); 
	IIC_Send_Byte(READ);	   //发送写命令
	IIC_Wait_Ack();
	for(i=0;i<8-1;i++)
	buffer[i]=IIC_Read_Byte(1);

	buffer[i]=IIC_Read_Byte(0);
	IIC_Stop();
	nWAKE_HIGN();
	
	CCS.eco2 = ((uint16_t)buffer[0] << 8) + buffer[1];
	CCS.tvoc = ((uint16_t)buffer[2] << 8) + buffer[3];
	CCS.status=buffer[4];
	
}
//睡眠模式
void sleep(void)
{
	CCS811_WriteOneByte(MEAS_MODE,0x00000000);
}

//软重置,回到boot模式
void reset(void)
{
	uint8_t ResetData[4]={0X11,0XE5,0X72,0X8A};
	nWAKE_LOW();
	delay_us(50);
	IIC_Start(); 
	IIC_Send_Byte(WRIT);	   //发送写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(SW_RESET);
	IIC_Wait_Ack();
	IIC_Send_Byte(0X11);
	IIC_Wait_Ack();
	IIC_Send_Byte(0XE5);
	IIC_Wait_Ack();
	IIC_Send_Byte(0X72);
	IIC_Wait_Ack();
	IIC_Send_Byte(0X8A);
	IIC_Wait_Ack();
	IIC_Stop();
	nWAKE_HIGN();
}

main.c

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_Delay(1000);

  readHW_ID();
  printf("id:%d\r\n",CCS.hw_id);

  readStatus();
  printf("sta0:%d\r\n",CCS.status);

  app_Start();

  readStatus();
  printf("sta1:%d\r\n",CCS.status);

  setMode(0x10);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_Delay(998);
	  getData();
	  printf("eco2:%d",CCS.eco2);
	  printf("tvoc:%d\r\n",CCS.tvoc);
	  readStatus();
	  printf("sta:%d\r\n",CCS.status);
  }
  /* USER CODE END 3 */
}

参考文献

1.二氧化碳传感器CCS811简单的测试驱动_基于Arduino

2.ccs811调试指南