Sensirion SCD4x 二氧化碳传感器,STM32 I2C读取CO2浓度,温度,湿度值

一、描述

SCD4xSensirion公司的微型二氧化碳传感器。
采用内置的SHT4x 湿度和温度传感器实现片上信号补偿。

Sensirion官网: https://sensirion.com/
SCD4x传感器:https://sensirion.com/products/catalog/?filter_series=7d9d4a77-bd13-4545-8e68-f8e03c184ddd

在这里插入图片描述基本参数:

尺寸10.1 x 10.1 x 6.5 mm3
输出范围0 ppm – 40’000 ppm
宽电压2.4 – 5.5 V
高精度±(40 ppm + 5 %)
低功耗运行时< 0.4 mA avg. @ 5 V, 1 meas. / 5 minutes
通信协议I2C

传感器集成SHT4x温湿度传感器可同时输出温度湿度数据。

接口定义:
在这里插入图片描述
I2C地址0x62
在这里插入图片描述

I2C指令协议
见下图,SCD4x具有四种不同的I2C命令类型, “read I2C sequences”, “write I2C sequences”,“send I2C
command
” and “send command and fetch result” sequences.

在这里插入图片描述

二、部分函数代码

文中所参考的数据文档:“SCD40_SCD41_dataSheet.pdf”可去官网下载

1.开始周期测量。

1.具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.5.1”
2.信号更新间隔为5秒

bool SCD4x_StartPeriodicMeasurement(void)
{
	bool success = 0;
  if (periodic_Measurements_AreRunning)
  {
    #if SCD4x_ENABLE_DEBUGLOG
     printf("SCD4x_StartPeriodicMeasurement: periodic measurements are already running");
    #endif // if SCD4x_ENABLE_DEBUGLOG
    return (true);  //Maybe this should be false?
  }

  success = SCD4x_sendCommand(SCD4x_COMMAND_START_PERIODIC_MEASUREMENT);
  if (success)
    periodic_Measurements_AreRunning = true;
  return (success);
}

2.停止周期测量。

1.具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.5.3”
2.传感器在发出 STOP_PERIONAL_MEASURATION 命令后等待 500毫秒 后才会对其他命令作出响应。

bool SCD4x_stopPeriodicMeasurement(uint16_t delayTime)
{
  bool success = SCD4x_sendCommand(SCD4x_COMMAND_STOP_PERIODIC_MEASUREMENT);
	
	if(success)
	{
		periodic_Measurements_AreRunning = false;
		if (delayTime > 0)
    		delay1ms(delayTime);
		return true;
	}
  if (delayTime > 0)
    delay1ms(delayTime);
	
  return (false);
}

3.读取传感器数据。

1.具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.5.2”
2.每个信号更新间隔只能读出一次测量数据,因为读数时缓冲区被清空.
3.如果缓冲区中没有可用数据,传感器将返回 NACK

