# CozIR-LP3

## 1. Cozir-LP2에서 추가된 기능

* 알람 기능

\- 사용자 알람 값을 설정하였을 경우 알람 값에 도달 하면 디지털 출력으로 사용자에게 알려줌

* 알람 UART Command

| Command | Description | Response |
| ------- | ----------- | -------- |
| V ##### | 알람 값 설정     | V #####  |
| v       | 현재 알람 값 읽기  | v 15000  |

\- 알람 값은 센서 전원을 껐다 켜도 유지됨

\- 초기에는 알람 설정이 꺼져있음

* PWM 기능

\- 통신 프로토콜을 이용하여 Prescalar, Resolution, mode, pulses setting, pwm on/off 설정 가능

* PWM UART Command

| Command | Description                                                  | Response |
| ------- | ------------------------------------------------------------ | -------- |
| J ###   | PWM 설정( Prescalar, Resolution, mode, pulses setting, on/off) | J ###    |
| j       | 현재 PWM 값 읽기                                                  | j        |

* J ###\r\n Command

\- J ###\r\n에서 ### 은 Bit \[7:0] 까지 설정한 값이 들어감

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-59f796effd95c93d6fcac0666ad12ce4bae427cc%2FCOZIR_LP3_PWM_%EC%84%A4%EC%A0%952.PNG?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* 센서 자기 진단 테스트

| Command | Description  | Response |
| ------- | ------------ | -------- |
| i       | 센서 자가 진단 테스트 | i ###    |

Response: ### = 170 - Sensor error

\### = 85 - no Sensor error

## 2. 특징

* 최첨단 Solid-State LED 광학 기술 이용한 초 저전력 NDIR CO2 센서
* 디지털(UART) 및 I2C 출력
* 높은 CO2 측정 정확도
* 내장형 자동 영점 조정
* 30 ppm(일반) 정확도

## 3. 애플리케이션

* 난방, 환기 및 공기 조절(HVAC)
* 건물 관리 시스템(BMS)
* 환기 조절 시스템(DCV)
* 차량 내 공기 질
* 무선 장비를 이용한 IoT 및 Smart Technology
* 실내 공기 질(IAQ)
* 계측
* 농업
* 항공우주

## 4. 사양

| 항목         | 내용                                                                                             |
| ---------- | ---------------------------------------------------------------------------------------------- |
| 측정 범위      | <p>CozIR-LP3-2000: 0-2000ppm<br>CozIR-LP3-5000: 0-5000ppm<br>CozIR-LP3-1: 0-10,000ppm (1%)</p> |
| 센서 내부      | Solid-State, 가열된 필라멘트 없음                                                                       |
| 통신 방식      | UART 또는 I²C                                                                                    |
| 전원 전압      | 3.25-5.5V                                                                                      |
| 소모 전류      | <p>측정 모드: 15mA<br>절전 모드: 0.01mA</p>                                                            |
| 응답 시간      | 30.5ms                                                                                         |
| 동작 온도      | 0\~50℃                                                                                         |
| 센서 치수 및 무게 | L x W x H(31mm x 19.5mm x 8.7mm), Weight(2.5g)                                                 |
| 센서 내구성     | 진동 및 충격에 강하고 비가열성                                                                              |
| 센서 교정      | 자동 영점교정 기능 내장                                                                                  |
| 센서 수명      | 15년                                                                                            |
| 헤더 핀 크기    | 2.54mm                                                                                         |

## 5. 제품 크기 및 핀 특성

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-9111e59651af235c8c057815390074ed2fa0173d%2Fcozir_lp3_pin_connection.PNG?alt=media" alt="" width="563"><figcaption></figcaption></figure>

| PIN | NAME        | Function                 |
| --- | ----------- | ------------------------ |
| 1   | GND         | VSS                      |
| 2   | VDD         | Positive Supply          |
| 5   | ALARM       | ALARM Output             |
| 7   | PWM\_RS485  | PWM or RS485 transceiver |
| 8   | I2C\_ENABLE | Digital Input            |
| 9   | I2C\_SCL    | I2C clock                |
| 10  | I2C\_SDA    | I2C data                 |
| 11  | Tx\_out     | Digital Input            |
| 12  | Rx\_ In     | Digital Output           |

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-e03334d88afb20130d9a145f77ecad9d664a720c%2Fcozir_lp3_size.PNG?alt=media" alt="" width="563"><figcaption></figcaption></figure>

## 6. 디바이스 연결 방법

### Connection DIAGRAM (UART)

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-6165660ec6fb90eb9b4c1026dc3d0f2735275da1%2Fconnetion_uart_diagram.PNG?alt=media" alt="" width="563"><figcaption></figcaption></figure>

