HVAC_M7_ADC_TEMP/ADC_Temp_KST45-14-2.c

221 lines
8.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by cfif on 02.12.2025.
//
#include "stdint.h"
#include <math.h>
// Константы
#define ADC_MAX 4095.0f // 12-битный АЦП
#define R1 3000.0f // Сопротивление делителя напряжения
#define TABLE_START_TEMP (-40)
#define TABLE_END_TEMP 85
#define TABLE_SIZE 26
// Структура для хранения табличных данных
typedef struct {
int temp_c; // Температура (°C)
float r_nom; // Номинальное сопротивление (Ω)
float r_min; // Минимальное сопротивление (Ω)
float r_max; // Максимальное сопротивление (Ω)
} ntc_table_entry;
// Таблица из документа
static const ntc_table_entry ntc_table[] = {
{-40, 100950.0f, 98626.0f, 103274.0f},
{-35, 72777.0f, 71232.0f, 74322.0f},
{-30, 53100.0f, 52064.0f, 54136.0f},
{-25, 39111.0f, 38413.0f, 39809.0f},
{-20, 29121.0f, 28647.0f, 29595.0f},
{-15, 21879.0f, 21556.0f, 22201.0f},
{-10, 16599.0f, 16379.0f, 16819.0f},
{-5, 12695.0f, 12544.0f, 12845.0f},
{0, 9795.0f, 9697.0f, 9893.0f},
{5, 7616.0f, 7526.0f, 7706.0f},
{10, 5970.0f, 5892.0f, 6048.0f},
{15, 4712.0f, 4645.0f, 4780.0f},
{20, 3747.0f, 3689.0f, 3805.0f},
{25, 3000.0f, 2950.0f, 3050.0f},
{30, 2417.0f, 2374.0f, 2460.0f},
{35, 1959.0f, 1923.0f, 1996.0f},
{40, 1598.0f, 1566.0f, 1630.0f},
{45, 1311.0f, 1283.0f, 1338.0f},
{50, 1081.0f, 1057.0f, 1104.0f},
{55, 895.9f, 875.5f, 916.2f},
{60, 746.4f, 728.7f, 764.1f},
{65, 624.9f, 609.6f, 640.2f},
{70, 525.6f, 512.3f, 538.9f},
{75, 444.4f, 432.8f, 456.1f},
{80, 377.4f, 367.2f, 387.6f},
{85, 321.7f, 312.8f, 330.7f}
};
// Функция расчёта сопротивления NTC из значения АЦП
static float calculate_resistance(uint16_t adc_value) {
if (adc_value == 0 || adc_value >= (uint16_t) ADC_MAX) {
return 0.0f;
}
// Формула делителя напряжения: R_ntc = R1 * (ADC_MAX / adc_value - 1)
// float R_ntc = R1 * (ADC_MAX / (float)adc_value - 1.0f);
float R_ntc = R1 * (float) adc_value / (ADC_MAX - (float) adc_value);
return R_ntc;
}
// Бинарный поиск в таблице
static int find_interval_index(float resistance) {
int left = 0;
int right = TABLE_SIZE - 1;
// Проверка границ
if (resistance >= ntc_table[0].r_nom) return 0;
if (resistance <= ntc_table[right].r_nom) return right - 1;
// Бинарный поиск
while (left <= right) {
int mid = left + (right - left) / 2;
if (mid < TABLE_SIZE - 1 &&
resistance <= ntc_table[mid].r_nom &&
resistance >= ntc_table[mid + 1].r_nom) {
return mid;
}
if (resistance > ntc_table[mid].r_nom) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1; // Не найден
}
// Интерполяция с использованием уравнения Стейнхарта-Харта между точками
static float interpolate_steinhart(float resistance, int index) {
// Берем две соседние точки из таблицы
float t1 = (float) ntc_table[index].temp_c + 273.15f; // в Кельвинах
float t2 = (float) ntc_table[index + 1].temp_c + 273.15f;
float r1 = ntc_table[index].r_nom;
float r2 = ntc_table[index + 1].r_nom;
// Вычисляем коэффициент B для интервала
float B = logf(r1 / r2) / (1.0f / t1 - 1.0f / t2);
// Используем уравнение Стейнхарта-Харта для вычисления температуры
float steinhart = logf(resistance / r1) / B + 1.0f / t1;
float temp_k = 1.0f / steinhart;
return temp_k - 273.15f; // Конвертация в °C
}
// Линейная интерполяция в логарифмическом масштабе
static float interpolate_log_linear(float resistance, int index) {
float t1 = (float) ntc_table[index].temp_c;
float t2 = (float) ntc_table[index + 1].temp_c;
float r1 = ntc_table[index].r_nom;
float r2 = ntc_table[index + 1].r_nom;
float log_r1 = logf(r1);
float log_r2 = logf(r2);
float log_r = logf(resistance);
return t1 + (t2 - t1) * (log_r - log_r1) / (log_r2 - log_r1);
}
// Основная функция для получения температуры
float get_temperature_from_adc_KST45(uint16_t adc_value, int use_steinhart) {
float resistance = calculate_resistance(adc_value);
if (resistance <= 0.0f) {
return -273.15f; // Ошибка
}
int index = find_interval_index(resistance);
if (index < 0 || index >= TABLE_SIZE - 1) {
// Вне диапазона таблицы
if (resistance >= ntc_table[0].r_nom) return TABLE_START_TEMP;
if (resistance <= ntc_table[TABLE_SIZE - 1].r_nom) return TABLE_END_TEMP;
return -273.15f; // Ошибка
}
if (use_steinhart) {
return interpolate_steinhart(resistance, index);
} else {
return interpolate_log_linear(resistance, index);
}
}
// Предварительно вычисленная таблица для быстрого доступа
typedef struct {
uint16_t adc_value; // Значение АЦП
int16_t temp_c; // Температура в °C * 10 (для фиксированной точки)
} adc_temp_lookup;
static adc_temp_lookup fast_lookup[256]; // Таблица на 256 значений
static void init_fast_lookup_table(void) {
// Создаем таблицу для быстрого преобразования АЦП->температура
for (int i = 0; i < 256; i++) {
uint16_t adc = i * 16; // Для 12-битного АЦП (0-4095)
float temp = get_temperature_from_adc_KST45(adc, 0);
fast_lookup[i].adc_value = adc;
fast_lookup[i].temp_c = (int16_t) (temp * 10.0f); // Храним с точностью 0.1°C
}
}
int16_t get_temperature_fast_KST45(uint16_t adc_value) {
// Простой поиск в таблице с линейной интерполяцией
uint8_t index = adc_value >> 4; // Делим на 16
if (index >= 255) return fast_lookup[255].temp_c;
uint16_t adc1 = fast_lookup[index].adc_value;
uint16_t adc2 = fast_lookup[index + 1].adc_value;
int16_t temp1 = fast_lookup[index].temp_c;
int16_t temp2 = fast_lookup[index + 1].temp_c;
// Линейная интерполяция
return temp1 + ((temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
}
// Константы для датчика
#define R25 3000.0f // Сопротивление при 25°C
#define B 3930.0f // Коэффициент B25/50
#define T25 298.15f // 25°C в Кельвинах
// Функция расчёта температуры из сопротивления
static float calculate_temperature(float resistance) {
if (resistance <= 0) return -273.15f; // Абсолютный ноль
// Расчёт по уравнению Стейнхарта-Харта
float t_kelvin = 1.0f / (1.0f / T25 + (1.0f / B) * logf(resistance / R25));
return t_kelvin - 273.15f;
}
// Прямой расчёт температуры из значения АЦП
float calculate_temperature_direct_KST45(uint16_t adc_value) {
float resistance = calculate_resistance(adc_value);
return calculate_temperature(resistance);
}
// сигнал АЦП, (R резистора / R термистора), B термистора, t термистора, разрешение АЦП
static float NTC_computeRR(float analog, float baseDiv, uint16_t BB, uint8_t t, uint8_t res) {
if (analog <= 0 || isnan(analog)) return INFINITY;
analog = baseDiv / ((float) ((1 << res) - 1) / analog - 1.0f);
analog = (logf(analog) / (float)BB) + 1.0f / ((float)t + 273.15f);
return (1.0f / analog - 273.15f);
}
// сигнал АЦП, R резистора, B термистора, t термистора, R термистора, разрешение АЦП
float NTC_compute_KST45(float analog, uint32_t R, uint16_t BB, uint8_t t, uint32_t Rt, uint8_t res) {
return NTC_computeRR(analog, (float) R / (float)Rt, BB, t, res);
}
void zz_AAS_KST45() {
NTC_compute_KST45(0, R25, B, 25, (uint32_t)R25, 12);
}