Study/Embedded SW

NTC 온도센서(A1737) 온도 구하기

Answer Choi 2025. 11. 12. 14:43
반응형

NTC A1737은 amphenol사의 ntc인데 이 제품은 온도에 따른 저항 값이 완전히 선형적이지 않습니다.

위 표와 같이 -40~0까지 저항이 급속히 떨어지며 0도부터 210도까지도 선형적이지 않고 아래 그림과 같이 몇번의 전환점이 있습니다.

 

이 센서를 ADC로 읽어서 계산을 해보려고 합니다.

 

adc 입력회로는 아래와 같습니다.

 

ADC로 전압을 읽어보면 저항이 클 때에는 3.3V에 가깝게 나오고 저항이 낮으면 0V에 가까워 집니다.

 

위의 저항-온도 테이블 보시면 -40도~210도 까지 측정 가능하니 범위를 벗어난 것은 오류 처리를 하면 됩니다.

 

그리고 전압으로 읽어서 온도를 구할 예정이므로 전압을 입력으로 함수를 만들었습니다.

#define VDDA_VOLTAGE        3.3f       // MCU 공급 전압 (V)
#define R_FIXED             510.0f     // 상단 고정 저항값 R1 (옴)

// 온도와 저항 쌍을 저장하는 구조체 정의
typedef struct {
    float resistance;
    float temperature_c;
} ResistanceTempPair;

// 이미지 데이터시트에서 발췌한 R-T 테이블 (저항 기준 오름차순으로 정렬 필수)
const ResistanceTempPair rt_table[] = {
    {155.4f,    210.0f},
    {309.9f,    175.0f},
    {541.8f,    150.0f},
    {886.9f,    130.0f},
    {2036.0f,   100.0f},
    {3776.0f,   80.0f},
    {10851.0f,  50.0f},
    {30000.0f,  25.0f},
    {37387.0f,  20.0f},
    {96248.0f,  0.0f},
    {965530.0f, -40.0f}
};

// 테이블 크기 계산
const int table_size = sizeof(rt_table) / sizeof(rt_table[0]);


/**
 * @brief 전압 분배기에서 측정된 전압을 섭씨 온도로 변환합니다 (LUT 방식).
 *
 * @param input_voltage TEMP1 핀에서 측정된 ADC raw value를 변환한 전압 값 (V)
 * @return float 섭씨 온도 (°C), 범위를 벗어나면 -999.0f 반환
 */
float convert_voltage_to_celsius_lut(float input_voltage) {
    float thermistor_resistance, temperature_c;

    // 1. 입력 전압 유효성 검사
    if (input_voltage < 0.0f || input_voltage > VDDA_VOLTAGE) {
        return -999.0f;
    }

    // 2. 전압 분배기 공식을 사용하여 NTC 서미스터의 저항 계산
    if (input_voltage >= (VDDA_VOLTAGE - 0.001f)) {
        thermistor_resistance = 9999999999.0f; // 매우 높은 저항
    } else if (input_voltage <= 0.001f) {
        thermistor_resistance = 0.0f; // 거의 0옴
    } else {
        thermistor_resistance = R_FIXED * (input_voltage / (VDDA_VOLTAGE - input_voltage));
    }

    // 3. 룩업 테이블을 사용하여 온도 찾기 (선형 보간)

    // 테이블 범위를 벗어나는 경우 처리 (최저/최고 온도 반환 또는 에러)
    if (thermistor_resistance > rt_table[table_size - 1].resistance) {
        return rt_table[table_size - 1].temperature_c; // -40도 이하
    }
    if (thermistor_resistance < rt_table[0].resistance) {
        return rt_table[0].temperature_c; // 210도 이상
    }

    // 보간할 두 지점 찾기
    for (int i = 0; i < table_size - 1; i++) {
        // 현재 저항값이 rt_table[i+1]과 rt_table[i] 사이에 있다면
        if (thermistor_resistance >= rt_table[i].resistance && thermistor_resistance <= rt_table[i+1].resistance) {

            float r1 = rt_table[i].resistance;
            float t1 = rt_table[i].temperature_c;
            float r2 = rt_table[i+1].resistance;
            float t2 = rt_table[i+1].temperature_c;

            // 선형 보간 공식 적용
            // T = T1 + (R - R1) * (T2 - T1) / (R2 - R1)
            temperature_c = t1 + (thermistor_resistance - r1) * (t2 - t1) / (r2 - r1);
            return temperature_c;
        }
    }

    // 찾지 못한 경우 (예외 상황)
    return -999.0f;
}

 

adc로 읽어와 전압으로 변환한 후 전압을 기준으로 저항 값을 유추합니다.

 

유추된 저항이 A1737이 읽을 수 있는 범위에 있는지 검사합니다.

 

이상이 없는 경우 저항을 lookup table을 이용하여 어느 저항 사이인지를 구합니다.(r1,r2)

 

이제 두 저항 사이를 점을 찍고 측정한 저항 값을 그 사이에서 온도를 유추해 냅니다.(저항과 저항사이는 선형성이 있다고 판단 합니다.)

 

 

 

예를 들어 위 테이블에 있는 309.9옴을 연결한 후 계산해 보겠습니다.

 

309.9옴이면 adc로 읽어 온 전압은 1.247V입니다.

저항을 역산해보니 309.7759옴이 나옵니다.

309.7759옴은 155.4옴과 309.9옴 사이입니다.

 

계산해보면 175.0281047도가 나옵니다.

테이블의 175도와 비슷하게 나오네요^^

 

 

 

 

반응형