Reading SenseAir LP8 CO2 sensor over bluetooth low energy
Dependencies: BLE_API mbed nRF51822
LP8.h
- Committer:
- jony1401
- Date:
- 2017-08-21
- Revision:
- 4:320febe026ed
- Parent:
- 3:933dd59ad44d
File content as of revision 4:320febe026ed:
#ifndef LP8_H #define LP8_H /* To initialize the lp8 object, you need to pass a serial (tx, rx), a DigitalOut signal for the en_vbb, an DigitalIn for the ready signal, DigitalOut for Reset and a timer object. */ class LP8 { public: //constructor LP8(Serial &device, DigitalOut &vbb_en, DigitalIn &rdy, DigitalOut &res ,Timer &_timer): Device(device), VBB_EN(vbb_en), RDY(rdy), RES(res), lp8Wait(_timer) { Device.baud(9600); //set baud rate to 9600 Hz Device.format(8, SerialBase::None, 2); //set bits, parity and stop bits //initialize arrays with lp8 modbus commands. //initial startup command: firstWrite[0] = 0xfe; //device adress firstWrite[1] = 0x41; //write to ram firstWrite[2] = 0x00; // firstWrite[3] = 0x80; //starting adress firstWrite[4] = 0x01; //nr of bytes to send firstWrite[5] = 0x10; //calculation control byte firstWrite[6] = 0x28; //crc low firstWrite[7] = 0x7e; //crc high //write previous sensor state to lp8, command: stateWrite[0] = 0xfe; //device adress stateWrite[1] = 0x41; //write to ram stateWrite[2] = 0x00; // stateWrite[3] = 0x80; //starting adress stateWrite[4] = 0x18; //nr of bytes to send stateWrite[5] = 0x20; //Calculation Control for(int k = 6; k < 31; k++) { stateWrite[k] = 0x00; } // //read request from the lp8: stateRead[0] = 0xfe; //adress stateRead[1] = 0x44; //read from ram stateRead[2] = 0x00; // stateRead[3] = 0x80; //starting adress stateRead[4] = 0x2c; //number of bytes to read stateRead[5] = 0x00; //crc_l stateRead[6] = 0x00; //crc_h //communication confirmation sequence (response from lp8) confirmation[0] = 0xfe; confirmation[1] = 0x41; confirmation[2] = 0x81; confirmation[3] = 0xe0; //response buffer for(int k = 0; k < 60; k++) { response[k] = 0x00; } //variable initialization co2 = 400; // CRC = 0x0000; // }; //LP8 Initialization and first message bool lp8Init(){ Device.format(8, SerialBase::None, 2); //Reset LP8 RES.write( 0 ); //reset timeIt( 1.0 ); RES.write( 1 ); //enable timeIt(0.2); //Enable Sensor VBB_EN.write( 1 ); //power on //wait for rdy signal timeIt( 0.30 ); //wait for lp8 rdy signal // while(RDY.read() != 0 ) { /* wait for rdy to go low */} //transmit first packet transmitPacket(firstWrite, 8); //Send out msg (and nr of bytes) over serial line Response( 4 ); //read 4 bytes response //check response if ( responseCompare() != true){ //VBB_EN.write( 0 ); return false; } //compute crc CRC = modbusCrc(stateRead, 5); //add crc value to the transmit package stateRead[5] = (uint8_t)CRC; //crc_l stateRead[6] = (uint8_t)(CRC >> 8); //crc_h //wait for rdy timeIt( 0.20 ); // // while(RDY.read() != 1 ) { /*wait for rdy to go high */} transmitPacket(stateRead, 7); //transmit packet Response( 49 ); //get sensor state and co2 value(s) VBB_EN.write( 0 ); //power off lp8 return true; }; //send subsequent messages to the lp8 bool lp8Talk(uint8_t inc_ccByte){ static const uint8_t A[] = {0xFE,0x41,0x00,0x80,0x20,0x00,0x00,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x7F,0xFF,0x00,0x00,0x95,0xED,0x00,0x03,0x29,0x00,0x27,0x8C, 0xf5, 0x63}; Device.format(8, SerialBase::None, 2); //transfer previous sensor state to the new msg out for (int u = 4; u < 23+4; u++) { stateWrite[u+2] = response[u]; } //Set Calibration Control Byte (see end of page for explantion), /* remove this statement if you want to be able to send anything to lp8 calculation control */ if( inc_ccByte != 0x20 ){ /* 0x52 is "simple recalibration, needs only one sample */ stateWrite[5] = inc_ccByte; } else { stateWrite[5] = 0x20; } //compute new crc value CRC = modbusCrc((uint8_t*)stateWrite, 29); //add new crc value to send list stateWrite[29] = (uint8_t)CRC; stateWrite[30] = (uint8_t)(CRC >> 8); //initialize new transfer sequence VBB_EN.write( 1 ); //power on sensor timeIt( 0.35 ); // while(RDY.read() != 0 ) { /* wait for rdy */} transmitPacket(/*(uint8_t*)A*/(uint8_t*)stateWrite, 31); //Send out msg with previous state (and nr of elements) over serial line Response( 4 ); //read 4 bytes response //compare to confirmation sequence if ( responseCompare() != true){ //VBB_EN.write( 0 ); return false; } //compute crc CRC = modbusCrc(stateRead, 5); //add crc value to the read request transmit package stateRead[5] = (uint8_t)CRC; //crc_l stateRead[6] = (uint8_t)(CRC >> 8); //crc_h timeIt( 0.20 ); // while(RDY.read() != 1 ) { /* wait for rdy to go high */} //send read request transmitPacket(stateRead, 7); //transmit packet //read sensor response Response( 49 ); //get sensor state VBB_EN.write( 0 ); //power off return true; }; //get value from lp8 response unsigned long getValue() /* CO2 Value */ { int high = response[29]; int low = response[30]; unsigned long val = high * 256 + low; return val; } float getTempValue() { int h = response[33]; int l = response[34]; unsigned long _temp = h * 256 + l; float _tempVal = 0.01 * _temp; return _tempVal; } /* get Vcap value for at current measurement, [35],[36] is previous Vcap value */ int getVcapValue(){ int hB = response[37]; int lB = response[38]; unsigned long temp = hB * 256 + lB; return temp; } uint32_t getErrorStatus(){ uint32_t tmp = 0; tmp += response[39] << (32-8); tmp += response[40] << (32-16); tmp += response[41] << (32-24); tmp += response[42]; return tmp; } //get calculation Control byte from lp8 response uint8_t getCCbyte(){ uint8_t rCCbyte = stateWrite[5]; return rCCbyte; } /************************************************* Helper Functions ********************************************/ //purge response buffer void responsePurge(int bytesToPurge){ for (int j = 0; j < bytesToPurge; j++) { response[j] = 0x00; } //for(int k = 6; k < 31; k++) { stateWrite[k] = 0x00; } //purge sensor state }; //read response from lp8 void Response( int bytesToRead ){ int Count = 0; lp8Wait.start(); /* timeout timer if something goes wrong */ do { if(Device.readable()) { response[Count] = Device.getc(); Count++; --bytesToRead; } } while( (bytesToRead > 0) || (lp8Wait.read() < 0.2 )); lp8Wait.stop(); lp8Wait.reset(); }; //transmit data over serial lines void transmitPacket(uint8_t msg[], int le ){ //Send out msg over serial line: while(!Device.writeable() ) { /* wait for serial available*/ } for(int pos = 0; pos < le; pos++) { Device.putc(msg[pos]); } }; //timer void timeIt(float timeMe){ //start amd stop timer... lp8Wait.start(); while (lp8Wait.read() < timeMe ) { /* W A I T I N G */ } lp8Wait.stop(); lp8Wait.reset(); }; // Computation for the modbus 16-bit crc uint16_t modbusCrc(uint8_t buffer[], int len){ uint16_t crc = 0xFFFF; for (int pos = 0; pos < len; pos++) { crc ^= (uint16_t)buffer[pos]; // XOR byte into least sig. byte of crc for (int i = 8; i != 0; i--) { // Loop over each bit if ((crc & 0x0001) != 0) { // If the LSB is set crc >>= 1; // shift right and XOR 0xA001 crc ^= 0xA001; } else // Else LSB is not set crc >>= 1; // shift right } } // Note, this number has low and high bytes swapped return crc; }; bool responseCompare(){ short seq = 0; for(int j=0; j < 4; j++){ if(response[j] == confirmation[j]){ seq++; } } //return false if check sequence fails if( seq != 4 ){ return false; } return true; } //variables and buffers private: //pins Serial &Device; DigitalOut &VBB_EN; DigitalIn &RDY; DigitalOut &RES; Timer &lp8Wait; //msg containers uint8_t firstWrite[8]; volatile uint8_t stateWrite[31]; uint8_t stateRead[7]; uint8_t confirmation[4]; volatile uint8_t response[60]; // int co2; //CO2 initial value int tempValue; uint16_t CRC; //modbus crc value }; #endif /* LP8 Modbus Communication Protocol (With no external Pressure Sensor): -------------------------------------------------------------------------------- Initial Measurement (first read after powerup): COMMANDS: -------------------------------------------------------------------------------- 1) host powers up sensor: VBB_EN = 1 2) host waits until rdy signal goes low: RDY = 0; 3) host writes command, "write 24 bytes starting from adress 0x0080": { 0xfe, 0x41, 0x00, 0x80, 0x18, 0x10, ... [any 23 bytes] ..., CRC_low, CRC_high }; 4) host reads response: { 0xfe, 0x41, 0x81, 0xe0 }; 5) host waits until rdy signal goes high: RDY = 1; 6) host writes command "read 44 bytes starting from adress 0x0080": { 0xfe, 0x44, 0x00, 0x80, 0x2c, CRC_low, CRC_high }; 7) host reads response: { 0xfe, 0x44, 0x2c, 0x00, SS1, SS2, ..., SS23, PP_H, PP_L, D1, D2, ..., D18, CRC_low, CRC_high }; 8) host powers down sensor: VBB_EN = 0; [------------------------------------------------------------------------------] Optional first reading W/O pressure sensor [------------------------------------------------------------------------------] 1) host powers up sensor: VBB_EN = 1 2) host waits until rdy signal goes low: RDY = 0; 3) host writes command, "write 24 bytes starting from adress 0x0080": { 0xfe, 0x41, 0x00, 0x80, 0x18, 0x10, 0x28, 0x7e }; 4) host reads response: { 0xfe, 0x41, 0x81, 0xe0 }; 5) host waits until rdy signal goes high: RDY = 1; 6) host writes command "read 44 bytes starting from adress 0x0080": { 0xfe, 0x44, 0x00, 0x80, 0x2c, CRC_low, CRC_high }; 7) host reads response: { 0xfe, 0x44, 0x2c, 0x00, SS1, SS2, ..., SS23, PP_H, PP_L, D1, D2, ..., D18, CRC_low, CRC_high }; 8) host powers down sensor: VBB_EN = 0; -------------------------------------------------------------------------------- Subsequent readings: -------------------------------------------------------------------------------- 1) host powers up sensor: VBB_EN = 1 2) host waits until rdy signal goes low: RDY = 0; 3) host writes command, "write 24 bytes starting from adress 0x0080": { 0xfe, 0x41, 0x00, 0x80, 0x18, CC, SS1, ..., SS23, CRC_low, CRC_high }; 4) host reads response: { 0xfe, 0x41, 0x81, 0xe0 }; 5) host waits until rdy signal goes high: RDY = 1; 6) host writes command "read 44 bytes starting from adress 0x0080": { 0xfe, 0x44, 0x00, 0x80, 0x2c, CRC_low, CRC_high }; 7) host reads response: { 0xfe, 0x44, 0x2c, 0x00, SS1, SS2, ..., SS23, PP_H, PP_L, D1, D2, ..., D18, CRC_low, CRC_high }; 8) host powers down sensor: VBB_EN = 0; -------------------------------------------------------------------------------- LP8 Background Calibration, Calculation Control Byte -------------------------------------------------------------------------------- To calibrate the lp8, commands needs to be sent with the calculation control byte Calculation: CC = 0x10 Initial measurement (filters reset, ABC sample reset and other, 0x20 Subsequent measurement, 0x40 Zero calibration using unfiltered data, 0x41 Zero calibration using filtered data, 0x42 Zero calibration using unfiltered data + reset filters, 0x43 Zero calibration using filtered data + reset filters, 0x50 Background calibration using unfiltered data, 0x51 Background calibration using filtered data, 0x52 Background calibration using unfiltered data + reset filters, 0x53 Background calibration using filtered data + reset filters, 0x70 ABC (based on filtered data), 0x72 ABC (based on filtered data) + reset filters -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- CC = Calculation Control, 1 byte SS = Sensor State, Sensor State, 23 bytes D = Measured data and Sensor Status, 23 bytes PP = Host Pressure Value CRC= 16 bit CRC error check -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- */