Skip to content

Commit 4e6d481

Browse files
committed
Add example for SCD40 FRC
1 parent 8f05bc3 commit 4e6d481

File tree

1 file changed

+216
-0
lines changed

1 file changed

+216
-0
lines changed
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
* Copyright (c) 2020, Sensirion AG
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* * Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* * Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* * Neither the name of Sensirion AG nor the names of its
16+
* contributors may be used to endorse or promote products derived from
17+
* this software without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
32+
#include <Wire.h>
33+
34+
// SCD40
35+
const int16_t SCD_ADDRESS = 0x62;
36+
37+
void setup() {
38+
float co2, temperature, humidity;
39+
uint16_t calibration;
40+
uint8_t data[12], counter, repetition;
41+
uint8_t ret;
42+
43+
Serial.begin(115200);
44+
// wait for serial connection from PC
45+
// comment the following line if you'd like the output
46+
// without waiting for the interface being ready
47+
while(!Serial);
48+
49+
// init I2C
50+
Wire.begin();
51+
52+
// wait until sensors are ready, > 1000 ms according to datasheet
53+
delay(1000);
54+
55+
// start scd measurement in periodic mode, will update every 2 s
56+
Wire.beginTransmission(SCD_ADDRESS);
57+
Wire.write(0x21);
58+
Wire.write(0xb1);
59+
Wire.endTransmission();
60+
61+
// wait for first measurement to be finished
62+
delay(2000);
63+
64+
Serial.println("# CO2 values before recalibration");
65+
66+
// measure 5 times
67+
for(repetition = 0; repetition < 5; repetition++) {
68+
// read measurement data: 2 bytes co2, 1 byte CRC,
69+
// 2 bytes T, 1 byte CRC, 2 bytes RH, 1 byte CRC,
70+
// 2 bytes sensor status, 1 byte CRC
71+
// stop reading after 12 bytes (not used)
72+
// other data like ASC not included
73+
Wire.requestFrom(SCD_ADDRESS, 12);
74+
counter = 0;
75+
while (Wire.available()) {
76+
data[counter++] = Wire.read();
77+
}
78+
79+
// floating point conversion according to datasheet
80+
co2 = (float)((uint16_t)data[0] << 8 | data[1]);
81+
// convert T in degC
82+
temperature = -45 + 175 * (float)((uint16_t)data[3] << 8 | data[4]) / 65536;
83+
// convert RH in %
84+
humidity = 100 * (float)((uint16_t)data[6] << 8 | data[7]) / 65536;
85+
86+
Serial.print("# ");
87+
Serial.print(co2);
88+
Serial.print("\t");
89+
Serial.print(temperature);
90+
Serial.print("\t");
91+
Serial.print(humidity);
92+
Serial.println();
93+
94+
delay(2000);
95+
}
96+
97+
// wait for another 5 minutes to equilibrate sensor to ambient
98+
Serial.println("# Waiting 5 minutes for equilibration");
99+
//delay(5 * 60 * 1000);
100+
101+
// stop scd measurement
102+
Wire.beginTransmission(SCD_ADDRESS);
103+
Wire.write(0x3f);
104+
Wire.write(0x86);
105+
ret = Wire.endTransmission();
106+
Serial.println(ret);
107+
108+
109+
// wait for sensor
110+
//delay(20);
111+
112+
// assuming an external reference shows 350 ppm
113+
calibration = 650;
114+
115+
// prepare buffer with data for calibration
116+
// calculate CRC for each 2 bytes of data
117+
data[0] = (calibration & 0xff00) >> 8;
118+
data[1] = calibration & 0x00ff;
119+
data[2] = CalcCrc(data);
120+
121+
// send command for perform_forced_recalibration
122+
Wire.beginTransmission(SCD_ADDRESS);
123+
Wire.write(0x36);
124+
Wire.write(0x2F);
125+
// append data for calibration
126+
// 2 bytes calibraion, CRC
127+
Wire.write(data[0]);
128+
Wire.write(data[1]);
129+
Wire.write(data[2]);
130+
ret = Wire.endTransmission();
131+
Serial.println(ret);
132+
133+
delay(400);
134+
135+
// read data: 2 bytes correction, 1 byte CRC
136+
Wire.requestFrom(SCD_ADDRESS, 3);
137+
counter = 0;
138+
while (Wire.available()) {
139+
data[counter++] = Wire.read();
140+
}
141+
142+
if(CalcCrc(data) != data[2])
143+
Serial.println("# ERROR: recalibration CRC return value");
144+
145+
calibration = ((uint16_t)data[0] << 8 | data[1]);
146+
147+
Serial.print("# Value after recalibration\n# ");
148+
Serial.println(calibration-32768);
149+
150+
// output format
151+
Serial.println("CO2(ppm)\tTemperature(degC)\tRelativeHumidity(percent)");
152+
153+
// start scd measurement again in periodic mode, will update every 2 s
154+
Wire.beginTransmission(SCD_ADDRESS);
155+
Wire.write(0x21);
156+
Wire.write(0xb1);
157+
Wire.endTransmission();
158+
159+
// wait for first measurement to be finished
160+
delay(4000);
161+
}
162+
163+
void loop() {
164+
float co2, temperature, humidity;
165+
uint8_t data[12], counter;
166+
167+
// send read data command
168+
Wire.beginTransmission(SCD_ADDRESS);
169+
Wire.write(0xec);
170+
Wire.write(0x05);
171+
Wire.endTransmission();
172+
173+
// read measurement data: 2 bytes co2, 1 byte CRC,
174+
// 2 bytes T, 1 byte CRC, 2 bytes RH, 1 byte CRC,
175+
// 2 bytes sensor status, 1 byte CRC
176+
// stop reading after 12 bytes (not used)
177+
// other data like ASC not included
178+
Wire.requestFrom(SCD_ADDRESS, 12);
179+
counter = 0;
180+
while (Wire.available()) {
181+
data[counter++] = Wire.read();
182+
}
183+
184+
// floating point conversion according to datasheet
185+
co2 = (float)((uint16_t)data[0] << 8 | data[1]);
186+
// convert T in degC
187+
temperature = -45 + 175 * (float)((uint16_t)data[3] << 8 | data[4]) / 65536;
188+
// convert RH in %
189+
humidity = 100 * (float)((uint16_t)data[6] << 8 | data[7]) / 65536;
190+
191+
Serial.print(co2);
192+
Serial.print("\t");
193+
Serial.print(temperature);
194+
Serial.print("\t");
195+
Serial.print(humidity);
196+
Serial.println();
197+
198+
// wait 2 s for next measurement
199+
delay(2000);
200+
}
201+
202+
// calculate CRC according to datasheet section 5.17
203+
uint8_t CalcCrc(uint8_t data[2]) {
204+
uint8_t crc = 0xFF;
205+
for(int i = 0; i < 2; i++) {
206+
crc ^= data[i];
207+
for(uint8_t bit = 8; bit > 0; --bit) {
208+
if(crc & 0x80) {
209+
crc = (crc << 1) ^ 0x31u;
210+
} else {
211+
crc = (crc << 1);
212+
}
213+
}
214+
}
215+
return crc;
216+
}

0 commit comments

Comments
 (0)