bool SCD4x_readMeasurement(uint16_t *co2, float *temperature, float *humidity, uint8_t *Error)
{
	uint8_t error = 0;
	uint8_t buffer[10] = {0};

  if (SCD4x_getDataReadyStatus() == false) // get_data_ready_status. see "SCD40_SCD41_Datasheet.pdf" 3.8.2
    return (false);

	SCD4x_SensorData.tempCO2.unsigned16 = 0;
	SCD4x_SensorData.tempHumidity.unsigned16 = 0;
	SCD4x_SensorData.tempTemperature.unsigned16 = 0;

	IIC_Start();
    IIC_Send_Byte( (SCD4x_ADDRESS<<1)&(~0x01)); //I2C Address + write
	IIC_Wait_Ack();
    IIC_Send_Byte(SCD4x_COMMAND_READ_MEASUREMENT >> 8);   //MSB
	IIC_Wait_Ack();
    IIC_Send_Byte(SCD4x_COMMAND_READ_MEASUREMENT & 0xFF); //LSB
	error = IIC_Wait_Ack();
	
  if ( error )
    return (false); //Sensor did not ACK

	error = 0;
    delay1ms(1); //Datasheet specifies this,  command execution time

	IIC_Start();
    IIC_Send_Byte( (SCD4x_ADDRESS<<1)|(0x01)); //I2C Address + read
	IIC_Wait_Ack();
	buffer[0] = IIC_Read_Byte(1); //read data and ack
	buffer[1] = IIC_Read_Byte(1);
	buffer[2] = IIC_Read_Byte(1);
	buffer[3] = IIC_Read_Byte(1);
	buffer[4] = IIC_Read_Byte(1);
	buffer[5] = IIC_Read_Byte(1);
	buffer[6] = IIC_Read_Byte(1);
	buffer[7] = IIC_Read_Byte(1);
	buffer[8] = IIC_Read_Byte(0); //read data and no ack
	IIC_Stop();

	uint8_t foundCrc = 0;
    uint8_t bytesToCrc[2]={0};
    for (uint8_t x = 0; x < 9; x++)
    {
      switch (x)
      {
      case 0:
      case 1:
        SCD4x_SensorData.tempCO2.bytes[x == 0 ? 1 : 0] = buffer[x]; // Store the two CO2 bytes in little-endian format
        bytesToCrc[x] = buffer[x]; // Calculate the CRC on the two CO2 bytes in the order they arrive
        break;
      case 3:
      case 4:
        SCD4x_SensorData.tempTemperature.bytes[x == 3 ? 1 : 0] = buffer[x]; // Store the two T bytes in little-endian format
        bytesToCrc[x % 3] = buffer[x]; // Calculate the CRC on the two T bytes in the order they arrive
        break;
      case 6:
      case 7:
        SCD4x_SensorData.tempHumidity.bytes[x == 6 ? 1 : 0] = buffer[x]; // Store the two RH bytes in little-endian format
        bytesToCrc[x % 3] = buffer[x]; // Calculate the CRC on the two RH bytes in the order they arrive
        break;
      default: // x == 2, 5, 8
        //Validate CRC
        foundCrc = SCD4x_computeCRC8(bytesToCrc, 2); // Calculate what the CRC should be for these two bytes
        if (foundCrc != buffer[x]) // CRC check error
        {
          #if SCD4x_ENABLE_DEBUGLOG		
          #endif // if SCD4x_ENABLE_DEBUGLOG
		  if(x==2)
			{error |= 0B1;} // CO2
		  if(x==5)
			{error |= 0B10;} // Temperature
		  if(x==8)
			{error |= 0B100;} // Humidity
        }
        break;
      }
    }

  if (error)
  {
	*Error = error;
    #if SCD4x_ENABLE_DEBUGLOG
    	printf("SCD4x_readMeasurement: encountered error reading SCD4x data.");
    #endif // if SCD4x_ENABLE_DEBUGLOG
    return (false);
  }
  // 返回解析后的数据
  *co2 = (uint16_t)SCD4x_SensorData.tempCO2.unsigned16; //ppm
  *temperature = -45 + (((float)SCD4x_SensorData.tempTemperature.unsigned16) * 175 / 65536);
  *humidity = ((float)SCD4x_SensorData.tempHumidity.unsigned16) * 100 / 65536;
	
  return (true); //Success! 
}

4.读取传感器序列号。

1.具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.9.2”
2.从SCD4x获取9个字节。并将48位序列号转换为ASCII字符。.
3.读出序列号可用于识别芯片和验证传感器。

