目录:
一、描述
SCD4x是Sensirion公司的微型二氧化碳传感器。
采用内置的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” 节
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