### Connection DIAGRAM (I2C)

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-55b3a56c868394b779f7b4977c2418807a04b434%2FCozIR-Blink_connetion_diagram_i2c.PNG?alt=media" alt="" width="563"><figcaption></figcaption></figure>

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-88102e48e6ab4d824eec0c218bb82bd756ee5b3a%2FCozir_series_uart_connection_with_arduino_uno.PNG?alt=media" alt="" width="563"><figcaption><p>Arduino Uno UART</p></figcaption></figure>

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-2e18c89bf277a3a33b4d9165bc0dfc018f1ce2a4%2FCozir_series_i2c_connection_with_arduino.PNG?alt=media" alt="" width="563"><figcaption><p>Arduino Uno I2C</p></figcaption></figure>

## 7. 통신 프로토콜

* 통신 환경

|       PARAMETER       |  TYP |  UNIT  |
| :-------------------: | :--: | :----: |
|       Buad Rate       | 9600 | Bits/s |
|       Data Bits       |   8  |        |
|         Parity        | None |        |
|       Stop Bits       |   1  |        |
| Hardware Flow Control | None |        |

* UART Command

| Command                      | Description                                 | Response                                    |
| ---------------------------- | ------------------------------------------- | ------------------------------------------- |
| K 0                          | Command를 기다리는 상태, 측정 X                      | K 00000                                     |
| K 1                          | 연속적으로 값을 측정                                 | K 00001                                     |
| K 2                          | 센서 값 요청시에만 응답                               | K 00002                                     |
| Z                            | 가장 최근에 측정한 CO2 필터 된 값                       | Z 00521                                     |
| z                            | 가장 최근에 측정한 CO2 필터 되지 않은 값                   | z 00521                                     |
| A ###                        | CO2 필터 값 설정                                 | A 00016                                     |
| a                            | CO2 필터 값 확인                                 | a 00016                                     |
| U                            | 질소를 사용하여 제로 교정                              | U 33000                                     |
| u                            | 초기 설정 값으로 제로 교정                             | u                                           |
| G                            | Fresh Air를 사용하여 제로 교정                       | G 33000                                     |
| X #####                      | 현재 값으로 스팬 교정                                | X 11000                                     |
| <p>P 10###</p><p>P 11###</p> | Fresh Air에서 사용할 대기 중 농도를 설정(default 400ppm) | Fresh Air에서 사용할 대기 중 농도를 설정(default 400ppm) |
| S ###                        | 고도 설정                                       | S 08192                                     |
| s                            | 고도 설정 값 확인                                  | s 08192                                     |
| M ###                        | 측정 데이터 문자열로 전송                              | M 6                                         |

### 모드 설정 및 CO2 값 읽기

> 모드

#### 1. COMMAND 모드

\- COMMAND를 기다리는 상태, 측정 X

#### 2. Streaming 모드(default)

\- 연속적으로 값을 측정함(초당 2회 측정), 측정 외 다른 Command시 100ms delay가 필요함

#### 3. Polling 모드

\- 센서 값 요청 시에만 응답, 센서 값 요청하지 않을 때에는 백그라운드에서 계속 측정을 수행함

| Mode      | Command | Description     | Response |
| --------- | ------- | --------------- | -------- |
| Command   | K 0     | 명령어 기다리는 상태     | K 00000  |
| Streaming | K 1     | 연속적으로 값 측정      | K 00001  |
| Polling   | K 2     | 센서 값 요청 시 에만 응답 | K 00002  |

#### 소스 코드

* Streaming mode에서 CO2 값 읽기

```cpp
#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 13); //Uno Rx Tx (12 13) = SoftwareSerial
const char* Polling_mode = "K 2\r\n";
const char* Stream_mode = "K 1\r\n";
const char* Standby_mode = "K 0\r\n";  
bool tx_ready;
bool rx_ready; 
String str;
void setup() {
  Serial.begin(9600); //시리얼 통신 초기화
  mySerial.begin(9600); 
  while(!mySerial){} //시리얼 통신 포트가 연결되기 전까지 대기
  delay(14); // power on data ready
  mySerial.print(Stream_mode); //Polling 모드로 변경
  mySerial.print("Z\r\n");  //CO2값 읽기 명령
}                              
 
void loop() 
{
 if(rx_ready == 0) // overflow 처리
 {
   delay(31); // Measurement data ready
   if(mySerial.available()>0) //수신받은 데이터가 0 초과, 즉 데이터가 존재한다면
   { //버퍼에서 읽어드린 char의 데이터를 String 형태로 반환
    str = "";
    str = mySerial.readStringUntil('\n'); 
    Serial.println(str);
    rx_ready = 1;   
    tx_ready = 1;
   }
 }
 else if(tx_ready == 1)
  {
     mySerial.print("Z\r\n"); //CO2값 읽기 명령
     tx_ready = 0;
     rx_ready = 0;
  }
}
```

