행복한 하루

비접촉 온도 센서 Digital Thermopile Sensor (TB-I2C-S70) I2C 연결, 프로그래밍, 작동 테스트 본문

IoT

비접촉 온도 센서 Digital Thermopile Sensor (TB-I2C-S70) I2C 연결, 프로그래밍, 작동 테스트

변화의 물결 2021. 2. 5. 15:29

 

 

안녕하세요

 

  이번 시간은 앞 내용에서 테스트해 보았던 온도 측정 센서에 대해서 제공해주는 보드를 이용하지 않고 배선해보고 프로그래밍하는 방법에 대해서 알아보도록 하겠습니다.

 온도 센서(Thermopile)의 값을 읽어 오는 방식에는 아날로그 값을 받아서 디지털로 변환하여 사용하는 표기해주는 방식과 온도 센서에 소형 칩이 있어 처리하고 간단하게 MCU에서 통신으로 값을 받아 볼 수 있는 방법이 있습니다. 그중에서 테스트해 본 제품은 I2C 통신을 지원하는 제품으로 I2C 통신을 통해서 값을 읽어오는 것을 프로그래밍해 보도록 하겠습니다.

 

아두이노 나노와 비접촉 온도센서(TH-I2C-S70) 연결

 

 우선 I2C 통신을 이용하려고 하면 Pull-up, Pull-down이라는 것을 간단하게 이해하고 있으면 도움이 됩니다.

그래서 간단하게 알아보겠습니다.

 

1. Pull-up, Pull-down 이해

1.1 개념 이해

  디지털 회로는 원칙적으로 H나 L의 전압 인가가 되어야 합니다. High와 Low의 중간 전압이 되면 내부 상태가 불안정하게 되거나 전력 소비가 증가한다. 그리고 L보다 낮은 전압이나 H보다 높은 전압이 인가되면 방해 전류 흐름이 생겨서 회로를 파괴할 수 있습니다.

 

  일반적으로 디지털 회로의 입력 단자는 내부 임피던스가 높기 때문에(전원 회로와 저항이 큼) 입력 단자가 어디에도 연결되어 있지 않으면 근처의 정전기나 전자기 유도에 의하여 예상할 수 없는 전압이 인가될 수 있습니다. 입력 단자가 어디에도 연결되어 있지 않은 상태를 플로팅(Floating) 상태라고 합니다.

 

 이러한 경우에는 수 kΩ ~ 수백kΩ 정도의 높은 저항으로 전원선이나 접지선에 연결합니다. 전원선에 연결한 것을 풀업 저항이라고 하고 접지선에 연결한 것을 풀다운 저항이라고 합니다.

 

 

Switch Open  상태

 

 스위치가 열려(Open) 있는 상태에서 Pull-up 경우는 1(High)로 읽게 되고, Pull-Down 경우 0(Low) 읽게 됩니다.

 

Switch Close  상태

 

  반대로 스위치가 닫힌(Close) 있는 상태에서 Pull-up 경우는 저항을 통과한 전류가 회로 쪽 저항보다 GND 쪽 저항이 더 작기 때문에 거의 모든 전류가 GND로 흐르면서 0(Low)으로 읽게 됩니다.

 

  스위치가 닫힌 상태의 Pull-down 경우 저항값보다 디지털 회로에 연결된 저항값이 더 작기 때문에 전류가 디지털 회로 쪽으로 흘러갑니다. 그래서 1(High) 읽게 됩니다.

 

 큰 개념에서 본다는 전류는 저항이 적은 쪽으로 흐른다고 보시면 이해하시기 편할 거라고 생각됩니다. 그중에 GND가 저항값이 적다고 보시면 전류 흐름이 왜 GND로 갈까에 대해 의문이 해결되지 않을까 합니다.

 

 

  

1.2 저항값 계산하는 방법

  5V 디지털 회로에서 최소 입력 전류가 1mA라고 한다면

  R = V / I  공식에 의해서 R = 5V / 1mA ,5000Ω = 5kΩ 저항을 달면 됩니다.

 