bool SCD4x_getSerialNumber(char *serialNumber)
{
	uint8_t error = 0;
	uint8_t Crc = 0;
	
  if (periodic_Measurements_AreRunning)
  {
    #if SCD4x_ENABLE_DEBUGLOG
      printf("SCD4x_getSerialNumber: periodic measurements are running. Aborting");
    #endif // if SCD4x_ENABLE_DEBUGLOG
    return (false);
  }

  IIC_Start();
  IIC_Send_Byte( (SCD4x_ADDRESS<<1)&(~0x01)); //I2C Address + write
  IIC_Wait_Ack();
  IIC_Send_Byte(SCD4x_COMMAND_GET_SERIAL_NUMBER >> 8);   //MSB
  IIC_Wait_Ack();
  IIC_Send_Byte(SCD4x_COMMAND_GET_SERIAL_NUMBER & 0xFF); //LSB
  error = IIC_Wait_Ack();
	
  if ( error )
    return (false); //Sensor did not ACK

  delay1ms(1); //Datasheet specifies this

  IIC_Start();
  IIC_Send_Byte( (SCD4x_ADDRESS<<1)|(0x01)); //I2C Address + read
  error = IIC_Wait_Ack();

  if (error==0)
  {
    uint8_t bytesToCrc[2];
    int digit = 0;
    for (uint8_t  x = 0; x < 9; x++)
    {
      uint8_t incoming = IIC_Read_Byte(1); //read data and ack
	  if(x==8)
		{
			incoming = IIC_Read_Byte(0);  //read data and no ack
			IIC_Stop();
		}
      switch (x)
      {
      case 0: // The serial number arrives as: two bytes, CRC, two bytes, CRC, two bytes, CRC
      case 1:
      case 3:
      case 4:
      case 6:
      case 7:
        serialNumber[digit++] = SCD4x_convertHexToASCII(incoming >> 4); // Convert each nibble to ASCII
        serialNumber[digit++] = SCD4x_convertHexToASCII(incoming & 0x0F);
        bytesToCrc[x % 3] = incoming;
        break;
      default: // x == 2, 5, 8
        Crc = SCD4x_computeCRC8(bytesToCrc, 2); // Calculate what the CRC should be for these two bytes
        if (Crc != incoming) // Does this match the CRC byte from the sensor?
        {
          #if SCD4x_ENABLE_DEBUGLOG

          #endif // if SCD4x_ENABLE_DEBUGLOG
          error = true;
        }
        break;
      }
      serialNumber[digit] = 0; // NULL-terminate the string
    }
  }

  if (error)
  {
    #if SCD4x_ENABLE_DEBUGLOG
      printf("SCD4x_readSerialNumber: encountered error reading SCD4x data.");
    #endif // if SCD4x_ENABLE_DEBUGLOG
    return (false);
  }

  return (true); //Success!
}

5.传感器自检。

1.具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.9.3”
2.执行传感器自检指令,该指令需要 10秒 的执行时间。

bool SCD4x_performSelfTest(void)
{
  if (periodic_Measurements_AreRunning)
  {
    #if SCD4x_ENABLE_DEBUGLOG
			
    #endif // if SCD4x_ENABLE_DEBUGLOG
    return (false);
  }

  uint16_t response;

  #if SCD4x_ENABLE_DEBUGLOG
    printf("SCD4x_performSelfTest: delaying for 10 seconds...");
  #endif // if SCD4x_ENABLE_DEBUGLOG

  bool success = SCD4x_readRegister(SCD4x_COMMAND_PERFORM_SELF_TEST, &response, 10000);

  return (success && (response == 0x0000)); // word[0] = 0 → no malfunction detected
}

6.传感器恢复出厂设置。

1.具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.9.4”
2.PERFORM_FACTORY_RESET 命令用于重置存储在 EEPROM 中的所有配置设置。
3. 执行时间 1200ms

bool SCD4x_performFactoryReset(uint16_t delayTime)
{
  if (periodic_Measurements_AreRunning)
  {
    #if SCD4x_ENABLE_DEBUGLOG

    #endif // if SCD4x_ENABLE_DEBUGLOG
    return (false);
  }

  bool success = SCD4x_sendCommand(SCD4x_COMMAND_PERFORM_FACTORY_RESET);
  if (delayTime > 0)
    delay1ms(delayTime);
  return (success);
}

7.传感器软件复位。

1.具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.9.5”
2. Reinit 命令通过从 EEPROM 重新加载用户设置来重新初始化传感器。
3. 执行此命令前,传感器必须 停止周期测量
4. 指令执行时间 20ms

