Private Private / Mbed 2 deprecated SenseAirLP8

Dependencies:   BLE_API mbed nRF51822

Fork of SenseAirLP8 by Jonas Skalman

Committer:
jony1401
Date:
Mon Jun 05 11:10:28 2017 +0000
Revision:
1:b512a405b584
Parent:
0:ee3787c8e209
Child:
2:d02255d8c36f
Reading Senseair LP8 CO2 sensor over bluetooth low energy with readbearlabs ble nano.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jony1401 0:ee3787c8e209 1 #ifndef LP8_H
jony1401 0:ee3787c8e209 2 #define LP8_H
jony1401 0:ee3787c8e209 3
jony1401 1:b512a405b584 4 /* To initialize the lp8 object, you need to pass a serial (tx, rx), an DigitalOut signal for the en_vbb,
jony1401 1:b512a405b584 5 an DigitalIn for the ready signal and a timer object. */
jony1401 1:b512a405b584 6
jony1401 0:ee3787c8e209 7 class LP8
jony1401 0:ee3787c8e209 8 {
jony1401 0:ee3787c8e209 9 public:
jony1401 1:b512a405b584 10 //constructor
jony1401 1:b512a405b584 11 LP8(Serial &device, DigitalOut &vbb_en, DigitalIn &rdy, Timer &_timer):
jony1401 1:b512a405b584 12 Device(device),
jony1401 1:b512a405b584 13 VBB_EN(vbb_en),
jony1401 1:b512a405b584 14 RDY(rdy),
jony1401 1:b512a405b584 15 lp8Wait(_timer)
jony1401 1:b512a405b584 16 {
jony1401 1:b512a405b584 17 Device.baud(9600); //set baud rate to 9600
jony1401 0:ee3787c8e209 18
jony1401 1:b512a405b584 19 //initialize arrays with lp8 modbus commands.
jony1401 1:b512a405b584 20 //initial startup command:
jony1401 1:b512a405b584 21 firstWrite[0] = 0xfe; //device adress
jony1401 1:b512a405b584 22 firstWrite[1] = 0x41; //write to ram
jony1401 1:b512a405b584 23 firstWrite[2] = 0x00; //
jony1401 1:b512a405b584 24 firstWrite[3] = 0x80; //starting adress
jony1401 1:b512a405b584 25 firstWrite[4] = 0x01; //nr of bytes to send
jony1401 1:b512a405b584 26 firstWrite[5] = 0x10; //calculation control byte
jony1401 1:b512a405b584 27 firstWrite[6] = 0x28; //crc low
jony1401 1:b512a405b584 28 firstWrite[7] = 0x7e; //crc high
jony1401 0:ee3787c8e209 29
jony1401 1:b512a405b584 30 //write previous sensor state to lp8, command:
jony1401 1:b512a405b584 31 stateWrite[0] = 0xfe; //device adress
jony1401 1:b512a405b584 32 stateWrite[1] = 0x41; //write to ram
jony1401 1:b512a405b584 33 stateWrite[2] = 0x00; //
jony1401 1:b512a405b584 34 stateWrite[3] = 0x80; //starting adress
jony1401 1:b512a405b584 35 stateWrite[4] = 0x18; //nr of bytes to send
jony1401 1:b512a405b584 36 stateWrite[5] = 0x20; //Calculation Control
jony1401 1:b512a405b584 37 for(int k = 6; k < 31; k++) { stateWrite[k] = 0x00; } //
jony1401 0:ee3787c8e209 38
jony1401 1:b512a405b584 39 //read request from the lp8:
jony1401 1:b512a405b584 40 stateRead[0] = 0xfe; //adress
jony1401 1:b512a405b584 41 stateRead[1] = 0x44; //read from ram
jony1401 1:b512a405b584 42 stateRead[2] = 0x00; //
jony1401 1:b512a405b584 43 stateRead[3] = 0x80; //starting adress
jony1401 1:b512a405b584 44 stateRead[4] = 0x2c; //number of bytes to read
jony1401 1:b512a405b584 45 stateRead[5] = 0x00; //crc_l
jony1401 1:b512a405b584 46 stateRead[5] = 0x00; //crc_h
jony1401 1:b512a405b584 47
jony1401 1:b512a405b584 48 //response buffer
jony1401 1:b512a405b584 49 for(int k = 0; k < 60; k++) { response[k] = 0x00; }
jony1401 0:ee3787c8e209 50
jony1401 1:b512a405b584 51 //variable initialization
jony1401 1:b512a405b584 52 co2 = 400; //co2 value
jony1401 1:b512a405b584 53 counter = 0; //
jony1401 1:b512a405b584 54 CRC = 0x0000; //crc value
jony1401 1:b512a405b584 55 _timeMe = 0.350; //wait timer(ms)
jony1401 1:b512a405b584 56 };
jony1401 0:ee3787c8e209 57
jony1401 0:ee3787c8e209 58
jony1401 1:b512a405b584 59 //LP8 Initialization .
jony1401 0:ee3787c8e209 60 bool lp8Init(){
jony1401 0:ee3787c8e209 61 VBB_EN.write( 1 ); //power on
jony1401 1:b512a405b584 62 //wait for rdy signal
jony1401 1:b512a405b584 63 timeIt( _timeMe ); //wait for lp8 rdy signal
jony1401 1:b512a405b584 64 transmitPacket(firstWrite, 8); //Send out msg (and nr of bytes) over serial line
jony1401 0:ee3787c8e209 65 Response( 4 ); //read 4 bytes response
jony1401 1:b512a405b584 66 //compute crc
jony1401 0:ee3787c8e209 67 CRC = modbusCrc(stateRead, 5);
jony1401 1:b512a405b584 68 //add crc value to the transmit package
jony1401 1:b512a405b584 69 stateRead[5] = (uint8_t)CRC; //crc_l
jony1401 1:b512a405b584 70 stateRead[6] = (uint8_t)(CRC >> 8); //crc_h
jony1401 1:b512a405b584 71 //wait for rdy
jony1401 1:b512a405b584 72 timeIt( _timeMe ); //
jony1401 0:ee3787c8e209 73 transmitPacket(stateRead, 7); //transmit packet
jony1401 0:ee3787c8e209 74 Response( 49 ); //read sensor state and co2 value(s)
jony1401 1:b512a405b584 75 VBB_EN.write( 0 ); //power off lp8
jony1401 1:b512a405b584 76 //was the talk a success? (simple check...)
jony1401 0:ee3787c8e209 77 if ( getValue() < 1 ) {
jony1401 0:ee3787c8e209 78 return 1; }
jony1401 0:ee3787c8e209 79 else {
jony1401 0:ee3787c8e209 80 return 0; }
jony1401 0:ee3787c8e209 81 };
jony1401 0:ee3787c8e209 82
jony1401 1:b512a405b584 83 //send subsequent messages to the lp8
jony1401 1:b512a405b584 84 void lp8Talk(uint8_t ccByte){
jony1401 0:ee3787c8e209 85 //transfer previous sensor state to the new msg out
jony1401 0:ee3787c8e209 86 for (int u = 4; u < 23+4; u++) {
jony1401 0:ee3787c8e209 87 stateWrite[u+2] = response[u];
jony1401 0:ee3787c8e209 88 }
jony1401 1:b512a405b584 89 //Set Calibration Control Byte (see end of page for explantion)
jony1401 1:b512a405b584 90 stateWrite[5] = ccByte;
jony1401 0:ee3787c8e209 91 //compute new crc value
jony1401 0:ee3787c8e209 92 CRC = modbusCrc(stateWrite, 29);
jony1401 0:ee3787c8e209 93 //add new crc value to send list
jony1401 0:ee3787c8e209 94 stateWrite[29] = (uint8_t)CRC;
jony1401 0:ee3787c8e209 95 stateWrite[30] = (uint8_t)(CRC >> 8);
jony1401 0:ee3787c8e209 96 //initialize new transfer sequence
jony1401 0:ee3787c8e209 97 VBB_EN.write( 1 ); //power on sensor
jony1401 0:ee3787c8e209 98 timeIt( _timeMe );
jony1401 0:ee3787c8e209 99 transmitPacket(stateWrite, 31); //Send out msg with previous state (and nr of elements) over serial line
jony1401 0:ee3787c8e209 100 Response( 4 ); //read 4 bytes response
jony1401 0:ee3787c8e209 101 //compute crc
jony1401 0:ee3787c8e209 102 CRC = modbusCrc(stateRead, 5);
jony1401 0:ee3787c8e209 103 //add crc value to the read request transmit package
jony1401 0:ee3787c8e209 104 stateRead[5] = (uint8_t)CRC; //crc_l
jony1401 0:ee3787c8e209 105 stateRead[6] = (uint8_t)(CRC >> 8); //crc_h
jony1401 1:b512a405b584 106 timeIt( _timeMe );
jony1401 0:ee3787c8e209 107 //send read request
jony1401 0:ee3787c8e209 108 transmitPacket(stateRead, 7); //transmit packet
jony1401 0:ee3787c8e209 109 //read sensor response
jony1401 0:ee3787c8e209 110 Response( 49 ); //read sensor state and co2 value(s)
jony1401 1:b512a405b584 111 VBB_EN.write( 0 ); //power off
jony1401 0:ee3787c8e209 112 };
jony1401 1:b512a405b584 113
jony1401 1:b512a405b584 114 //get co2 value from lp8 response
jony1401 0:ee3787c8e209 115 unsigned long getValue()
jony1401 0:ee3787c8e209 116 {
jony1401 1:b512a405b584 117 int high = response[29];
jony1401 1:b512a405b584 118 int low = response[30];
jony1401 0:ee3787c8e209 119 unsigned long val = high * 256 + low;
jony1401 0:ee3787c8e209 120
jony1401 0:ee3787c8e209 121 return val;
jony1401 0:ee3787c8e209 122 }
jony1401 0:ee3787c8e209 123
jony1401 1:b512a405b584 124
jony1401 1:b512a405b584 125 /************************************************* Helper Functions ********************************************/
jony1401 1:b512a405b584 126 /************************************************* ********************************************/
jony1401 1:b512a405b584 127 //purge response buffer
jony1401 0:ee3787c8e209 128 void responsePurge(int bytesToPurge){
jony1401 0:ee3787c8e209 129 for (int j = 0; j < bytesToPurge; j++) {
jony1401 0:ee3787c8e209 130 response[j] = 0x00;
jony1401 0:ee3787c8e209 131 }
jony1401 0:ee3787c8e209 132 };
jony1401 1:b512a405b584 133
jony1401 1:b512a405b584 134 //read from the lp8
jony1401 0:ee3787c8e209 135 void Response(int bytesToRead ){
jony1401 1:b512a405b584 136 lp8Wait.start(); //poll rx line for 0.5 seconds
jony1401 0:ee3787c8e209 137 do {
jony1401 0:ee3787c8e209 138 if(Device.readable()) {
jony1401 0:ee3787c8e209 139 response[counter] = Device.getc();
jony1401 0:ee3787c8e209 140 counter++;
jony1401 0:ee3787c8e209 141 }
jony1401 0:ee3787c8e209 142 }
jony1401 0:ee3787c8e209 143 while( lp8Wait.read() < 0.5 );
jony1401 0:ee3787c8e209 144 counter = 0;
jony1401 0:ee3787c8e209 145 lp8Wait.stop();
jony1401 0:ee3787c8e209 146 lp8Wait.reset();
jony1401 0:ee3787c8e209 147 };
jony1401 0:ee3787c8e209 148
jony1401 1:b512a405b584 149 //transmit data over serial lines
jony1401 0:ee3787c8e209 150 void transmitPacket(uint8_t msg[], int le ){
jony1401 0:ee3787c8e209 151 //Send out msg over serial line:
jony1401 0:ee3787c8e209 152 while(!Device.writeable() ) { /* wait for serial available*/ }
jony1401 0:ee3787c8e209 153 for(int pos = 0; pos < le; pos++) {
jony1401 0:ee3787c8e209 154 Device.putc(msg[pos]);
jony1401 0:ee3787c8e209 155 }
jony1401 0:ee3787c8e209 156
jony1401 0:ee3787c8e209 157 };
jony1401 0:ee3787c8e209 158
jony1401 1:b512a405b584 159 //timer
jony1401 0:ee3787c8e209 160 void timeIt(float &timeMe){
jony1401 0:ee3787c8e209 161 //start amd stop timer...
jony1401 0:ee3787c8e209 162 lp8Wait.start();
jony1401 0:ee3787c8e209 163 while (lp8Wait.read() < timeMe ) { /* W A I T I N G */ }
jony1401 0:ee3787c8e209 164 lp8Wait.stop();
jony1401 0:ee3787c8e209 165 lp8Wait.reset();
jony1401 0:ee3787c8e209 166 };
jony1401 0:ee3787c8e209 167
jony1401 1:b512a405b584 168 // Computation for the modbus 16-bit crc
jony1401 0:ee3787c8e209 169 uint16_t modbusCrc(uint8_t buffer[], int len){
jony1401 0:ee3787c8e209 170 uint16_t crc = 0xFFFF;
jony1401 0:ee3787c8e209 171
jony1401 0:ee3787c8e209 172 for (int pos = 0; pos < len; pos++) {
jony1401 0:ee3787c8e209 173 crc ^= (uint16_t)buffer[pos]; // XOR byte into least sig. byte of crc
jony1401 0:ee3787c8e209 174
jony1401 0:ee3787c8e209 175 for (int i = 8; i != 0; i--) { // Loop over each bit
jony1401 0:ee3787c8e209 176 if ((crc & 0x0001) != 0) { // If the LSB is set
jony1401 0:ee3787c8e209 177 crc >>= 1; // shift right and XOR 0xA001
jony1401 0:ee3787c8e209 178 crc ^= 0xA001;
jony1401 0:ee3787c8e209 179 }
jony1401 0:ee3787c8e209 180 else // Else LSB is not set
jony1401 0:ee3787c8e209 181 crc >>= 1; // shift right
jony1401 0:ee3787c8e209 182 }
jony1401 0:ee3787c8e209 183 }
jony1401 0:ee3787c8e209 184 // Note, this number has low and high bytes swapped
jony1401 0:ee3787c8e209 185 return crc;
jony1401 0:ee3787c8e209 186 };
jony1401 1:b512a405b584 187
jony1401 1:b512a405b584 188 //variables and buffers
jony1401 0:ee3787c8e209 189 private:
jony1401 0:ee3787c8e209 190
jony1401 0:ee3787c8e209 191 Serial &Device;
jony1401 0:ee3787c8e209 192 DigitalOut &VBB_EN;
jony1401 0:ee3787c8e209 193 DigitalIn &RDY;
jony1401 0:ee3787c8e209 194 Timer &lp8Wait;
jony1401 0:ee3787c8e209 195
jony1401 1:b512a405b584 196 //msg containers
jony1401 0:ee3787c8e209 197 uint8_t firstWrite[8];
jony1401 0:ee3787c8e209 198 uint8_t stateWrite[31];
jony1401 0:ee3787c8e209 199 uint8_t stateRead[7];
jony1401 0:ee3787c8e209 200 uint8_t response[60];
jony1401 0:ee3787c8e209 201
jony1401 0:ee3787c8e209 202 int co2; //CO2 initial value
jony1401 0:ee3787c8e209 203 int counter; //simple counter
jony1401 0:ee3787c8e209 204 uint16_t CRC; //modbus crc value
jony1401 0:ee3787c8e209 205 float _timeMe; //timer value
jony1401 0:ee3787c8e209 206
jony1401 0:ee3787c8e209 207
jony1401 0:ee3787c8e209 208 };
jony1401 0:ee3787c8e209 209 #endif
jony1401 0:ee3787c8e209 210
jony1401 0:ee3787c8e209 211 /*
jony1401 1:b512a405b584 212 LP8 Modbus Communication Protocol (With no external Pressure Sensor):
jony1401 0:ee3787c8e209 213 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 214 Initial Measurement (first read after powerup): COMMANDS:
jony1401 0:ee3787c8e209 215 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 216 1) host powers up sensor: VBB_EN = 1
jony1401 0:ee3787c8e209 217 2) host waits until rdy signal goes low: RDY = 0;
jony1401 0:ee3787c8e209 218 3) host writes command, "write 24 bytes starting from adress 0x0080": { 0xfe, 0x41, 0x00, 0x80, 0x18, 0x10, ... [any 23 bytes] ..., CRC_low, CRC_high };
jony1401 0:ee3787c8e209 219 4) host reads response: { 0xfe, 0x41, 0x81, 0xe0 };
jony1401 0:ee3787c8e209 220 5) host waits until rdy signal goes high: RDY = 1;
jony1401 0:ee3787c8e209 221 6) host writes command "read 44 bytes starting from adress 0x0080": { 0xfe, 0x44, 0x00, 0x80, 0x2c, CRC_low, CRC_high };
jony1401 0:ee3787c8e209 222 7) host reads response: { 0xfe, 0x44, 0x2c, 0x00, SS1, SS2, ..., SS23, PP_H, PP_L, D1, D2, ..., D18, CRC_low, CRC_high };
jony1401 0:ee3787c8e209 223 8) host powers down sensor: VBB_EN = 0;
jony1401 0:ee3787c8e209 224
jony1401 0:ee3787c8e209 225 [------------------------------------------------------------------------------]
jony1401 0:ee3787c8e209 226 Optional first reading W/O pressure sensor
jony1401 0:ee3787c8e209 227 [------------------------------------------------------------------------------]
jony1401 0:ee3787c8e209 228 1) host powers up sensor: VBB_EN = 1
jony1401 0:ee3787c8e209 229 2) host waits until rdy signal goes low: RDY = 0;
jony1401 0:ee3787c8e209 230 3) host writes command, "write 24 bytes starting from adress 0x0080": { 0xfe, 0x41, 0x00, 0x80, 0x18, 0x10, 0x28, 0x7e };
jony1401 0:ee3787c8e209 231 4) host reads response: { 0xfe, 0x41, 0x81, 0xe0 };
jony1401 0:ee3787c8e209 232 5) host waits until rdy signal goes high: RDY = 1;
jony1401 0:ee3787c8e209 233 6) host writes command "read 44 bytes starting from adress 0x0080": { 0xfe, 0x44, 0x00, 0x80, 0x2c, CRC_low, CRC_high };
jony1401 0:ee3787c8e209 234 7) host reads response: { 0xfe, 0x44, 0x2c, 0x00, SS1, SS2, ..., SS23, PP_H, PP_L, D1, D2, ..., D18, CRC_low, CRC_high };
jony1401 0:ee3787c8e209 235 8) host powers down sensor: VBB_EN = 0;
jony1401 0:ee3787c8e209 236
jony1401 0:ee3787c8e209 237
jony1401 0:ee3787c8e209 238 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 239 Subsequent readings:
jony1401 0:ee3787c8e209 240 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 241 1) host powers up sensor: VBB_EN = 1
jony1401 0:ee3787c8e209 242 2) host waits until rdy signal goes low: RDY = 0;
jony1401 0:ee3787c8e209 243 3) host writes command, "write 24 bytes starting from adress 0x0080": { 0xfe, 0x41, 0x00, 0x80, 0x18, CC, SS1, ..., SS23, CRC_low, CRC_high };
jony1401 0:ee3787c8e209 244 4) host reads response: { 0xfe, 0x41, 0x81, 0xe0 };
jony1401 0:ee3787c8e209 245 5) host waits until rdy signal goes high: RDY = 1;
jony1401 0:ee3787c8e209 246 6) host writes command "read 44 bytes starting from adress 0x0080": { 0xfe, 0x44, 0x00, 0x80, 0x2c, CRC_low, CRC_high };
jony1401 0:ee3787c8e209 247 7) host reads response: { 0xfe, 0x44, 0x2c, 0x00, SS1, SS2, ..., SS23, PP_H, PP_L, D1, D2, ..., D18, CRC_low, CRC_high };
jony1401 0:ee3787c8e209 248 8) host powers down sensor: VBB_EN = 0;
jony1401 0:ee3787c8e209 249
jony1401 0:ee3787c8e209 250
jony1401 0:ee3787c8e209 251 --------------------------------------------------------------------------------
jony1401 1:b512a405b584 252 LP8 Background Calibration, Calculation Control Byte
jony1401 1:b512a405b584 253 --------------------------------------------------------------------------------
jony1401 1:b512a405b584 254 To calibrate the lp8, commands needs to be sent with the calculation control byte
jony1401 1:b512a405b584 255 Calculation:
jony1401 1:b512a405b584 256 CC =
jony1401 1:b512a405b584 257 0x10 Initial measurement (filters reset, ABC sample reset and other,
jony1401 1:b512a405b584 258 0x20 Subsequent measurement,
jony1401 1:b512a405b584 259 0x40 Zero calibration using unfiltered data,
jony1401 1:b512a405b584 260 0x41 Zero calibration using filtered data,
jony1401 1:b512a405b584 261 0x42 Zero calibration using unfiltered data + reset filters,
jony1401 1:b512a405b584 262 0x43 Zero calibration using filtered data + reset filters,
jony1401 1:b512a405b584 263 0x50 Background calibration using unfiltered data,
jony1401 1:b512a405b584 264 0x51 Background calibration using filtered data,
jony1401 1:b512a405b584 265 0x52 Background calibration using unfiltered data + reset filters,
jony1401 1:b512a405b584 266 0x53 Background calibration using filtered data + reset filters,
jony1401 1:b512a405b584 267 0x70 ABC (based on filtered data),
jony1401 1:b512a405b584 268 0x72 ABC (based on filtered data) + reset filters
jony1401 1:b512a405b584 269
jony1401 1:b512a405b584 270
jony1401 1:b512a405b584 271 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 272 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 273 CC = Calculation Control, 1 byte
jony1401 0:ee3787c8e209 274 SS = Sensor State, Sensor State, 23 bytes
jony1401 0:ee3787c8e209 275 D = Measured data and Sensor Status, 23 bytes
jony1401 0:ee3787c8e209 276 PP = Host Pressure Value
jony1401 0:ee3787c8e209 277 CRC= 16 bit CRC error check
jony1401 0:ee3787c8e209 278 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 279 --------------------------------------------------------------------------------
jony1401 0:ee3787c8e209 280 */
jony1401 0:ee3787c8e209 281