STM32 ads1115 및 NTC 10K 3435 포팅

STM32 ADC는 12비트 resolution을 제공하지만, ads1115 IC는 16비트 ADC 4개 채널을 제공하여 STM32 ADC보다 정밀도 높기 때문에 이것을 사용하는 경우가 종종 있다. 뭐... STM32의 포트 부족으로 사용할 가능성도 있고...

 

ads1115 IC 포팅한 소스는 구글에서 쉽게 찾을 수 있으며, 필요하다면 아래 GitHub의 F407/Sensor 디렉토리를 참고하도록 한다. 아래 코드는 ads1115 포팅뿐 만 아니라 NTC10K 3435 온도센스의 온도 변환식도 포함하고 있다.

 

GitHub - highgon2/STM32: STM32 TestCode

STM32 TestCode. Contribute to highgon2/STM32 development by creating an account on GitHub.

github.com

ads1115는 동일 레지스터 어드레스에서 4개 채널의 ADC 값을 읽기 때문에, 특정 ADC 채널을 읽기 위해서 우선적으로 MUX_AINx를 설정해야 하며, Single ended로 읽을지 아니면 Continuous로 읽을지를 설정할 수 있다. 예제 코드에선 Single ended로 설정하여 요청한 순간의 ADC 값을 변환하도록 레지스터를 설정하였다.

uint32_t ads1115_set_temperature(uint8_t port)
{
  uint8_t mux_port = 0;
  uint8_t config[2] = {
      0,
  };

  switch (port) {
  case 0:
    mux_port = ADS1115_MUX_AIN3;
    break;
  case 1:
    mux_port = ADS1115_MUX_AIN2;
    break;
  case 2:
    mux_port = ADS1115_MUX_AIN1;
    break;
  case 3:
    mux_port = ADS1115_MUX_AIN0;
    break;
  default:
    error("%s() : invalid port : %d", __func__, port);
    return 1;
  }

  config[0] = ADS1115_OS | mux_port | pga | ADS1115_MODE;
  config[1] = data_rate | ADS1115_COMP_MODE | ADS1115_COMP_POL | ADS1115_COMP_LAT | ADS1115_COMP_QUE;

  if (i2c_write(TEMP_SENSOR, ADS1115_CONFIG_REG, 1, config, 2, 10) != 0) {
    return 1;
  }

  return 0;
}

아래 코드는 위 코드에서 설정한 채널의 ADC 값을 읽어 NTC 온도센서의 저항 값으로 온도를 측정한 코드이다.

uint32_t ads1115_get_temperature(float* value)
{
  uint8_t data[2];
  int16_t adc_value;
  float voltage = 0;
  float resistor = 0;

  if (i2c_read(TEMP_SENSOR, ADS1115_CONVER_REG, 1, data, 2, 10) != 0) {
    return 1;
  }

  /**
   * NTC 온도센서 저항(R2) 계산 (https://openstory.tistory.com/230)
   *   R1   = 10Kohm
   *   V1   = 5267 (입력전압)
   *   Vout = 저항을 거친 출력전압
   *
   *   R2 = (R1 * Vout) / (V1 - Vout)
   *      = ((10 * 1000) * voltage) / (5267 - voltage)
   *
   *  NTC 저항(R2)에 따른 온도(T2) 계산 (https://m.blog.naver.com/sst-korea/221875675521)
   *    B  = 3435 (NTCLE413E2103F520L)
   *    T1 = 기준온도 25
   *    TK = 기준온도의 절대온도 값 273 + 25 = 298
   *    R1 = 10Kohm
   *
   *    T2 = B / ((B / TK) - log(R1 / R2))
   *       = 3435 / ((3435 / 298) - log((10 * 1000) / resistor))
   */
  adc_value = (int16_t)(data[0] << 8) | data[1];
  voltage = adc_value * ads1115_get_volate(pga); // mV

  if (voltage > 5200) {
    *value = 0;
  }
  else {
    resistor = ((10 * 1000) * voltage) / (5267 - voltage);
    *value = (3435.0 / ((3435.0 / 298.0) - log((10 * 1000) / resistor))) - 273;
  }

  return 0;
}

주석처리된 블로그를 참고하여 온도 값을 변환한 것이며, 입력전압이 5.2V일 때 NTC 온도센서의 저항을 구한 후, 온도 값으로 변환하는 로직을 추가한 것이다. 자세한 사항을 주석에 있는 블로그를 참고하도록 한다.

 

여기서 하나 주의할 사항을 ads1115 datasheet를 보면 Single ended로 ADC 채널을 설정했다면, Conversion time이 최소 10ms가 필요하기 때문에 아래 코드와 같이 ads1115의 읽을 ADC 채널 설정 후 10ms를 대기하여야 한다.

uint32_t ads1115_read_temperature(uint8_t port, float* value)
{
  if (ads1115_set_temperature(port) == 0) {
    HAL_Delay(10); /* minimum conversion time */
    ads1115_get_temperature(value);
  }

  return 1;
}