256 lines
13 KiB
C
256 lines
13 KiB
C
#include <stdio.h>
|
||
#include "ADC_Temp.h"
|
||
|
||
// Упрощенная структура для хранения записи таблицы
|
||
typedef struct {
|
||
uint16_t adc_value; // Значение АЦП
|
||
int16_t temp_c; // Температура в °C * 10
|
||
float resistance_ohm; // Сопротивление в Ом
|
||
} adc_temp_lookup_entry_t;
|
||
|
||
// Функция для сохранения температур в одну строку через пробел (все значения)
|
||
void save_temperature_int_one_line(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=%.2fV, VREF=%.2fV\n", VCC_DIVIDER_MV / 1000.0f, VREF_MV / 1000.0f);
|
||
fprintf(file, "# Всего значений: %d\n", TABLE_SIZE_LOOKUP);
|
||
fprintf(file, "# Температура в °C * 10 (целые числа)\n\n");
|
||
|
||
for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) {
|
||
if (i > 0) fprintf(file, " ");
|
||
fprintf(file, "%d", table[i].temp_c);
|
||
}
|
||
|
||
fprintf(file, "\n");
|
||
fclose(file);
|
||
printf("Температуры (int one-line) для '%s' сохранены в файл: %s\n", table_name, filename);
|
||
}
|
||
|
||
// Функция для сохранения таблицы в 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 <stdint.h>\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");
|
||
save_temperature_int_one_line("duct_temperatures.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");
|
||
save_temperature_int_one_line("incar_temperatures.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");
|
||
save_temperature_int_one_line("ambient_temperatures.txt", tables->ambient, "AMBIENT");
|
||
|
||
printf("\nВсе таблицы успешно сохранены!\n");
|
||
}
|
||
|
||
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("\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");
|
||
|
||
// Сохраняем таблицы в файлы
|
||
save_all_tables_to_files();
|
||
|
||
printf("\n=== Готово ===\n");
|
||
printf("Сгенерированы файлы:\n");
|
||
printf(" - duct_table_array.c, incar_table_array.c, 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");
|
||
printf(" - duct_temperatures.txt, incar_temperatures.txt, ambient_temperatures.txt (температуры в одну строку)\n");
|
||
|
||
return 0;
|
||
} |