+시리얼 모니터

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-78daba39340f59143ed883ad5dcefb2625489535%2Fcozirlp2_serial_streamiing.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* Polling mode에서 CO2값 읽기

```cpp
#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 13); //Uno Rx Tx (12 13) = SoftwareSerial
const char* Polling_mode = "K 2\r\n";
const char* Stream_mode = "K 1\r\n";
const char* Standby_mode = "K 0\r\n";   
String str;
void setup() {
  Serial.begin(9600); //시리얼 통신 초기화
  mySerial.begin(9600); 
  while(!mySerial){} //시리얼 통신 포트가 연결되기 전까지 대기
  delay(14); // power on data ready
  mySerial.print(Polling_mode); //Polling 모드로 변경
}                              
 
void loop() 
{
 if(Serial.read() == 'R') 
 {
  mySerial.print("Z\r\n"); //CO2값 읽기 명령
 }
  if(mySerial.available()>0) //수신받은 데이터가 0 초과, 즉 데이터가 존재한다면
   { //버퍼에서 읽어드린 char의 데이터를 String 형태로 반환
    str = "";
    str = mySerial.readStringUntil('\n'); 
    Serial.println(str);
   }
}
```

* 시리얼 모니터
* 시리얼 모니터에 'R' 입력 후 엔터

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-0aad0f6d9749a8787c453ddc7a04f4a94970e4a9%2Fcozirlp2_serial_r.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* 응답

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-5d77d12e4af0969712918c974e75e591450d8d9c%2Fcozirlp2_polling.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

### 인터페이스 유형별(UART,I2C) CO2값 읽기

* I2C

```cpp
#include <Wire.h>
#define Slave_adddress 0x41
#define CO2_READ_command 0x34
#define CO2_READ_and_test_command 0x02

void setup() {
  Wire.begin();
  Serial.begin(9600);   
}
void loop() {    
int CO2_value = 0;
 Wire.beginTransmission(Slave_adddress); // transmit to slave address
 Wire.write(CO2_READ_and_test_command);  // transmit to register address
 Wire.endTransmission();    // stop transmitting
 Wire.requestFrom(Slave_adddress, 3); //from slave request 2byte  
  while ( Wire.available()) {
    int CO2_high_value = Wire.read();
    int CO2_low_value = Wire.read();
   /* CO2_Self_test value = 85(DEC) : Sensor is nominal , 
   CO2_Self_test value = 170(DEC): Sensor error */
    int CO2_self_test = Wire.read(); 
    CO2_high_value = CO2_high_value <<8;
    CO2_value = CO2_high_value + CO2_low_value;
    Serial.print("CO2_value : ");
    Serial.print(CO2_value);   //reading CO2 value  
    Serial.println(" PPM ");
  }   
  delay(1000);
}
```

* UART

```cpp
#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 13); //Uno Rx Tx (12 13) = SoftwareSerial
const char* Polling_mode = "K 2\r\n";
const char* Stream_mode = "K 1\r\n";
const char* Standby_mode = "K 0\r\n";  
bool tx_ready;
bool rx_ready; 
String str;
void setup() {
  Serial.begin(9600); //시리얼 통신 초기화
  mySerial.begin(9600); 
  while(!mySerial){} //시리얼 통신 포트가 연결되기 전까지 대기
  delay(14); // power on data ready
  mySerial.print(Stream_mode); //Polling 모드로 변경
  mySerial.print("Z\r\n");  //CO2값 읽기 명령
}                              
 
void loop() 
{
 if(rx_ready == 0) // overflow 처리
 {
   delay(31); // Measurement data ready
   if(mySerial.available()>0) //수신받은 데이터가 0 초과, 즉 데이터가 존재한다면
   { //버퍼에서 읽어드린 char의 데이터를 String 형태로 반환
    str = "";
    str = mySerial.readStringUntil('\n'); 
    Serial.println(str);
    rx_ready = 1;   
    tx_ready = 1;
   }
 }
 else if(tx_ready == 1)
  {
     mySerial.print("Z\r\n"); //CO2값 읽기 명령
     tx_ready = 0;
     rx_ready = 0;
  }
}
```

**Serial Monitor**

