This commit is contained in:
cfif 2026-04-01 13:14:08 +03:00
parent 6c359a9c7a
commit 29202b55f4
2 changed files with 185 additions and 66 deletions

View File

@ -1,6 +1,95 @@
#include <stdio.h> #include <stdio.h>
#include "ADC_Temp.h" #include "ADC_Temp.h"
// Функция для сохранения таблицы в файл
void save_table_to_file(const char* filename, const adc_temp_lookup* table, const char* table_name) {
FILE* file = fopen(filename, "w");
if (file == NULL) {
printf("Ошибка: не удалось создать файл %s\n", filename);
return;
}
fprintf(file, "=== Таблица быстрого поиска: %s ===\n", table_name);
fprintf(file, "Всего записей: %d\n", TABLE_SIZE_LOOKUP);
fprintf(file, "%-8s %-12s %-15s\n", "ADC", "Temp (°C)", "Resistance (Ω)");
fprintf(file, "----------------------------------------\n");
for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) {
fprintf(file, "%-8u %-12.1f %-15.2f\n",
table[i].adc_value,
table[i].temp_c / 10.0f,
table[i].resistance_ohm);
}
fclose(file);
printf("Таблица '%s' сохранена в файл: %s\n", table_name, filename);
}
// Функция для сохранения таблицы в CSV формате
void save_table_to_csv(const char* filename, const adc_temp_lookup* table, const char* table_name) {
FILE* file = fopen(filename, "w");
if (file == NULL) {
printf("Ошибка: не удалось создать файл %s\n", filename);
return;
}
fprintf(file, "# Таблица быстрого поиска: %s\n", table_name);
fprintf(file, "ADC,Temperature_C,Resistance_Ohm\n");
for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) {
fprintf(file, "%u,%.1f,%.2f\n",
table[i].adc_value,
table[i].temp_c / 10.0f,
table[i].resistance_ohm);
}
fclose(file);
printf("Таблица '%s' сохранена в CSV файл: %s\n", table_name, filename);
}
// Функция для сохранения обеих таблиц
void save_both_tables(void) {
const fast_lookup_tables_t* tables = get_fast_tables();
// Сохраняем в текстовом формате
save_table_to_file("kst45_table.txt", tables->kst45, "KST45");
save_table_to_file("incar_table.txt", tables->incar, "INCAR");
// Сохраняем в CSV формате (удобно для Excel)
save_table_to_csv("kst45_table.csv", tables->kst45, "KST45");
save_table_to_csv("incar_table.csv", tables->incar, "INCAR");
}
// Функция для сохранения только рабочего диапазона (без зон насыщения)
void save_working_range_to_file(const char* filename, const adc_temp_lookup* table,
const char* table_name, uint16_t min_adc, uint16_t max_adc) {
FILE* file = fopen(filename, "w");
if (file == NULL) {
printf("Ошибка: не удалось создать файл %s\n", filename);
return;
}
fprintf(file, "=== Рабочий диапазон таблицы: %s ===\n", table_name);
fprintf(file, "Диапазон ADC: %u - %u\n", min_adc, max_adc);
fprintf(file, "%-8s %-12s %-15s\n", "ADC", "Temp (°C)", "Resistance (Ω)");
fprintf(file, "----------------------------------------\n");
int count = 0;
for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) {
if (table[i].adc_value >= min_adc && table[i].adc_value <= max_adc) {
fprintf(file, "%-8u %-12.1f %-15.2f\n",
table[i].adc_value,
table[i].temp_c / 10.0f,
table[i].resistance_ohm);
count++;
}
}
fprintf(file, "\nВсего записей в рабочем диапазоне: %d\n", count);
fclose(file);
printf("Рабочий диапазон таблицы '%s' сохранен в файл: %s\n", table_name, filename);
}
int main() { int main() {
// Инициализируем обе таблицы одновременно с разными значениями R1 // Инициализируем обе таблицы одновременно с разными значениями R1
init_both_tables(3300.0f, // R1 для KST45 init_both_tables(3300.0f, // R1 для KST45
@ -34,39 +123,46 @@ int main() {
const fast_lookup_tables_t* tables = get_fast_tables(); const fast_lookup_tables_t* tables = get_fast_tables();
printf("\n=== Пример данных из таблиц быстрого поиска ===\n"); printf("\n=== Пример данных из таблиц быстрого поиска ===\n");
printf("KST45 таблица (первые 3 записи):\n"); printf("KST45 таблица (первые 15 записи):\n");
for(int i = 0; i < 3; i++) { for(int i = 0; i < 15; i++) {
printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n",
tables->kst45[i].adc_value, tables->kst45[i].adc_value,
tables->kst45[i].temp_c / 10.0f, tables->kst45[i].temp_c / 10.0f,
tables->kst45[i].resistance_ohm); tables->kst45[i].resistance_ohm);
} }
printf("\nINCAR таблица (первые 3 записи):\n"); printf("\nINCAR таблица (первые 15 записи):\n");
for(int i = 0; i < 3; i++) { for(int i = 0; i < 15; i++) {
printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n",
tables->incar[i].adc_value, tables->incar[i].adc_value,
tables->incar[i].temp_c / 10.0f, tables->incar[i].temp_c / 10.0f,
tables->incar[i].resistance_ohm); tables->incar[i].resistance_ohm);
} }
printf("\nKST45 таблица (последние 15 записи):\n");
printf("\nKST45 таблица (последние 3 записи):\n"); for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 16; i--) {
for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 4; i--) {
printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n",
tables->kst45[i].adc_value, tables->kst45[i].adc_value,
tables->kst45[i].temp_c / 10.0f, tables->kst45[i].temp_c / 10.0f,
tables->kst45[i].resistance_ohm); tables->kst45[i].resistance_ohm);
} }
printf("\nINCAR таблица (последние 3 записи):\n"); printf("\nINCAR таблица (последние 15 записи):\n");
for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 4; i--) { for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 16; i--) {
printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n",
tables->incar[i].adc_value, tables->incar[i].adc_value,
tables->incar[i].temp_c / 10.0f, tables->incar[i].temp_c / 10.0f,
tables->incar[i].resistance_ohm); tables->incar[i].resistance_ohm);
} }
// Сохраняем таблицы в файлы
printf("\n=== Сохранение таблиц в файлы ===\n");
save_both_tables();
// Сохраняем только рабочие диапазоны (без зон насыщения)
// Для KST45 рабочий диапазон примерно от 58 до 3418
save_working_range_to_file("kst45_working_range.txt", tables->kst45, "KST45", 58, 3418);
save_working_range_to_file("incar_working_range.txt", tables->incar, "INCAR", 58, 3418);
// Пример обратного преобразования (температура -> сопротивление) // Пример обратного преобразования (температура -> сопротивление)
printf("\n=== Обратное преобразование ===\n"); printf("\n=== Обратное преобразование ===\n");