통상적으로 풀업 저항은 10kΩ~100kΩ 많이 사용한다고 합니다.

   

2. 아두이노와 온도센서 연결하기

  - 준비물 : 아두이노 나노, 가변저항 10k , TB-I2C-S70, 브레드 보드, 케이블

 

아두이노와 배선

 

  - 탄소 피막 저항을 사용하면 Thermopile 회사에서 제공해 주는 배선처럼 간단하게 가능한데 가진 탄소 저항이 없어서 가변저항을 사용하다 보니 배선이 늘어났습니다.

 

  - 중요한 것은 Thermopile에 방향이 있습니다. 살짝 튀어나온 쪽을 기준으로 하셔서 전원 쪽, 데이터 쪽을 구분하셔서 브레드보드 혹은 연결하시면 됩니다.

 

 

3. 소스 컴파일 & 실행

  - 측정된 온도만 본다면 제공해주고 있는 소스를 특별하게 수정할 필요 없이 실행시키면 측정된 온도가 나옵니다.

  제공된 아두이노 폴더를 보면 방사율 조정, 하는 부분 주소 가져오고 설정하는 코드로 되어 있습니다.

  - 단, I2C 주소 설정에서는 "주소 변경 예제는 필요 때문에 주소를 변경할 경우가 아니라면 사용하지 마시기 바랍니다.

  주소를 변경했을 경우, 코드를 수정하지 않으면 더는 통신이 안 됩니다." 주의를 주고 있으니 참고하시기 바랍니다.

 

제공 파일 중 아두이노 폴더

 

  다른 설정 없이 온도만 가져오는 소스로 확인해 보겠습니다.

  

/*****************************************************************************
*
* Project Name : TB-I2C 센서 온도 읽기 I2C 통신 예제
* Version : 1.0 
* SYSTEM CLOCK : 16Mhz 
* BOARD : Arduino UNO. 5V operation 
* I2C Clock : default 100kHz ( Max: 100kHz )
* Development environment : Arduino 1.6.4

 PORT Description

1. SDA : A4 or SDA (4번핀과 A4번핀은 다릅니다. 주의바랍니다.)
2. SCL : A5 or SCL (5번핀과 A5번핀은 다릅니다. 주의바랍니다.)
  센서 전원은 3.3V이며, 구체적인 회로 연결 방법은 첨부 pdf 파일을 참고하십시오.

 Revision history.

1. 2019.5.20.  : First version is released.
****************************************************************************/

#include <Wire.h>

#define TB_REG_SENSOR  0x06
#define TB_REG_OBJECT  0x07

uint8_t _deviceAddress = 0x3A;                // default Address
int16_t _rawObject;
int16_t _rawSensor;

const unsigned char crc8_table[256]=          //CRC table (Please don't change this value)
{
    0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,    0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
    0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,    0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
    0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,    0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
    0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,    0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
    0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,    0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
    0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,    0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
    0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,    0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
    0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,    0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
    0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,    0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
    0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,    0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
    0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,    0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
    0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,    0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
    0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,    0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
    0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,    0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
    0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,    0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
    0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,    0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3  
};

void setup() {
  Wire.begin();                              // Initialize I2C
  delay(200);                                // Waiting for sensor initialization.(min : 200ms)
  Serial.begin(9600);                       // Initialize Serial to log output
  while (!Serial) ;
}

void loop() {
  // put your main code here, to run repeatedly:
  if(GetObject() && GetSensor())              // 대상온도 및 센서온도 Read 완료되면
  {
     Serial.print("Object Temp : ");
     Serial.print(CalcTemp(_rawObject));   // 대상온도 출력
     Serial.print("    Sensor Temp : ");
     Serial.println(CalcTemp(_rawSensor));     // 센서온도 출력
     
     delay(100);                              // Delay 최소 100ms 이상
  }
  else
  {
    Serial.println("Please check the connection or I2C Address.");
    delay(1000);
  }
}