* I2C

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-480c13a724048e0f31256b0d5501ee7dcc93bcd3%2Fi2c_Serial_monitir_co2_read.PNG?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* UART

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-5cd6a0d97d01377beb30b2da2e2175512807f70d%2Fco2_lp2_Serial_monitor_pic_size.PNG?alt=media" alt="" width="563"><figcaption></figcaption></figure>

### Digital filter

* 필터(Filtered)된 값과 필터 되지 않은(Unfiltered) CO2 값의 차이는 아래 그림과 같음

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-f67b5822da54da6af18c315d971061c5873eb3f9%2Fcozirlp2_filter_unfilter.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* 필터된(Filtered) CO2 값은 노이즈를 제거하여 더 정확한 값을 제공함

Digital filter 설정

* 필터 설정 범위: 1\~255( 1= Unfiltered)
* 필터의 설정 값이 증가하면 측정 출력 응답 시간이 늘어남

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-d3e279f2357fa15aa64acb278af465570f1a4dd2%2Fcozirlp2_filter_response_time.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* A=필터 설정 값
* A = 32 가 A = 16(default) 보다 T90에 도달하는 시간이 늘어남

Digital filter Command

| Command | Description | Example | Response |
| ------- | ----------- | ------- | -------- |
| A ###   | CO2 필터 값 설정 | A 16    | A 00016  |
| a       | CO2 필터 값 확인 | a       | a 00016  |

## 소스코드

* CO2 필터 값 확인

```cpp
#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 13); //Uno Rx Tx (12 13) = SoftwareSerial
const char* Polling_mode = "K 2\r\n";
const char* Stream_mode = "K 1\r\n";
const char* Standby_mode = "K 0\r\n";  
bool tx_ready;
bool rx_ready; 
String str;
void setup() {
  Serial.begin(9600); //시리얼 통신 초기화
  mySerial.begin(9600); 
  while(!mySerial){} //시리얼 통신 포트가 연결되기 전까지 대기
  delay(14); // power on data ready
  mySerial.print(Stream_mode); //Polling 모드로 변경
}                              
 
void loop() 
{
 if(rx_ready == 0) // overflow 처리
 {
   delay(31); // Measurement data ready
   if(mySerial.available()>0) //수신받은 데이터가 0 초과, 즉 데이터가 존재한다면
   { //버퍼에서 읽어드린 char의 데이터를 String 형태로 반환
    str = "";
    str = mySerial.readStringUntil('\n'); 
    Serial.println(str);
    rx_ready = 1;   
    tx_ready = 1;
   }
 }
 else if(tx_ready == 1)
  {
     mySerial.print("a\r\n"); //현재 설정된 필터 값 읽기 명령어
     tx_ready = 0;
     rx_ready = 0;
  }
}++
```

* 시리얼 모니터

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-c7389594806cb56265db8eee27b0cf226d7b0e45%2Fcozirlp2_filter_confirm.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>

* CO2 필터 값 설정

```cpp
#include <SoftwareSerial.h>
SoftwareSerial mySerial(12, 13); //Uno Rx Tx (12 13) = SoftwareSerial
const char* Polling_mode = "K 2\r\n";
const char* Stream_mode = "K 1\r\n";
const char* Standby_mode = "K 0\r\n";  
bool tx_ready;
bool rx_ready; 
String str;
void setup() {
  Serial.begin(9600); //시리얼 통신 초기화
  mySerial.begin(9600); 
  while(!mySerial){} //시리얼 통신 포트가 연결되기 전까지 대기
  delay(14); // power on data ready
  mySerial.print(Stream_mode); //Polling 모드로 변경
}                              
 
void loop() 
{
 if(rx_ready == 0) // overflow 처리
 {
   delay(31); // Measurement data ready
   if(mySerial.available()>0) //수신받은 데이터가 0 초과, 즉 데이터가 존재한다면
   { //버퍼에서 읽어드린 char의 데이터를 String 형태로 반환
    str = "";
    str = mySerial.readStringUntil('\n'); 
    Serial.println(str);
    rx_ready = 1;   
    tx_ready = 1;
   }
 }
 else if(tx_ready == 1)
  {
     mySerial.print("A 32\r\n"); //필터 값 변경 명령어 
     tx_ready = 0;
     rx_ready = 0;
  }
}
```

* 시리얼 모니터

<figure><img src="https://1534755138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8USAZVpjShlBinaURjim%2Fuploads%2Fgit-blob-7a416a98368670c94d1fb9377889cadee46ba549%2Fcozirlp2_serial_filter_change.png?alt=media" alt="" width="563"><figcaption></figcaption></figure>