bool SCD4x_reInit(uint16_t delayTime)
{
  if (periodic_Measurements_AreRunning)
  {
    return (false); // 需停止周期测量
  }

  bool success = SCD4x_sendCommand(SCD4x_COMMAND_REINIT);
  if (delayTime > 0)
    delay1ms(delayTime);
  return (success);
}

8 查询传感器数据是否就绪

bool SCD4x_getDataReadyStatus(void)
{
  uint16_t response;
  bool success = SCD4x_readRegister(SCD4x_COMMAND_GET_DATA_READY_STATUS, &response, 1);

  if (success == false)
    return (false);

  // 0 至 11 bit 是 0 --> data not ready
  //else → data ready for read-out
  if ((response & 0x07ff) == 0x0000)
    return (false);
  return (true);
}

9.主机发送指令

下图为传感器IIC通信时的不同指令类型
具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.3”
IIC指令类型

9.1 发送指令,不带参数和CRC

“send I2C command sequence”

bool SCD4x_sendCommand(uint16_t command)
{
  uint8_t error = 0;
	
  IIC_Start();
  IIC_Send_Byte((SCD4x_ADDRESS<<1)&(~0x01));
  IIC_Wait_Ack();
  IIC_Send_Byte(command >> 8);   //MSB
  IIC_Wait_Ack();
  IIC_Send_Byte(command & 0xFF); //LSB
  error = IIC_Wait_Ack();
  IIC_Stop();
	
  if ( error )
    return (false); //Sensor did not ACK

  return (true);
}

9.2 发送指令,带参数和CRC

“write I2C sequence”

bool SCD4x_sendCommand_CmdData_CRC(uint16_t command, uint16_t arguments)
{
  uint8_t data[2];
  uint8_t error = 0;
  data[0] = arguments >> 8;
  data[1] = arguments & 0xFF;
  uint8_t crc = SCD4x_computeCRC8(data, 2); //Calc CRC on the arguments only, not the command

  IIC_Start();
  IIC_Send_Byte( (SCD4x_ADDRESS<<1)&(~0x01) );
  IIC_Wait_Ack();
  IIC_Send_Byte(command >> 8);     //MSB
  IIC_Wait_Ack();
  IIC_Send_Byte(command & 0xFF);   //LSB
  IIC_Wait_Ack();
  IIC_Send_Byte(arguments >> 8);   //MSB
  IIC_Wait_Ack();
  IIC_Send_Byte(arguments & 0xFF); //LSB
  IIC_Wait_Ack();
  IIC_Send_Byte(crc); //CRC
  error = IIC_Wait_Ack();
  IIC_Stop();
	
  if ( error )
    return (false); //Sensor did not ACK

  return (true);
}

9.3 发送指令,并读取一个16位数据

“read I2C sequence”
如果 IIC_Wait_Ack(); 返回0,且 CRC 校验正确,此函数返回true

bool SCD4x_readRegister(uint16_t registerAddress, uint16_t *response, uint16_t delayTime)
{
	uint8_t error = 0;
	uint8_t crc = 0;
	uint8_t data[2] = {0};
	
  IIC_Start();
  IIC_Send_Byte( (SCD4x_ADDRESS<<1)&(~0x01) ); //I2C Address + write
  IIC_Wait_Ack();
  IIC_Send_Byte(registerAddress >> 8);   //MSB
  IIC_Wait_Ack();
  IIC_Send_Byte(registerAddress & 0xFF); //LSB
  error = IIC_Wait_Ack();
  IIC_Stop();
	
  if ( error )
    return (false); //Sensor did not ACK

  delay1ms(delayTime);
	
  IIC_Start();
  IIC_Send_Byte( (SCD4x_ADDRESS<<1)|(0x01) ); //I2C Address + read
  IIC_Wait_Ack();
  data[0] = IIC_Read_Byte(1);
  data[1] = IIC_Read_Byte(1);
  crc = IIC_Read_Byte(0);
  IIC_Stop();  
	
  *response = (uint16_t)data[0] << 8 | data[1];
  uint8_t expectedCRC = SCD4x_computeCRC8(data, 2);
    if (crc == expectedCRC) // Return true if CRC check is OK
      return (true);
  
  return (false);
}