float CalcTemp(int rawTemp)                    // 온도계산
{
  float retTemp;
  retTemp = float(rawTemp)*0.02;
  retTemp -= 273.15;
  return retTemp; 
}
uint8_t GetObject(void)                   // 대상온도 읽기
{
  int16_t rawObj;
  if(I2CReadWord(TB_REG_OBJECT, &rawObj))
  {
    if (rawObj & 0x8000)                         // 최상위 비트가 1 이면 에러
    {
      return 0;
    }
    _rawObject = rawObj;
    return 1;
  }
}
uint8_t GetSensor(void)                    // 센서온도 읽기 
{
  int16_t rawSen;
  if(I2CReadWord(TB_REG_SENSOR, &rawSen) )
  {
    _rawSensor = rawSen;
    return 1;
  }
  return 0;
}

uint8_t I2CReadWord(uint8_t reg, int16_t *dest)
{
  uint8_t BUF[5], Low_Byte, High_Byte, PEC;

  Wire.beginTransmission(_deviceAddress);
  Wire.write(reg);
	
  Wire.endTransmission(false);             // Send restart
  Wire.requestFrom(_deviceAddress, (uint8_t)3);// 3Byte Read
	
  Low_Byte = Wire.read();                  // Low Byte 저장
  High_Byte = Wire.read();                 // High Byte 저장
  PEC = Wire.read();                       // 센서에서 전송한 PEC 값
  
  //PEC 연산을 위한 데이터 저장
  BUF[0] = _deviceAddress<<1;
  BUF[1] = reg;
  BUF[2] = (_deviceAddress<<1) | 0x01;
  BUF[3] = Low_Byte;
  BUF[4] = High_Byte;

  if (PEC == CalPEC(BUF, 5))              // 센서가 전송한 PEC 값이 맞는지 검증
  {
    *dest = (High_Byte<<8) | Low_Byte;    // 에러가 없으면 온도 데이터 저장
    return 1;
  }
  return 0;                               // 실패시 0 return
}

uint8_t CalPEC(uint8_t *crc, uint8_t nBytes)  // PEC 연산
{
  uint8_t data, count;
  uint16_t remainder = 0;
    
  for(count=0; count<nBytes; ++count)
  {
     data = *(crc++) ^ remainder;
     remainder = crc8_table[data] ^ (remainder >> 8);
  }
  return (uint8_t)remainder;
}

 

 

온도데이터 출력

 

  - A4번 핀과 SDA , A5번 핀이 SCL과 연결되고 배선처럼 Pull-Up 저항과 연결이 잘 되어 있다면 Object Temp(측정하고자 하는 물체 온도)와 Sensor Temp(센서 모듈 자체 온도)가 나오는 것을 확인할 수 있습니다.

 

4. 결  론

  - 특별하게 문제없이 물체 온도를 측정할 수 있습니다. 그러나 I2C 통신이라 풀업 저항을 구성해주어야 합니다. 그리고 방사율 등 설정해줄 수 있는 모듈이라 측정하고자 하는 물체 맞게 방사율을 조정해 주면 됩니다. 설정 소스도 오픈되어 있어 사용할 수 있습니다.

 

측정 오차와 제품 사항은 이전 편을 참조하시면 됩니다.

https://remnant24c.tistory.com/148

  

  - 수온 온도계랑 비교한 영상입니다.  방사율과 거리가 조정이 조금 필요한데 대략 몇 번 해 보면 결과 1도에서 ~ 2 정도 차이가 나는 것 같습니다.

 

감사합니다.

 

 

<참고 사이트>

1. 풀업과 풀다운

ko.wikipedia.org/wiki/%EB%94%94%EC%A7%80%ED%84%B8_%ED%9A%8C%EB%A1%9C#%ED%92%80%EC%97%85%EA%B3%BC_%ED%92%80%EB%8B%A4%EC%9A%B4

2. TB-I2C-S70

diwell.com/

 

 

“쿠팡 파트너스 활동을 통해 일정액의 수수료를 받을 수 있음"

Comments