#include #include "ADC_Temp.h" // Упрощенная структура для хранения записи таблицы typedef struct { uint16_t adc_value; // Значение АЦП int16_t temp_c; // Температура в °C * 10 float resistance_ohm; // Сопротивление в Ом } adc_temp_lookup_entry_t; // Функция для сохранения таблицы в C файл в виде статического массива void save_table_to_c_file(const char* filename, const adc_temp_lookup* table, const char* table_name, const char* array_name) { FILE* file = fopen(filename, "w"); if (file == NULL) { printf("Ошибка: не удалось создать файл %s\n", filename); return; } // Заголовок файла fprintf(file, "//\n"); fprintf(file, "// Автоматически сгенерированный файл таблицы быстрого поиска: %s\n", table_name); fprintf(file, "// VCC делителя = %.2f V\n", VCC_DIVIDER_MV / 1000.0f); fprintf(file, "// VREF АЦП = %.2f V\n", VREF_MV / 1000.0f); fprintf(file, "// Сопротивление R1 = %.0f Ом\n", (table_name[0] == 'D' && table_name[1] == 'U') ? g_fast_tables.duct_r1 : (table_name[0] == 'I') ? g_fast_tables.incar_r1 : g_fast_tables.ambient_r1); fprintf(file, "// Всего записей: %d\n", TABLE_SIZE_LOOKUP); fprintf(file, "//\n\n"); fprintf(file, "#include \n\n"); // Структура для элемента таблицы fprintf(file, "// Структура для хранения записи таблицы\n"); fprintf(file, "typedef struct {\n"); fprintf(file, " uint16_t adc_value; // Значение АЦП\n"); fprintf(file, " int16_t temp_c; // Температура в °C * 10\n"); fprintf(file, " float resistance_ohm; // Сопротивление в Ом\n"); fprintf(file, "} adc_temp_lookup_entry_t;\n\n"); // Объявление массива fprintf(file, "static const adc_temp_lookup_entry_t %s[%d] = {\n", array_name, TABLE_SIZE_LOOKUP); // Вывод данных - по 4 элемента в строке для компактности for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) { if (i % 4 == 0) { fprintf(file, " "); } // Округляем сопротивление до 2 знаков после запятой fprintf(file, "{%u, %d, %.2ff}", table[i].adc_value, table[i].temp_c, table[i].resistance_ohm); if (i < TABLE_SIZE_LOOKUP - 1) { fprintf(file, ", "); } if ((i + 1) % 4 == 0) { fprintf(file, "\n"); } } // Завершаем массив if (TABLE_SIZE_LOOKUP % 4 != 0) { fprintf(file, "\n"); } fprintf(file, "};\n\n"); // Добавляем функцию для быстрого доступа по ADC fprintf(file, "// Быстрый поиск температуры по ADC (прямая индексация)\n"); fprintf(file, "static inline int16_t %s_get_temp(uint16_t adc_value) {\n", array_name); fprintf(file, " if (adc_value >= %d) return %s[%d].temp_c;\n", TABLE_SIZE_LOOKUP, array_name, TABLE_SIZE_LOOKUP - 1); fprintf(file, " return %s[adc_value].temp_c;\n", array_name); fprintf(file, "}\n\n"); fprintf(file, "// Быстрый поиск сопротивления по ADC (прямая индексация)\n"); fprintf(file, "static inline float %s_get_resistance(uint16_t adc_value) {\n", array_name); fprintf(file, " if (adc_value >= %d) return %s[%d].resistance_ohm;\n", TABLE_SIZE_LOOKUP, array_name, TABLE_SIZE_LOOKUP - 1); fprintf(file, " return %s[adc_value].resistance_ohm;\n", array_name); fprintf(file, "}\n\n"); // Добавляем функцию для обратного поиска (температура -> сопротивление) fprintf(file, "// Поиск сопротивления по температуре (бинарный поиск)\n"); fprintf(file, "static inline float %s_get_resistance_by_temp(int16_t temp_c10) {\n", array_name); fprintf(file, " if (temp_c10 >= %s[0].temp_c) return %s[0].resistance_ohm;\n", array_name, array_name); fprintf(file, " if (temp_c10 <= %s[%d].temp_c) return %s[%d].resistance_ohm;\n", array_name, TABLE_SIZE_LOOKUP - 1, array_name, TABLE_SIZE_LOOKUP - 1); fprintf(file, " \n"); fprintf(file, " // Бинарный поиск\n"); fprintf(file, " int left = 0, right = %d;\n", TABLE_SIZE_LOOKUP - 1); fprintf(file, " while (left <= right) {\n"); fprintf(file, " int mid = left + (right - left) / 2;\n"); fprintf(file, " if (temp_c10 >= %s[mid].temp_c && temp_c10 <= %s[mid + 1].temp_c) {\n", array_name, array_name); fprintf(file, " // Нашли интервал, интерполируем в логарифмическом масштабе\n"); fprintf(file, " int16_t t_high = %s[mid].temp_c;\n", array_name); fprintf(file, " int16_t t_low = %s[mid + 1].temp_c;\n", array_name); fprintf(file, " float r_high = %s[mid].resistance_ohm;\n", array_name); fprintf(file, " float r_low = %s[mid + 1].resistance_ohm;\n", array_name); fprintf(file, " \n"); fprintf(file, " if (t_high == t_low) return r_high;\n"); fprintf(file, " \n"); fprintf(file, " float log_r_high = logf(r_high);\n"); fprintf(file, " float log_r_low = logf(r_low);\n"); fprintf(file, " float log_r = log_r_high + (log_r_low - log_r_high) * \n"); fprintf(file, " (float)(t_high - temp_c10) / (float)(t_high - t_low);\n"); fprintf(file, " return expf(log_r);\n"); fprintf(file, " }\n"); fprintf(file, " \n"); fprintf(file, " if (temp_c10 > %s[mid].temp_c) {\n", array_name); fprintf(file, " right = mid - 1;\n"); fprintf(file, " } else {\n"); fprintf(file, " left = mid + 1;\n"); fprintf(file, " }\n"); fprintf(file, " }\n"); fprintf(file, " return %s[%d].resistance_ohm;\n", array_name, TABLE_SIZE_LOOKUP - 1); fprintf(file, "}\n"); fclose(file); printf("Таблица '%s' сохранена в файл: %s\n", table_name, filename); } // Функция для сохранения таблицы в CSV формате (для Excel) 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, "# VCC_DIVIDER = %.2f V, VREF = %.2f V\n", VCC_DIVIDER_MV / 1000.0f, VREF_MV / 1000.0f); fprintf(file, "ADC,Temperature_C,Temperature_x10,Resistance_Ohm\n"); for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) { fprintf(file, "%u,%.1f,%d,%.2f\n", table[i].adc_value, table[i].temp_c / 10.0f, table[i].temp_c, table[i].resistance_ohm); } fclose(file); printf("Таблица '%s' сохранена в CSV файл: %s\n", table_name, filename); } // Функция для сохранения таблицы в TXT формате (для просмотра) void save_table_to_txt(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, "VCC делителя = %.2f V\n", VCC_DIVIDER_MV / 1000.0f); fprintf(file, "VREF АЦП = %.2f V\n", VREF_MV / 1000.0f); fprintf(file, "Всего записей: %d\n", TABLE_SIZE_LOOKUP); fprintf(file, "%-8s %-12s %-15s\n", "ADC", "Temp (°C)", "Resistance (Ω)"); fprintf(file, "---------------------------------------------\n"); // Выводим каждые 100 записей для компактности 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' сохранена в TXT файл: %s\n", table_name, filename); } // Функция для сохранения всех таблиц во всех форматах void save_all_tables_to_files(void) { const fast_lookup_tables_t* tables = get_fast_tables(); printf("\n=== Сохранение таблиц в файлы ===\n"); // Сохраняем DUCT таблицу save_table_to_c_file("duct_table_array.c", tables->duct, "DUCT", "duct_lookup_table"); save_table_to_csv("duct_table.csv", tables->duct, "DUCT"); save_table_to_txt("duct_table.txt", tables->duct, "DUCT"); // Сохраняем INCAR таблицу save_table_to_c_file("incar_table_array.c", tables->incar, "INCAR", "incar_lookup_table"); save_table_to_csv("incar_table.csv", tables->incar, "INCAR"); save_table_to_txt("incar_table.txt", tables->incar, "INCAR"); // Сохраняем AMBIENT таблицу save_table_to_c_file("ambient_table_array.c", tables->ambient, "AMBIENT", "ambient_lookup_table"); save_table_to_csv("ambient_table.csv", tables->ambient, "AMBIENT"); save_table_to_txt("ambient_table.txt", tables->ambient, "AMBIENT"); printf("\nВсе таблицы успешно сохранены!\n"); } // Функция для проверки корректности таблицы void validate_table(const adc_temp_lookup* table, const char* table_name, float r1) { printf("\n=== Проверка таблицы: %s (R1=%.0fΩ) ===\n", table_name, r1); int monotonic_errors = 0; int last_temp = table[0].temp_c; float min_resistance = 999999999.0f; float max_resistance = 0.0f; for (int i = 1; i < TABLE_SIZE_LOOKUP; i++) { // Проверка монотонности температуры (должна убывать) if (table[i].temp_c > last_temp) { if (monotonic_errors < 5) { printf("Ошибка монотонности: ADC=%u, Temp=%d > предыдущего %d\n", table[i].adc_value, table[i].temp_c, last_temp); } monotonic_errors++; } last_temp = table[i].temp_c; // Поиск min/max сопротивления if (table[i].resistance_ohm < min_resistance && table[i].resistance_ohm > 0) { min_resistance = table[i].resistance_ohm; } if (table[i].resistance_ohm > max_resistance) { max_resistance = table[i].resistance_ohm; } } if (monotonic_errors > 0) { printf("Найдено %d ошибок монотонности\n", monotonic_errors); } else { printf("Монотонность: OK (температура монотонно убывает)\n"); } printf("Диапазон сопротивлений: %.2f Ом ... %.2f Ом\n", max_resistance, min_resistance); // Вывод первых и последних записей printf("\nПервые 10 записей:\n"); for (int i = 0; i < 10 && i < TABLE_SIZE_LOOKUP; i++) { printf(" ADC=%4u: Temp=%6.1f°C, R=%8.2fΩ\n", table[i].adc_value, table[i].temp_c / 10.0f, table[i].resistance_ohm); } printf("\nПоследние 10 записей:\n"); for (int i = TABLE_SIZE_LOOKUP - 10; i < TABLE_SIZE_LOOKUP; i++) { printf(" ADC=%4u: Temp=%6.1f°C, R=%8.2fΩ\n", table[i].adc_value, table[i].temp_c / 10.0f, table[i].resistance_ohm); } } int main() { printf("=== Генерация таблиц быстрого поиска для NTC термисторов ===\n"); printf("Конфигурация:\n"); printf(" VCC делителя = %.2f V\n", VCC_DIVIDER_MV / 1000.0f); printf(" VREF АЦП = %.2f V\n", VREF_MV / 1000.0f); printf(" ADC_MAX = %.0f\n", ADC_MAX); printf(" Максимальное ADC при VCC=%.2fV: %.1f\n", VCC_DIVIDER_MV / 1000.0f, (VCC_DIVIDER_MV * ADC_MAX) / VREF_MV); // Инициализируем все три таблицы printf("\n=== Инициализация таблиц ===\n"); init_all_tables(3000.0f, // R1 для DUCT (KST45) - 3kΩ 20000.0f, // R1 для INCAR - 20kΩ 20000.0f, // R1 для AMBIENT (NTC 10k) - 20kΩ ALG_STEINHART); printf("Таблицы успешно инициализированы\n"); // Проверяем таблицы const fast_lookup_tables_t* tables = get_fast_tables(); validate_table(tables->duct, "DUCT", g_fast_tables.duct_r1); validate_table(tables->incar, "INCAR", g_fast_tables.incar_r1); validate_table(tables->ambient, "AMBIENT", g_fast_tables.ambient_r1); // Сохраняем таблицы в файлы save_all_tables_to_files(); // Пример использования printf("\n=== Пример использования ===\n"); uint16_t test_adcs[] = {0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000}; printf("ADC\tDUCT Temp\tINCAR Temp\tAMBIENT Temp\n"); printf("------------------------------------------------\n"); for (int i = 0; i < sizeof(test_adcs)/sizeof(test_adcs[0]); i++) { uint16_t adc = test_adcs[i]; int16_t temp_duct = get_temperature_log_fast_for_table(adc, TABLE_DUCT); int16_t temp_incar = get_temperature_log_fast_for_table(adc, TABLE_INCAR); int16_t temp_ambient = get_temperature_log_fast_for_table(adc, TABLE_AMBIENT); printf("%u\t%.1f°C\t\t%.1f°C\t\t%.1f°C\n", adc, temp_duct / 10.0f, temp_incar / 10.0f, temp_ambient / 10.0f); } printf("\n=== Готово ===\n"); printf("Сгенерированы файлы:\n"); printf(" - duct_table_array.c (статический массив)\n"); printf(" - incar_table_array.c (статический массив)\n"); printf(" - ambient_table_array.c (статический массив)\n"); printf(" - duct_table.csv, incar_table.csv, ambient_table.csv (для Excel)\n"); printf(" - duct_table.txt, incar_table.txt, ambient_table.txt (для просмотра)\n"); return 0; }