10 十六进制转ASCII

char SCD4x_convertHexToASCII(uint8_t digit)
{
  if (digit <= 9)
    return ( (char)(digit + 0x30) );
  else
    return ( (char)(digit + 0x41 - 10) ); // Use upper case for A-F
}

11 CRC计算

具体请阅读 “SCD40_SCD41_dataSheet.pdf”, 第“3.11”
参考: http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html
验证: http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
x8+x5+x4+1 = 0x31

uint8_t SCD4x_computeCRC8(uint8_t data[], uint8_t len)
{
  uint8_t crc = 0xFF; //Init with 0xFF

  for (uint8_t x = 0; x < len; x++)
  {
    crc ^= data[x]; // XOR-in the next input byte

    for (uint8_t i = 0; i < 8; i++)
    {
      if ((crc & 0x80) != 0)
        crc = (uint8_t)((crc << 1) ^ 0x31);
      else
        crc <<= 1;
    }
  }
	
  return crc; //No output reflection
}

三、传感器指令定义

//The default I2C address for the SCD4x is 0x62.
#define SCD4x_ADDRESS 0x62

//Available commands

//Basic Commands
#define SCD4x_COMMAND_START_PERIODIC_MEASUREMENT              0x21b1
#define SCD4x_COMMAND_READ_MEASUREMENT                        0xec05 // execution time: 1ms
#define SCD4x_COMMAND_STOP_PERIODIC_MEASUREMENT               0x3f86 // execution time: 500ms

//On-chip output signal compensation
#define SCD4x_COMMAND_SET_TEMPERATURE_OFFSET                  0x241d // execution time: 1ms
#define SCD4x_COMMAND_GET_TEMPERATURE_OFFSET                  0x2318 // execution time: 1ms
#define SCD4x_COMMAND_SET_SENSOR_ALTITUDE                     0x2427 // execution time: 1ms
#define SCD4x_COMMAND_GET_SENSOR_ALTITUDE                     0x2322 // execution time: 1ms
#define SCD4x_COMMAND_SET_AMBIENT_PRESSURE                    0xe000 // execution time: 1ms

//Field calibration
#define SCD4x_COMMAND_PERFORM_FORCED_CALIBRATION              0x362f // execution time: 400ms
#define SCD4x_COMMAND_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED  0x2416 // execution time: 1ms
#define SCD4x_COMMAND_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED  0x2313 // execution time: 1ms

//Low power
#define SCD4x_COMMAND_START_LOW_POWER_PERIODIC_MEASUREMENT    0x21ac
#define SCD4x_COMMAND_GET_DATA_READY_STATUS                   0xe4b8 // execution time: 1ms

//Advanced features
#define SCD4x_COMMAND_PERSIST_SETTINGS                        0x3615 // execution time: 800ms
#define SCD4x_COMMAND_GET_SERIAL_NUMBER                       0x3682 // execution time: 1ms
#define SCD4x_COMMAND_PERFORM_SELF_TEST                       0x3639 // execution time: 10000ms
#define SCD4x_COMMAND_PERFORM_FACTORY_RESET                   0x3632 // execution time: 1200ms
#define SCD4x_COMMAND_REINIT                                  0x3646 // execution time: 20ms

//Low power single shot - SCD41 only
#define SCD4x_COMMAND_MEASURE_SINGLE_SHOT                     0x219d // execution time: 5000ms
#define SCD4x_COMMAND_MEASURE_SINGLE_SHOT_RHT_ONLY            0x2196 // execution time: 50ms

四、写在最后

1.最后需要源码的朋友自己跳转下载就好。
2.欢迎交流学习
3.觉得还不错的话,就点个赞赞吧。

“SCD40_SCD41_dataSheet.pdf”: https://download.csdn.net/download/weixin_47800123/86732243
源码: https://download.csdn.net/download/weixin_47800123/87796757

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值