Init
This commit is contained in:
parent
8eed3f46f4
commit
6cf52262e2
|
|
@ -7,39 +7,68 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Константы
|
// Типы таблиц NTC
|
||||||
#define ADC_MAX 4095.0f // 12-битный АЦП
|
typedef enum {
|
||||||
#define R1 3300.0f // Сопротивление делителя напряжения
|
TABLE_KST45 = 0, // Таблица из документа KST45
|
||||||
#define TABLE_START_TEMP (-40)
|
TABLE_INCAR = 1 // Таблица из документа Incar
|
||||||
#define TABLE_END_TEMP 85
|
} eNtcTable;
|
||||||
#define TABLE_SIZE 38
|
|
||||||
|
|
||||||
// Параметры Steinhart-Hart для термистора
|
|
||||||
#define koef_A 0.001741624168166423
|
|
||||||
#define koef_B 0.00017003940268680147
|
|
||||||
#define koef_C 0.0000004890545443703666
|
|
||||||
|
|
||||||
#define TABLE_SIZE_LOOKUP 4096
|
|
||||||
|
|
||||||
|
// Алгоритмы расчёта температуры
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ALG_STEINHART = 0,
|
ALG_STEINHART = 0,
|
||||||
ALG_STEINHART_FULL = 1,
|
ALG_STEINHART_FULL = 1,
|
||||||
ALG_LINEAR = 2
|
ALG_LINEAR = 2
|
||||||
} eAlg;
|
} eAlg;
|
||||||
|
|
||||||
|
// Константы
|
||||||
|
#define ADC_MAX 4095.0f // 12-битный АЦП
|
||||||
|
|
||||||
|
// Параметры Steinhart-Hart для термистора (общие для всех таблиц)
|
||||||
|
#define koef_A 0.001741624168166423
|
||||||
|
#define koef_B 0.00017003940268680147
|
||||||
|
#define koef_C 0.0000004890545443703666
|
||||||
|
|
||||||
|
// Размеры таблиц
|
||||||
|
#define TABLE_SIZE_KST45 26
|
||||||
|
#define TABLE_SIZE_INCAR 38
|
||||||
|
#define TABLE_SIZE_LOOKUP 4096
|
||||||
|
|
||||||
// Предварительно вычисленная таблица для быстрого доступа
|
// Предварительно вычисленная таблица для быстрого доступа
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t adc_value; // Значение АЦП
|
uint16_t adc_value; // Значение АЦП
|
||||||
int16_t temp_c; // Температура в °C * 10 (для фиксированной точки)
|
int16_t temp_c; // Температура в °C * 10 (для фиксированной точки)
|
||||||
float resistance_ohm; // Сопротивление в Ом, соответствующее значению АЦП
|
float resistance_ohm; // Сопротивление в Ом, соответствующее значению АЦП
|
||||||
|
eNtcTable table_type; // Тип таблицы, для которой вычислены данные
|
||||||
} adc_temp_lookup;
|
} adc_temp_lookup;
|
||||||
|
|
||||||
void init_fast_lookup_table(eAlg use_alg);
|
// Структура конфигурации для NTC
|
||||||
|
typedef struct {
|
||||||
|
eNtcTable table_type; // Тип используемой таблицы
|
||||||
|
float r1; // Сопротивление делителя напряжения (Ом)
|
||||||
|
int16_t start_temp; // Начальная температура таблицы (°C)
|
||||||
|
int16_t end_temp; // Конечная температура таблицы (°C)
|
||||||
|
uint16_t table_size; // Размер таблицы
|
||||||
|
} ntc_config_t;
|
||||||
|
|
||||||
|
// Функции инициализации и конфигурации
|
||||||
|
void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg);
|
||||||
|
void set_active_config(eNtcTable table_type, float r1);
|
||||||
|
const ntc_config_t* get_active_config(void);
|
||||||
|
|
||||||
|
// Основные функции получения температуры
|
||||||
float get_temperature_from_adc(uint16_t adc_value, eAlg alg);
|
float get_temperature_from_adc(uint16_t adc_value, eAlg alg);
|
||||||
|
float get_temperature_from_adc_with_table(uint16_t adc_value, eAlg alg, eNtcTable table_type, float r1);
|
||||||
|
float get_resistance_from_adc(uint16_t adc_value);
|
||||||
|
float get_resistance_from_adc_with_table(uint16_t adc_value, eNtcTable table_type, float r1);
|
||||||
|
|
||||||
|
// Быстрые функции с использованием предварительно вычисленной таблицы
|
||||||
int16_t get_temperature_log_fast(uint16_t adc_value);
|
int16_t get_temperature_log_fast(uint16_t adc_value);
|
||||||
int16_t get_temperature_linear_fast(uint16_t adc_value);
|
int16_t get_temperature_linear_fast(uint16_t adc_value);
|
||||||
float get_resistance_from_adc(uint16_t adc_value); // Новая функция для получения сопротивления
|
|
||||||
|
|
||||||
float get_resistance_log_fast(int16_t temperature_c10);
|
float get_resistance_log_fast(int16_t temperature_c10);
|
||||||
float get_resistance_fast_simple(int16_t temperature_c10);
|
float get_resistance_fast_simple(int16_t temperature_c10);
|
||||||
|
|
||||||
|
// Вспомогательные функции
|
||||||
|
void print_fast_lookup_table(void);
|
||||||
|
void print_table_info(void);
|
||||||
|
|
||||||
#endif //MDF_ADC_TEMP_KST45_14_2_H
|
#endif //MDF_ADC_TEMP_KST45_14_2_H
|
||||||
52
APP/main.c
52
APP/main.c
|
|
@ -4,22 +4,16 @@
|
||||||
extern adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP];
|
extern adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP];
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Инициализация таблицы быстрого поиска
|
uint16_t adc_value = 1980;
|
||||||
init_fast_lookup_table(ALG_STEINHART);
|
|
||||||
|
|
||||||
uint16_t value = 1980;
|
printf("\n-----------TABLE_KST45------------------\n");
|
||||||
|
|
||||||
// Получение температуры различными методами
|
// Инициализация с таблицей KST45 и R1=3300 Ом
|
||||||
float T_ALG_STEINHART = get_temperature_from_adc(value, ALG_STEINHART);
|
init_fast_lookup_table(TABLE_KST45, 3000.0f, ALG_STEINHART);
|
||||||
int16_t T_FAST = get_temperature_log_fast(value);
|
// Получение температуры
|
||||||
float resistance = get_resistance_from_adc(value);
|
float temp = get_temperature_from_adc(adc_value, ALG_STEINHART);
|
||||||
|
int16_t temp_fast = get_temperature_log_fast(adc_value);
|
||||||
printf("T_ALG_STEINHART = %f °C\n", T_ALG_STEINHART);
|
printf("ADC: %u, temp_fast: %.1f °C\n", adc_value, temp_fast / 10.0f);
|
||||||
printf("T_FAST = %.1f °C\n", T_FAST / 10.0f);
|
|
||||||
printf("Resistance = %.2f Ω\n", resistance);
|
|
||||||
|
|
||||||
float R = get_resistance_log_fast(227);
|
|
||||||
printf("Resistance FAST = %.2f Ω\n", R);
|
|
||||||
|
|
||||||
|
|
||||||
// Пример доступа к таблице
|
// Пример доступа к таблице
|
||||||
|
|
@ -31,6 +25,7 @@ int main() {
|
||||||
fast_lookup[i].resistance_ohm);
|
fast_lookup[i].resistance_ohm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Пример доступа к таблице
|
||||||
printf("\nПример данных из таблицы быстрого поиска:\n");
|
printf("\nПример данных из таблицы быстрого поиска:\n");
|
||||||
for(int i = 0; i < 5; i++) {
|
for(int i = 0; i < 5; i++) {
|
||||||
printf("ADC: %u, Temp: %.1f °C, Resistance: %.2f Ω\n",
|
printf("ADC: %u, Temp: %.1f °C, Resistance: %.2f Ω\n",
|
||||||
|
|
@ -39,5 +34,34 @@ int main() {
|
||||||
fast_lookup[i].resistance_ohm);
|
fast_lookup[i].resistance_ohm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
printf("\n-----------INCAR------------------\n");
|
||||||
|
// Смена конфигурации на INCAR с R1=20000 Ом
|
||||||
|
// set_active_config(TABLE_INCAR, 2000.0f);
|
||||||
|
init_fast_lookup_table(TABLE_INCAR, 20000.0f, ALG_STEINHART);
|
||||||
|
|
||||||
|
temp_fast = get_temperature_log_fast(adc_value);
|
||||||
|
printf("ADC: %u, temp_fast: %.1f °C\n", adc_value, temp_fast / 10.0f);
|
||||||
|
|
||||||
|
// Пример доступа к таблице
|
||||||
|
printf("\nПример данных из таблицы быстрого поиска:\n");
|
||||||
|
for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 5; i--) {
|
||||||
|
printf("ADC: %u, Temp: %.1f °C, Resistance: %.2f Ω\n",
|
||||||
|
fast_lookup[i].adc_value,
|
||||||
|
fast_lookup[i].temp_c / 10.0f,
|
||||||
|
fast_lookup[i].resistance_ohm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Пример доступа к таблице
|
||||||
|
printf("\nПример данных из таблицы быстрого поиска:\n");
|
||||||
|
for(int i = 0; i < 5; i++) {
|
||||||
|
printf("ADC: %u, Temp: %.1f °C, Resistance: %.2f Ω\n",
|
||||||
|
fast_lookup[i].adc_value,
|
||||||
|
fast_lookup[i].temp_c / 10.0f,
|
||||||
|
fast_lookup[i].resistance_ohm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
//
|
//
|
||||||
// Created by cfif on 02.12.2025.
|
// Created by cfif on 02.12.2025.
|
||||||
//
|
//
|
||||||
#include "stdint.h"
|
|
||||||
#include "ADC_Temp.h"
|
#include "ADC_Temp.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
// Структура для хранения табличных данных
|
// Структура для хранения табличных данных
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -11,9 +11,8 @@ typedef struct {
|
||||||
float r_nom; // Номинальное сопротивление (Ω)
|
float r_nom; // Номинальное сопротивление (Ω)
|
||||||
} ntc_table_entry;
|
} ntc_table_entry;
|
||||||
|
|
||||||
/*
|
|
||||||
// Таблица из документа KST45
|
// Таблица из документа KST45
|
||||||
static const ntc_table_entry ntc_table[] = {
|
static const ntc_table_entry ntc_table_kst45[] = {
|
||||||
{-40, 100950.0f},
|
{-40, 100950.0f},
|
||||||
{-35, 72777.0f},
|
{-35, 72777.0f},
|
||||||
{-30, 53100.0f},
|
{-30, 53100.0f},
|
||||||
|
|
@ -41,10 +40,9 @@ static const ntc_table_entry ntc_table[] = {
|
||||||
{80, 377.4f},
|
{80, 377.4f},
|
||||||
{85, 321.7f}
|
{85, 321.7f}
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|
||||||
// Таблица из документа Incar
|
// Таблица из документа Incar
|
||||||
static ntc_table_entry ntc_table[] = {
|
static const ntc_table_entry ntc_table_incar[] = {
|
||||||
{-40, 101000.0f},
|
{-40, 101000.0f},
|
||||||
{-35, 72600.0f},
|
{-35, 72600.0f},
|
||||||
{-30, 52720.0f},
|
{-30, 52720.0f},
|
||||||
|
|
@ -85,38 +83,75 @@ static ntc_table_entry ntc_table[] = {
|
||||||
{85, 283.0f}
|
{85, 283.0f}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Предварительно вычисленная таблица для быстрого доступа
|
// Глобальная таблица быстрого доступа
|
||||||
adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP];
|
adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP];
|
||||||
|
|
||||||
|
// Активная конфигурация
|
||||||
|
static ntc_config_t active_config = {
|
||||||
|
.table_type = TABLE_KST45,
|
||||||
|
.r1 = 3300.0f,
|
||||||
|
.start_temp = -40,
|
||||||
|
.end_temp = 85,
|
||||||
|
.table_size = TABLE_SIZE_KST45
|
||||||
|
};
|
||||||
|
|
||||||
|
// Вспомогательная функция для получения таблицы по типу
|
||||||
|
static const ntc_table_entry* get_table_by_type(eNtcTable table_type, uint16_t* size, int16_t* start_temp, int16_t* end_temp) {
|
||||||
|
const ntc_table_entry* table = NULL;
|
||||||
|
*size = 0;
|
||||||
|
|
||||||
|
switch(table_type) {
|
||||||
|
case TABLE_KST45:
|
||||||
|
table = ntc_table_kst45;
|
||||||
|
*size = TABLE_SIZE_KST45;
|
||||||
|
*start_temp = -40;
|
||||||
|
*end_temp = 85;
|
||||||
|
break;
|
||||||
|
case TABLE_INCAR:
|
||||||
|
table = ntc_table_incar;
|
||||||
|
*size = TABLE_SIZE_INCAR;
|
||||||
|
*start_temp = -40;
|
||||||
|
*end_temp = 85;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
table = ntc_table_kst45;
|
||||||
|
*size = TABLE_SIZE_KST45;
|
||||||
|
*start_temp = -40;
|
||||||
|
*end_temp = 85;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
// Функция расчёта сопротивления NTC из значения АЦП
|
// Функция расчёта сопротивления NTC из значения АЦП
|
||||||
static float calculate_resistance(uint16_t adc_value) {
|
static float calculate_resistance(uint16_t adc_value, float r1) {
|
||||||
if (adc_value == 0 || adc_value >= (uint16_t) ADC_MAX) {
|
if (adc_value == 0 || adc_value >= (uint16_t) ADC_MAX) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
float R_ntc = R1 * (float) adc_value / (ADC_MAX - (float) adc_value);
|
float R_ntc = r1 * (float) adc_value / (ADC_MAX - (float) adc_value);
|
||||||
return R_ntc;
|
return R_ntc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Бинарный поиск в таблице
|
// Бинарный поиск в таблице
|
||||||
static int find_interval_index(float resistance) {
|
static int find_interval_index(float resistance, const ntc_table_entry* table, uint16_t table_size) {
|
||||||
int left = 0;
|
int left = 0;
|
||||||
int right = TABLE_SIZE - 1;
|
int right = table_size - 1;
|
||||||
|
|
||||||
// Проверка границ
|
// Проверка границ
|
||||||
if (resistance >= ntc_table[0].r_nom) return 0;
|
if (resistance >= table[0].r_nom) return 0;
|
||||||
if (resistance <= ntc_table[right].r_nom) return right - 1;
|
if (resistance <= table[right].r_nom) return right - 1;
|
||||||
|
|
||||||
// Бинарный поиск
|
// Бинарный поиск
|
||||||
while (left <= right) {
|
while (left <= right) {
|
||||||
int mid = left + (right - left) / 2;
|
int mid = left + (right - left) / 2;
|
||||||
|
|
||||||
if (mid < TABLE_SIZE - 1 &&
|
if (mid < table_size - 1 &&
|
||||||
resistance <= ntc_table[mid].r_nom &&
|
resistance <= table[mid].r_nom &&
|
||||||
resistance >= ntc_table[mid + 1].r_nom) {
|
resistance >= table[mid + 1].r_nom) {
|
||||||
return mid;
|
return mid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resistance > ntc_table[mid].r_nom) {
|
if (resistance > table[mid].r_nom) {
|
||||||
right = mid - 1;
|
right = mid - 1;
|
||||||
} else {
|
} else {
|
||||||
left = mid + 1;
|
left = mid + 1;
|
||||||
|
|
@ -127,12 +162,12 @@ static int find_interval_index(float resistance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Интерполяция с использованием уравнения Стейнхарта-Харта между точками
|
// Интерполяция с использованием уравнения Стейнхарта-Харта между точками
|
||||||
static float interpolate_steinhart(float resistance, int index) {
|
static float interpolate_steinhart(float resistance, int index, const ntc_table_entry* table) {
|
||||||
// Берем две соседние точки из таблицы
|
// Берем две соседние точки из таблицы
|
||||||
float t1 = (float) ntc_table[index].temp_c + 273.15f; // в Кельвинах
|
float t1 = (float) table[index].temp_c + 273.15f; // в Кельвинах
|
||||||
float t2 = (float) ntc_table[index + 1].temp_c + 273.15f;
|
float t2 = (float) table[index + 1].temp_c + 273.15f;
|
||||||
float r1 = ntc_table[index].r_nom;
|
float r1 = table[index].r_nom;
|
||||||
float r2 = ntc_table[index + 1].r_nom;
|
float r2 = table[index + 1].r_nom;
|
||||||
|
|
||||||
// Вычисляем коэффициент B для интервала
|
// Вычисляем коэффициент B для интервала
|
||||||
float B = logf(r1 / r2) / (1.0f / t1 - 1.0f / t2);
|
float B = logf(r1 / r2) / (1.0f / t1 - 1.0f / t2);
|
||||||
|
|
@ -145,11 +180,11 @@ static float interpolate_steinhart(float resistance, int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Линейная интерполяция в логарифмическом масштабе
|
// Линейная интерполяция в логарифмическом масштабе
|
||||||
static float interpolate_log_linear(float resistance, int index) {
|
static float interpolate_log_linear(float resistance, int index, const ntc_table_entry* table) {
|
||||||
float t1 = (float) ntc_table[index].temp_c;
|
float t1 = (float) table[index].temp_c;
|
||||||
float t2 = (float) ntc_table[index + 1].temp_c;
|
float t2 = (float) table[index + 1].temp_c;
|
||||||
float r1 = ntc_table[index].r_nom;
|
float r1 = table[index].r_nom;
|
||||||
float r2 = ntc_table[index + 1].r_nom;
|
float r2 = table[index + 1].r_nom;
|
||||||
|
|
||||||
float log_r1 = logf(r1);
|
float log_r1 = logf(r1);
|
||||||
float log_r2 = logf(r2);
|
float log_r2 = logf(r2);
|
||||||
|
|
@ -159,7 +194,7 @@ static float interpolate_log_linear(float resistance, int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Более надежная версия с проверкой параметров
|
// Более надежная версия с проверкой параметров
|
||||||
static float interpolate_steinhart_full(float resistance, int index) {
|
static float interpolate_steinhart_full(float resistance, int index, const ntc_table_entry* table) {
|
||||||
// Проверка корректности входных данных
|
// Проверка корректности входных данных
|
||||||
if (resistance <= 0.0f) {
|
if (resistance <= 0.0f) {
|
||||||
return -273.15f; // Абсолютный ноль при некорректном сопротивлении
|
return -273.15f; // Абсолютный ноль при некорректном сопротивлении
|
||||||
|
|
@ -177,7 +212,7 @@ static float interpolate_steinhart_full(float resistance, int index) {
|
||||||
// Проверка на физическую реализуемость (температура должна быть положительной в Кельвинах)
|
// Проверка на физическую реализуемость (температура должна быть положительной в Кельвинах)
|
||||||
if (inv_T <= 0.0f || inv_T > 1.0f) { // 1/T не может быть <= 0 (T < 0K) или слишком большим
|
if (inv_T <= 0.0f || inv_T > 1.0f) { // 1/T не может быть <= 0 (T < 0K) или слишком большим
|
||||||
// В случае ошибки возвращаем температуру из таблицы по индексу
|
// В случае ошибки возвращаем температуру из таблицы по индексу
|
||||||
return (float) ntc_table[index].temp_c;
|
return (float) table[index].temp_c;
|
||||||
}
|
}
|
||||||
|
|
||||||
double temp_K = 1.0f / inv_T;
|
double temp_K = 1.0f / inv_T;
|
||||||
|
|
@ -185,67 +220,84 @@ static float interpolate_steinhart_full(float resistance, int index) {
|
||||||
// Дополнительная проверка диапазона (например, для NTC обычно -50...+150°C)
|
// Дополнительная проверка диапазона (например, для NTC обычно -50...+150°C)
|
||||||
if (temp_K < 223.15f || temp_K > 423.15f) { // -50°C...150°C в Кельвинах
|
if (temp_K < 223.15f || temp_K > 423.15f) { // -50°C...150°C в Кельвинах
|
||||||
// Возвращаем значение из таблицы как запасной вариант
|
// Возвращаем значение из таблицы как запасной вариант
|
||||||
return (float) ntc_table[index].temp_c;
|
return (float) table[index].temp_c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (float) (temp_K - 273.15f);
|
return (float) (temp_K - 273.15f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Основная функция для получения температуры
|
// Основная функция для получения температуры с указанием таблицы и R1
|
||||||
float get_temperature_from_adc(uint16_t adc_value, eAlg use_alg) {
|
float get_temperature_from_adc_with_table(uint16_t adc_value, eAlg alg, eNtcTable table_type, float r1) {
|
||||||
float resistance = calculate_resistance(adc_value);
|
float resistance = calculate_resistance(adc_value, r1);
|
||||||
|
|
||||||
if (resistance <= 0.0f) {
|
if (resistance <= 0.0f) {
|
||||||
return -273.15f; // Ошибка
|
return -273.15f; // Ошибка
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = find_interval_index(resistance);
|
uint16_t table_size;
|
||||||
|
int16_t start_temp, end_temp;
|
||||||
|
const ntc_table_entry* table = get_table_by_type(table_type, &table_size, &start_temp, &end_temp);
|
||||||
|
|
||||||
if (index < 0 || index >= TABLE_SIZE - 1) {
|
int index = find_interval_index(resistance, table, table_size);
|
||||||
|
|
||||||
|
if (index < 0 || index >= table_size - 1) {
|
||||||
// Вне диапазона таблицы
|
// Вне диапазона таблицы
|
||||||
if (resistance >= ntc_table[0].r_nom) return TABLE_START_TEMP;
|
if (resistance >= table[0].r_nom) return (float) start_temp;
|
||||||
if (resistance <= ntc_table[TABLE_SIZE - 1].r_nom) return TABLE_END_TEMP;
|
if (resistance <= table[table_size - 1].r_nom) return (float) end_temp;
|
||||||
return -273.15f; // Ошибка
|
return -273.15f; // Ошибка
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_alg == ALG_STEINHART) {
|
if (alg == ALG_STEINHART) {
|
||||||
return interpolate_steinhart(resistance, index);
|
return interpolate_steinhart(resistance, index, table);
|
||||||
} else if (use_alg == ALG_STEINHART_FULL) {
|
} else if (alg == ALG_STEINHART_FULL) {
|
||||||
return interpolate_steinhart_full(resistance, index);
|
return interpolate_steinhart_full(resistance, index, table);
|
||||||
} else {
|
} else {
|
||||||
return interpolate_log_linear(resistance, index);
|
return interpolate_log_linear(resistance, index, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция для получения сопротивления из значения АЦП
|
// Функция для получения температуры с активной конфигурацией
|
||||||
float get_resistance_from_adc(uint16_t adc_value) {
|
float get_temperature_from_adc(uint16_t adc_value, eAlg alg) {
|
||||||
return calculate_resistance(adc_value);
|
return get_temperature_from_adc_with_table(adc_value, alg, active_config.table_type, active_config.r1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_fast_lookup_table(eAlg use_alg) {
|
// Функция для получения сопротивления из значения АЦП с указанием таблицы
|
||||||
// Сначала найдем рабочий диапазон АЦП, который дает температуры в пределах таблицы
|
float get_resistance_from_adc_with_table(uint16_t adc_value, eNtcTable table_type, float r1) {
|
||||||
|
return calculate_resistance(adc_value, r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для получения сопротивления с активной конфигурацией
|
||||||
|
float get_resistance_from_adc(uint16_t adc_value) {
|
||||||
|
return calculate_resistance(adc_value, active_config.r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация таблицы быстрого поиска
|
||||||
|
void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg) {
|
||||||
|
uint16_t table_size;
|
||||||
|
int16_t start_temp, end_temp;
|
||||||
|
const ntc_table_entry* table = get_table_by_type(table_type, &table_size, &start_temp, &end_temp);
|
||||||
|
|
||||||
|
// Находим рабочий диапазон АЦП
|
||||||
uint16_t min_valid_adc = 0;
|
uint16_t min_valid_adc = 0;
|
||||||
uint16_t max_valid_adc = 0;
|
uint16_t max_valid_adc = 0;
|
||||||
float min_temp = TABLE_START_TEMP;
|
|
||||||
float max_temp = TABLE_END_TEMP;
|
|
||||||
|
|
||||||
// Ищем минимальное АЦП, при котором температура >= TABLE_START_TEMP
|
// Ищем минимальное АЦП, при котором температура >= start_temp
|
||||||
for (uint16_t adc = 1; adc < ADC_MAX; adc++) {
|
for (uint16_t adc = 1; adc < ADC_MAX; adc++) {
|
||||||
float resistance = calculate_resistance(adc);
|
float resistance = calculate_resistance(adc, r1);
|
||||||
float temp = get_temperature_from_adc(adc, ALG_STEINHART);
|
float temp = get_temperature_from_adc_with_table(adc, ALG_STEINHART, table_type, r1);
|
||||||
|
|
||||||
if (temp >= TABLE_START_TEMP && temp <= TABLE_END_TEMP) {
|
if (temp >= start_temp && temp <= end_temp) {
|
||||||
min_valid_adc = adc;
|
min_valid_adc = adc;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ищем максимальное АЦП, при котором температура <= TABLE_END_TEMP
|
// Ищем максимальное АЦП, при котором температура <= end_temp
|
||||||
for (uint16_t adc = (uint16_t)(ADC_MAX - 1); adc > 0; adc--) {
|
for (uint16_t adc = (uint16_t)(ADC_MAX - 1); adc > 0; adc--) {
|
||||||
float resistance = calculate_resistance(adc);
|
float resistance = calculate_resistance(adc, r1);
|
||||||
float temp = get_temperature_from_adc(adc, ALG_STEINHART);
|
float temp = get_temperature_from_adc_with_table(adc, ALG_STEINHART, table_type, r1);
|
||||||
|
|
||||||
if (temp >= TABLE_START_TEMP && temp <= TABLE_END_TEMP) {
|
if (temp >= start_temp && temp <= end_temp) {
|
||||||
max_valid_adc = adc;
|
max_valid_adc = adc;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -255,32 +307,52 @@ void init_fast_lookup_table(eAlg use_alg) {
|
||||||
if (min_valid_adc == 0) min_valid_adc = 1;
|
if (min_valid_adc == 0) min_valid_adc = 1;
|
||||||
if (max_valid_adc == 0) max_valid_adc = (uint16_t)(ADC_MAX - 1);
|
if (max_valid_adc == 0) max_valid_adc = (uint16_t)(ADC_MAX - 1);
|
||||||
|
|
||||||
printf("Диапазон АЦП: %u - %u\n", min_valid_adc, max_valid_adc);
|
// Заполняем таблицу
|
||||||
|
|
||||||
// Заполняем таблицу, равномерно распределяя АЦП в рабочем диапазоне
|
|
||||||
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP; i++) {
|
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP; i++) {
|
||||||
// Линейная интерполяция АЦП в рабочем диапазоне
|
|
||||||
float ratio = (float)i / (TABLE_SIZE_LOOKUP - 1);
|
float ratio = (float)i / (TABLE_SIZE_LOOKUP - 1);
|
||||||
uint16_t adc = min_valid_adc + (uint16_t)(ratio * (max_valid_adc - min_valid_adc));
|
uint16_t adc = min_valid_adc + (uint16_t)(ratio * (max_valid_adc - min_valid_adc));
|
||||||
|
|
||||||
float resistance = calculate_resistance(adc);
|
float resistance = calculate_resistance(adc, r1);
|
||||||
float temp = get_temperature_from_adc(adc, use_alg);
|
float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1);
|
||||||
|
|
||||||
// Ограничиваем температуру пределами таблицы
|
// Ограничиваем температуру пределами таблицы
|
||||||
if (temp < TABLE_START_TEMP) temp = TABLE_START_TEMP;
|
if (temp < start_temp) temp = (float)start_temp;
|
||||||
if (temp > TABLE_END_TEMP) temp = TABLE_END_TEMP;
|
if (temp > end_temp) temp = (float)end_temp;
|
||||||
|
|
||||||
fast_lookup[i].adc_value = adc;
|
fast_lookup[i].adc_value = adc;
|
||||||
fast_lookup[i].temp_c = (int16_t)(temp * 10.0f);
|
fast_lookup[i].temp_c = (int16_t)(temp * 10.0f);
|
||||||
fast_lookup[i].resistance_ohm = resistance;
|
fast_lookup[i].resistance_ohm = resistance;
|
||||||
|
fast_lookup[i].table_type = table_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Обновляем активную конфигурацию
|
||||||
|
set_active_config(table_type, r1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Установка активной конфигурации
|
||||||
|
void set_active_config(eNtcTable table_type, float r1) {
|
||||||
|
active_config.table_type = table_type;
|
||||||
|
active_config.r1 = r1;
|
||||||
|
|
||||||
|
uint16_t table_size;
|
||||||
|
get_table_by_type(table_type, &table_size, &active_config.start_temp, &active_config.end_temp);
|
||||||
|
active_config.table_size = table_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение активной конфигурации
|
||||||
|
const ntc_config_t* get_active_config(void) {
|
||||||
|
return &active_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Быстрые функции с использованием предварительно вычисленной таблицы
|
||||||
int16_t get_temperature_log_fast(uint16_t adc_value) {
|
int16_t get_temperature_log_fast(uint16_t adc_value) {
|
||||||
// Защита от выхода за границы
|
// Защита от выхода за границы
|
||||||
if (adc_value >= fast_lookup[TABLE_SIZE_LOOKUP - 1].adc_value) {
|
if (adc_value >= fast_lookup[TABLE_SIZE_LOOKUP - 1].adc_value) {
|
||||||
return fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c;
|
return fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c;
|
||||||
}
|
}
|
||||||
|
if (adc_value <= fast_lookup[0].adc_value) {
|
||||||
|
return fast_lookup[0].temp_c;
|
||||||
|
}
|
||||||
|
|
||||||
// Бинарный поиск интервала
|
// Бинарный поиск интервала
|
||||||
int left = 0;
|
int left = 0;
|
||||||
|
|
@ -302,7 +374,6 @@ int16_t get_temperature_log_fast(uint16_t adc_value) {
|
||||||
int16_t temp1 = fast_lookup[mid].temp_c;
|
int16_t temp1 = fast_lookup[mid].temp_c;
|
||||||
int16_t temp2 = fast_lookup[mid + 1].temp_c;
|
int16_t temp2 = fast_lookup[mid + 1].temp_c;
|
||||||
|
|
||||||
// Избегаем деления на ноль
|
|
||||||
if (adc2 == adc1) {
|
if (adc2 == adc1) {
|
||||||
return temp1;
|
return temp1;
|
||||||
}
|
}
|
||||||
|
|
@ -317,10 +388,9 @@ int16_t get_temperature_log_fast(uint16_t adc_value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fast_lookup[0].temp_c; // Если не нашли, возвращаем первое значение
|
return fast_lookup[0].temp_c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Альтернативная простая версия
|
// Альтернативная простая версия
|
||||||
int16_t get_temperature_linear_fast(uint16_t adc_value) {
|
int16_t get_temperature_linear_fast(uint16_t adc_value) {
|
||||||
// Находим интервал
|
// Находим интервал
|
||||||
|
|
@ -346,18 +416,13 @@ int16_t get_temperature_linear_fast(uint16_t adc_value) {
|
||||||
return temp1 + ((int32_t) (temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
|
return temp1 + ((int32_t) (temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Функция для получения сопротивления из температуры (обратное преобразование)
|
|
||||||
// Функция для получения сопротивления из температуры (обратное преобразование)
|
// Функция для получения сопротивления из температуры (обратное преобразование)
|
||||||
float get_resistance_log_fast(int16_t temperature_c10) {
|
float get_resistance_log_fast(int16_t temperature_c10) {
|
||||||
// temperature_c10 - температура в °C * 10 (например, 250 = 25.0°C)
|
|
||||||
// Таблица отсортирована по убыванию температуры (от max к min)
|
|
||||||
|
|
||||||
// Защита от выхода за границы
|
// Защита от выхода за границы
|
||||||
if (temperature_c10 >= fast_lookup[0].temp_c) { // >= максимальной температуры
|
if (temperature_c10 >= fast_lookup[0].temp_c) {
|
||||||
return fast_lookup[0].resistance_ohm;
|
return fast_lookup[0].resistance_ohm;
|
||||||
}
|
}
|
||||||
if (temperature_c10 <= fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c) { // <= минимальной температуры
|
if (temperature_c10 <= fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c) {
|
||||||
return fast_lookup[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
|
return fast_lookup[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,19 +433,14 @@ float get_resistance_log_fast(int16_t temperature_c10) {
|
||||||
while (left <= right) {
|
while (left <= right) {
|
||||||
int mid = left + (right - left) / 2;
|
int mid = left + (right - left) / 2;
|
||||||
|
|
||||||
// Таблица отсортирована по убыванию температуры
|
|
||||||
if (temperature_c10 <= fast_lookup[mid].temp_c &&
|
if (temperature_c10 <= fast_lookup[mid].temp_c &&
|
||||||
temperature_c10 >= fast_lookup[mid + 1].temp_c) {
|
temperature_c10 >= fast_lookup[mid + 1].temp_c) {
|
||||||
// Нашли интервал
|
// Нашли интервал
|
||||||
// mid - точка с большей температурой
|
int16_t temp_high = fast_lookup[mid].temp_c;
|
||||||
// mid+1 - точка с меньшей температурой
|
int16_t temp_low = fast_lookup[mid + 1].temp_c;
|
||||||
|
float res_high = fast_lookup[mid].resistance_ohm;
|
||||||
|
float res_low = fast_lookup[mid + 1].resistance_ohm;
|
||||||
|
|
||||||
int16_t temp_high = fast_lookup[mid].temp_c; // большая температура
|
|
||||||
int16_t temp_low = fast_lookup[mid + 1].temp_c; // меньшая температура
|
|
||||||
float res_high = fast_lookup[mid].resistance_ohm; // сопротивление при большей температуре
|
|
||||||
float res_low = fast_lookup[mid + 1].resistance_ohm; // сопротивление при меньшей температуре
|
|
||||||
|
|
||||||
// Избегаем деления на ноль
|
|
||||||
if (temp_high == temp_low) {
|
if (temp_high == temp_low) {
|
||||||
return res_high;
|
return res_high;
|
||||||
}
|
}
|
||||||
|
|
@ -395,9 +455,9 @@ float get_resistance_log_fast(int16_t temperature_c10) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temperature_c10 > fast_lookup[mid].temp_c) {
|
if (temperature_c10 > fast_lookup[mid].temp_c) {
|
||||||
right = mid - 1; // ищем в сторону больших температур
|
right = mid - 1;
|
||||||
} else {
|
} else {
|
||||||
left = mid + 1; // ищем в сторону меньших температур
|
left = mid + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,4 +499,5 @@ float get_resistance_fast_simple(int16_t temperature_c10) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return fast_lookup[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
|
return fast_lookup[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue