PT1000은 널리 쓰이는 온도센서로 온도가 높아지면 저항 값이 커지는 특성을 가지고 있다. 따라서 저항 값에 따라 온도를 측정할 수 있다. 구글링하여 보면 저항에 대한 온도 테이블이 검색되지만, 이것을 하드코딩하는 것은 매우 단순하지만 노가다라는 생각에 산술식으로 변환하려고 한다.
위 표를 참고하면 PT1000은 기준 온도 0℃에서 저항값 1000을 가지며, 온도가 올라가면 저항이 커지고, 온도가 낮아지면 저항값이 작아진다. 참고로 PT100은 저항이 1/10 작은 값을 가지므로, 위 표에서 저항 값을 10으로 나눈 값으로 온도를 환산할 수 있다.
그리고, 아래 수식을 이용하여 PT100 & PT1000의 저항 값에 따른 온도를 측정할 수 있다.
위 수식으로 온도를 구하려면 아래 함수를 사용하면 쉽게 구할 수 있다. 위 저항에 따른 온도 값을 입력하면 정확하게 나오는 것을 확인할 수 있다.
static float calc_temperature(float Cur_R)
{
/**
* PT1000 온도 계산
*
* A = 3.9083e-3
* B = -5.775e-7
* C = -4.183e-12
* R0 = 1000
* Cur_R = PT1000 저항값
*
* T = (sqrt(A^2 - (4 * B * (1-(Cur_R / R0))) - A) / (2 * B)
*/
// Cur_R = 1077.95; // 20도
// Cur_R = 1143.81; // 37도
// Cur_R = 723.34; // -70도
float t1 = PT1000_A * PT1000_A;
float t2 = 4 * PT1000_B * (1 - (Cur_R / PT1000_R0));
float t3 = 2 * PT1000_B;
float temp = (sqrt(t1 - t2) - PT1000_A) / t3;
// debug("Cur_R = %.2f, Temp = %.2f", Cur_R, temp);
return temp;
}
그런데, 여기서 저항값을 갖고 온도를 측정할 수 있지만, STM32 ADC 출력 값은 전압을 측정하는 것이기 때문에 측전된 전압으로 저항 값을 수식이 필요하다. 이 부분은 하드웨어 담당자가 알려준 수식을 이용하였다. 아직 이부분은 정확한 이해가 부족하지만 일단 블로그에 정리해 두도록 한다.
#define VREF (3000.0)
#define ADC_12BIT_RESOLUTION (4096.0)
#define PT1000_A (3.9083e-3)
#define PT1000_B (-5.775e-7)
#define PT1000_C (-4.183e-12)
#define PT1000_R0 (1000)
#define OHM_MAGINE (5)
static float get_resistor_value(float adc_volt)
{
uint32_t resistor = (uint32_t)(((PT1000_R0 - OHM_MAGINE) * adc_volt / (VREF - adc_volt)) * 100);
return resistor / 100.0;
}
static float get_adc_out_volt(uint8_t type, uint8_t index)
{
uint16_t value = adc_get_value(type, index);
if (value == 0) {
return 0;
}
return ((value * VREF) / ADC_12BIT_RESOLUTION);
}
STM32 ADC는 12비트이기 때문에 resolution 값이 4096이며, 레퍼런스 전압이 3V이므로 ADC 값 1비트당 약 0.7324mV을 나타낸다. ADC 출력 전압에 따른 저항 값은 get_resistor_value() 함수를 이용하면 ADC 출력 전압에 걸린 저항을 구할 수 있으며, 이 값을 갖고 온도를 측정하면 된다.
관련 예제코드는 아래 코드를 참고하면 된다. 참고로 ADC 값 튀는 것을 방지하기 위해 ADC 100개의 평균 값으로 상보 필터를 적용하여 상온에서 100℃까지 측정하였다. 오차는 3℃ 갖는다.