View File

@ -319,48 +319,91 @@ void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg) {
uint16_t min_valid_adc = 0; uint16_t min_valid_adc = 0;
uint16_t max_valid_adc = 0; uint16_t max_valid_adc = 0;
// Ищем минимальное АЦП, при котором температура >= start_temp // Значения для граничных точек
float temp_at_min_adc = 0.0f;
float temp_at_max_adc = 0.0f;
float res_at_min_adc = 0.0f;
float res_at_max_adc = 0.0f;
// Ищем минимальное АЦП, при котором температура >= 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, r1); float resistance = calculate_resistance(adc, r1);
float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1); float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1);
if (temp >= start_temp && temp <= end_temp) { if (temp >= start_temp && temp <= end_temp) {
min_valid_adc = adc; min_valid_adc = adc;
temp_at_min_adc = temp;
res_at_min_adc = resistance;
break; break;
} }
} }
// Ищем максимальное АЦП, при котором температура <= 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, r1); float resistance = calculate_resistance(adc, r1);
float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1); float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1);
if (temp >= start_temp && temp <= end_temp) { if (temp >= start_temp && temp <= end_temp) {
max_valid_adc = adc; max_valid_adc = adc;
temp_at_max_adc = temp;
res_at_max_adc = resistance;
break; break;
} }
} }
// Если не нашли корректные значения, используем весь диапазон // Заполняем таблицу для всего диапазона ADC от 0 до 4095
if (min_valid_adc == 0) min_valid_adc = 1; uint32_t adc_step = ((uint32_t)(ADC_MAX - 1) * 1000) / (TABLE_SIZE_LOOKUP - 1);
if (max_valid_adc == 0) max_valid_adc = (uint16_t)(ADC_MAX - 1); uint32_t current_adc = 0;
uint16_t prev_adc = 0;
// Заполняем таблицу
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); uint16_t adc;
uint16_t adc = min_valid_adc + (uint16_t)(ratio * (max_valid_adc - min_valid_adc));
float resistance = calculate_resistance(adc, r1); if (i == 0) {
float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1); adc = 0;
current_adc = 0;
prev_adc = 0;
} else if (i == TABLE_SIZE_LOOKUP - 1) {
adc = (uint16_t)(ADC_MAX - 1);
} else {
current_adc += adc_step;
adc = (uint16_t)(current_adc / 1000);
// Ограничиваем температуру пределами таблицы // Убеждаемся, что значения монотонно возрастают и нет дубликатов
if (temp < start_temp) temp = (float)start_temp; if (adc <= prev_adc) {
if (temp > end_temp) temp = (float)end_temp; adc = prev_adc + 1;
}
// Убеждаемся, что не выходим за пределы
if (adc >= (uint16_t)(ADC_MAX - 1)) {
adc = (uint16_t)(ADC_MAX - 2);
}
}
float resistance;
float temp;
// Определяем, находится ли ADC в рабочем диапазоне
if (adc <= min_valid_adc) {
// Зона низких ADC (высокая температура) - используем граничное значение
resistance = res_at_min_adc;
temp = temp_at_min_adc;
} else if (adc >= max_valid_adc) {
// Зона высоких ADC (низкая температура) - используем граничное значение
resistance = res_at_max_adc;
temp = temp_at_max_adc;
} else {
// В рабочем диапазоне - вычисляем нормально
resistance = calculate_resistance(adc, r1);
temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1);
}
fast_table[i].adc_value = adc; fast_table[i].adc_value = adc;
fast_table[i].temp_c = (int16_t)(temp * 10.0f); fast_table[i].temp_c = (int16_t)(temp * 10.0f);
fast_table[i].resistance_ohm = resistance; fast_table[i].resistance_ohm = resistance;
fast_table[i].table_type = table_type; fast_table[i].table_type = table_type;
prev_adc = adc;
} }
// Устанавливаем флаг инициализации // Устанавливаем флаг инициализации
@ -397,11 +440,6 @@ const fast_lookup_tables_t* get_fast_tables(void) {
return &g_fast_tables; return &g_fast_tables;
} }
// Быстрые функции с использованием активной таблицы
int16_t get_temperature_log_fast(uint16_t adc_value) {
return get_temperature_log_fast_for_table(adc_value, active_config.table_type);
}
// Быстрая функция для конкретной таблицы // Быстрая функция для конкретной таблицы
int16_t get_temperature_log_fast_for_table(uint16_t adc_value, eNtcTable table_type) { int16_t get_temperature_log_fast_for_table(uint16_t adc_value, eNtcTable table_type) {
if (!is_table_initialized(table_type)) { if (!is_table_initialized(table_type)) {
@ -413,49 +451,34 @@ int16_t get_temperature_log_fast_for_table(uint16_t adc_value, eNtcTable table_t
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type); adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
// Защита от выхода за границы // Простой линейный поиск (так как таблица небольшая - 4096 элементов)
if (adc_value >= fast_table[TABLE_SIZE_LOOKUP - 1].adc_value) { for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP - 1; i++) {
return fast_table[TABLE_SIZE_LOOKUP - 1].temp_c; if (adc_value >= fast_table[i].adc_value && adc_value <= fast_table[i + 1].adc_value) {
}
if (adc_value <= fast_table[0].adc_value) {
return fast_table[0].temp_c;
}
// Бинарный поиск интервала
int left = 0;
int right = TABLE_SIZE_LOOKUP - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (fast_table[mid].adc_value <= adc_value &&
(mid == TABLE_SIZE_LOOKUP - 1 || adc_value < fast_table[mid + 1].adc_value)) {
// Нашли интервал
if (mid == TABLE_SIZE_LOOKUP - 1) {
return fast_table[mid].temp_c;
}
// Линейная интерполяция // Линейная интерполяция
uint16_t adc1 = fast_table[mid].adc_value; uint16_t adc1 = fast_table[i].adc_value;
uint16_t adc2 = fast_table[mid + 1].adc_value; uint16_t adc2 = fast_table[i + 1].adc_value;
int16_t temp1 = fast_table[mid].temp_c; int16_t temp1 = fast_table[i].temp_c;
int16_t temp2 = fast_table[mid + 1].temp_c; int16_t temp2 = fast_table[i + 1].temp_c;
if (adc2 == adc1) { if (adc2 == adc1) {
return temp1; return temp1;
} }
return temp1 + ((int32_t) (temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1); return temp1 + ((int32_t)(temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
}
if (adc_value < fast_table[mid].adc_value) {
right = mid - 1;
} else {
left = mid + 1;
} }
} }
return fast_table[0].temp_c; // Если не нашли, возвращаем ближайшее значение
if (adc_value <= fast_table[0].adc_value) {
return fast_table[0].temp_c;
} else {
return fast_table[TABLE_SIZE_LOOKUP - 1].temp_c;
}
}
// Быстрые функции с использованием активной таблицы
int16_t get_temperature_log_fast(uint16_t adc_value) {
return get_temperature_log_fast_for_table(adc_value, active_config.table_type);
} }
// Альтернативная простая версия // Альтернативная простая версия
@ -463,11 +486,6 @@ int16_t get_temperature_linear_fast(uint16_t adc_value) {
return get_temperature_log_fast_for_table(adc_value, active_config.table_type); return get_temperature_log_fast_for_table(adc_value, active_config.table_type);
} }
// Функция для получения сопротивления из температуры (обратное преобразование)
float get_resistance_log_fast(int16_t temperature_c10) {
return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type);
}
// Функция для получения сопротивления из температуры для конкретной таблицы // Функция для получения сопротивления из температуры для конкретной таблицы
float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table_type) { float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table_type) {
if (!is_table_initialized(table_type)) { if (!is_table_initialized(table_type)) {
@ -522,6 +540,11 @@ float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table
return fast_table[TABLE_SIZE_LOOKUP - 1].resistance_ohm; return fast_table[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
} }
// Функция для получения сопротивления из температуры (обратное преобразование)
float get_resistance_log_fast(int16_t temperature_c10) {
return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type);
}
// Упрощенная версия с линейным поиском // Упрощенная версия с линейным поиском
float get_resistance_fast_simple(int16_t temperature_c10) { float get_resistance_fast_simple(int16_t temperature_c10) {
return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type); return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type);