Skip to content

Commit 5f200b2

Browse files
authored
Merge pull request Sensirion#4 from Sensirion/add_sen5x_snippets
added SEN5x Snippets
2 parents a6403e8 + 94bb5b1 commit 5f200b2

File tree

9 files changed

+1703
-0
lines changed

9 files changed

+1703
-0
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ All samples in this directory share the same format; as such, you can follow the
4141
|[SEN44_SCD40_I2C_example](/SEN44_SCD40_I2C_example)|I2C|Example using SEN44 with SCD4x|
4242
|[SEN44_UART_minimal_example](/SEN44_UART_minimal_example)|UART|Basic example for UART (Serial) interface|
4343

44+
## SEN5x
45+
|Name|Protocol|Description|
46+
|----|--------|-----------|
47+
|[SEN5x_I2C_minimal_example](/SEN5x_I2C_minimal_example)|I2C|Basic example for I2C|
48+
|[SEN5x_I2C_config_STAR_example](/SEN5x_I2C_config_STAR_example)|I2C|Example configuration of STAR|
49+
|[SEN5x_I2C_config_coldstart_example](/SEN5x_I2C_config_coldstart_example)|I2C|Change T offset for cold start compensation|
50+
|[SEN5x_I2C_config_warmstart_example](/SEN5x_I2C_config_warmstart_example)|I2C|Change T behaviour in warm start scenario|
51+
|[SEN5x_I2C_change_VOC_parameters_example](/SEN5x_I2C_change_VOC_parameters_example)|I2C|Change VOC parameters over I2C|
52+
|[SEN5x_I2C_change_NOx_parameters_example](/SEN5x_I2C_change_NOx_parameters_example)|I2C|Change NOx parameters over I2C|
53+
|[SEN5x_I2C_read_raw](/SEN5x_I2C_read_raw)|I2C|Example for reading raw VOC and NOX values from the sensor over I2C|
54+
|[SEN5x_I2C_switch_measurement_mode](/SEN5x_I2C_switch_measurement_mode)|I2C|Example for switching between gas only and full measurement mode (requires FW2.0) over I2C|
55+
56+
4457
## SFA30
4558
|Name|Protocol|Description|
4659
|----|--------|-----------|
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
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+
// SEN5x
35+
const int16_t SEN55_ADDRESS = 0x69;
36+
37+
void setup() {
38+
int16_t nox_offset, nox_learning, nox_learning_gain, nox_gating, nox_initial, nox_gain;
39+
uint8_t data[18], counter;
40+
41+
Serial.begin(115200);
42+
43+
// Wait for serial connection from PC
44+
// comment the following line if you'd like the output
45+
// without waiting for the interface being ready
46+
while(!Serial);
47+
48+
// Initiate I2C communication
49+
Wire.begin();
50+
51+
// Wait until sensors startup, > 50 ms according to datasheet
52+
delay(50);
53+
54+
// Send command to NOx algorithm tuning parameters (0x60E1)
55+
Wire.beginTransmission(SEN55_ADDRESS);
56+
Wire.write(0x60);
57+
Wire.write(0xE1);
58+
Wire.endTransmission();
59+
60+
// Wait 20 ms to allow the sensor to fill the internal buffer
61+
delay(20);
62+
63+
// Read preset NOx algorithm tuning parameters from SEN55
64+
Wire.requestFrom(SEN55_ADDRESS, 18);
65+
counter = 0;
66+
while (Wire.available()) {
67+
data[counter++] = Wire.read();
68+
}
69+
70+
// Processing preset NOx algorithm tuning parameters
71+
// CRC byte (every 3rd byte) is excluded from processing
72+
// offset is arbitrary
73+
nox_offset = (uint16_t)data[0] << 8 | data[1];
74+
// learning time is in hours
75+
nox_learning = (uint16_t)data[3] << 8 | data[4];
76+
// learning time gain in hours
77+
nox_learning_gain = (uint16_t)data[6] << 8 | data[7];
78+
// gating time is in minutes
79+
nox_gating = (uint16_t)data[9] << 8 | data[10];
80+
// standard initial is arbitrary
81+
nox_initial = (uint16_t)data[12] << 8 | data[13];
82+
// standard initial is arbitrary
83+
nox_gain = (uint16_t)data[15] << 8 | data[16];
84+
85+
Serial.println();
86+
Serial.println("Default parameters: ");
87+
Serial.print("Index offset: ");
88+
Serial.println(float(nox_offset));
89+
Serial.print("Learning time offset hours: ");
90+
Serial.println(float(nox_learning));
91+
Serial.print("Learning time gain hours: ");
92+
Serial.println(nox_learning_gain);
93+
Serial.print("Gating max duration minutes: ");
94+
Serial.println(nox_gating);
95+
Serial.print("Std initial: ");
96+
Serial.println(nox_initial);
97+
Serial.print("Gain factor: ");
98+
Serial.println(nox_gain);
99+
Serial.println();
100+
101+
// Set new NOx algorithm tuning parameters
102+
// Offset 100 instead of 1
103+
nox_offset = 100;
104+
// Learning 6 h instead of 12 h
105+
nox_learning = 6;
106+
// gating 1500 min instead of 720 min
107+
nox_gating = 1500;
108+
// gain 250 instead of 230
109+
nox_gain = 250;
110+
111+
// prepare buffer with algorithm parameter data
112+
// calculate CRC for each 2 bytes of data
113+
data[0] = (nox_offset & 0xff00) >> 8;
114+
data[1] = nox_offset & 0x00ff;
115+
data[2] = CalcCrc(data);
116+
data[3] = (nox_learning & 0xff00) >> 8;
117+
data[4] = nox_learning & 0x00ff;
118+
data[5] = CalcCrc(data+3);
119+
data[6] = (nox_learning_gain & 0xff00) >> 8;
120+
data[7] = nox_learning_gain & 0x00ff;
121+
data[8] = CalcCrc(data+6);
122+
data[9] = (nox_gating & 0xff00) >> 8;
123+
data[10] = nox_gating & 0x00ff;
124+
data[11] = CalcCrc(data+9);
125+
data[12] = (nox_initial & 0xff00) >> 8;
126+
data[13] = nox_initial & 0x00ff;
127+
data[14] = CalcCrc(data+12);
128+
data[15] = (nox_gain & 0xff00) >> 8;
129+
data[16] = nox_gain & 0x00ff;
130+
data[17] = CalcCrc(data+15);
131+
132+
// Send new value for NOx parameters to sensor (will be hold in RAM, not persistent)
133+
Wire.beginTransmission(SEN55_ADDRESS);
134+
Wire.write(0x60);
135+
Wire.write(0xE1);
136+
Wire.write(data[0]);
137+
Wire.write(data[1]);
138+
Wire.write(data[2]);
139+
Wire.write(data[3]);
140+
Wire.write(data[4]);
141+
Wire.write(data[5]);
142+
Wire.write(data[6]);
143+
Wire.write(data[7]);
144+
Wire.write(data[8]);
145+
Wire.write(data[9]);
146+
Wire.write(data[10]);
147+
Wire.write(data[11]);
148+
Wire.write(data[12]);
149+
Wire.write(data[13]);
150+
Wire.write(data[14]);
151+
Wire.write(data[15]);
152+
Wire.write(data[16]);
153+
Wire.write(data[17]);
154+
Wire.endTransmission();
155+
156+
// Wait 20 ms to allow the sensor to fill the internal buffer
157+
delay(20);
158+
159+
// Send command to read NOx algortihm tuning parameters (0x60E1)
160+
Wire.beginTransmission(SEN55_ADDRESS);
161+
Wire.write(0x60);
162+
Wire.write(0xE1);
163+
Wire.endTransmission();
164+
165+
// Wait 20 ms to allow the sensor to fill the internal buffer
166+
delay(20);
167+
168+
// Read NOx algorithm tuning parameters from SEN55
169+
Wire.requestFrom(SEN55_ADDRESS, 18);
170+
counter = 0;
171+
while (Wire.available()) {
172+
data[counter++] = Wire.read();
173+
}
174+
175+
// Parse data to make sure that new NOx algorithm tuning parameters are correct
176+
// offset is arbitrary
177+
nox_offset = (uint16_t)data[0] << 8 | data[1];
178+
// learning time is in hours
179+
nox_learning = (uint16_t)data[3] << 8 | data[4];
180+
// learning time gain in hours
181+
nox_learning_gain = (uint16_t)data[6] << 8 | data[7];
182+
// gating time is in minutes
183+
nox_gating = (uint16_t)data[9] << 8 | data[10];
184+
// standard initial is arbitrary
185+
nox_initial = (uint16_t)data[12] << 8 | data[13];
186+
// standard initial is arbitrary
187+
nox_gain = (uint16_t)data[15] << 8 | data[16];
188+
189+
// Print new NOx algorithm tuning parameters
190+
Serial.println("default parameters (offset, learning, learning gain, gating, initial, gain): ");
191+
Serial.println(nox_offset);
192+
Serial.println(nox_learning);
193+
Serial.println(nox_learning_gain);
194+
Serial.println(nox_gating);
195+
Serial.println(nox_initial);
196+
Serial.println(nox_gain);
197+
Serial.println();
198+
199+
// Send command to start measurement (0x0021)
200+
Wire.beginTransmission(SEN55_ADDRESS);
201+
Wire.write(0x00);
202+
Wire.write(0x21);
203+
Wire.endTransmission();
204+
205+
// Wait until command is executed, sensors are ready and fan is initialized
206+
delay(2000);
207+
208+
// Output measurement value format
209+
Serial.println("PM1.0\tPM2.5\tPM4.0\tPM10.0\tVOC_Index\tNOx_Index\tRH\tT");
210+
}
211+
212+
void loop() {
213+
uint16_t pm1p0, pm2p5, pm4p0, pm10p0;
214+
int16_t voc, nox, humidity, temperature;
215+
uint8_t data[24], counter;
216+
217+
// Send read measurement data command (0x03C4)
218+
Wire.beginTransmission(SEN55_ADDRESS);
219+
Wire.write(0x03);
220+
Wire.write(0xC4);
221+
Wire.endTransmission();
222+
223+
// Wait 20 ms for command execution
224+
delay(20);
225+
226+
// Read measurement data SEN55, after two bytes a CRC follows
227+
Wire.requestFrom(SEN55_ADDRESS, 24);
228+
counter = 0;
229+
while (Wire.available()) {
230+
data[counter++] = Wire.read();
231+
}
232+
233+
// PM1.0 to PM10 are unscaled unsigned integer values in ug / um3
234+
// VOC level is a signed int and scaled by a factor of 10 and needs to be divided by 10
235+
// humidity is a signed int and scaled by 100 and need to be divided by 100
236+
// temperature is a signed int and scaled by 200 and need to be divided by 200
237+
pm1p0 = (uint16_t)data[0] << 8 | data[1];
238+
pm2p5 = (uint16_t)data[3] << 8 | data[4];
239+
pm4p0 = (uint16_t)data[6] << 8 | data[7];
240+
pm10p0 = (uint16_t)data[9] << 8 | data[10];
241+
humidity = (uint16_t)data[12] << 8 | data[13];
242+
temperature = (uint16_t)data[15] << 8 | data[16];
243+
voc = (uint16_t)data[18] << 8 | data[19];
244+
nox = (uint16_t)data[21] << 8 | data[22];
245+
246+
Serial.print(String(float(pm1p0) / 10));
247+
Serial.print("\t");
248+
Serial.print(String(float(pm2p5) / 10));
249+
Serial.print("\t");
250+
Serial.print(String(float(pm4p0) / 10));
251+
Serial.print("\t");
252+
Serial.print(String(float(pm10p0) / 10));
253+
Serial.print("\t");
254+
Serial.print(String(float(voc) / 10));
255+
Serial.print("\t\t");
256+
Serial.print(String(float(nox) / 10));
257+
Serial.print("\t\t");
258+
Serial.print(String(float(humidity) / 100));
259+
Serial.print("\t");
260+
Serial.print(String(float(temperature) / 200));
261+
Serial.println();
262+
263+
// Wait 1 s for next measurement
264+
delay(1000);
265+
}
266+
267+
// Calculate CRC according to datasheet
268+
uint8_t CalcCrc(uint8_t data[2]) {
269+
uint8_t crc = 0xFF;
270+
for(int i = 0; i < 2; i++) {
271+
crc ^= data[i];
272+
for(uint8_t bit = 8; bit > 0; --bit) {
273+
if(crc & 0x80) {
274+
crc = (crc << 1) ^ 0x31u;
275+
} else {
276+
crc = (crc << 1);
277+
}
278+
}
279+
}
280+
return crc;
281+
}

0 commit comments

Comments
 (0)