Форум программистов, компьютерный форум, киберфорум
Электроника для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/28: Рейтинг темы: голосов - 28, средняя оценка - 4.82
0 / 0 / 0
Регистрация: 27.06.2014
Сообщений: 35

Алгоритм калибровки датчика уровня топлива.

19.02.2015, 00:32. Показов 6082. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Продолжаю осваивать AVR микроконтроллеры на примере датчика уровня топлива. Датчик обычный резистивный(поплавковый). Прочитав несколько статей по этому поводу, я определился с алгоритмом:
Калибровка:
Заливаем 1 литр топлива в бак - сохраняем показания АЦП
Заливаем 2 литра в бак и. т. д....
Контроль уровня топлива:
Нужно сравнивать значения которые приходят с АЦП, с теми, что были ранее сохранены. Но я так понимаю, я не могу конкретно сравнивать текущее значение с сохраненным, так как текущее значение АЦП (которое отвечает определенному количеству топлива) может отличаться от сохраненного (отвечающего ЭТОМУ же количеству топлива) в некотором диапазоне.
Все попытки осуществить задумку закончились функцией для первоначальной калибровки:
Code
1
2
3
4
5
6
7
8
9
10
11
void kotybrovka(void)
{
if(press_button)
{
adc_fuel(); //функция сканирования каналов АЦП
}
fuel[i]=adc_data[1];//переменная в которую записался результат сканирования каналов АЦП
i++;
if(i>=30) i=0;
}
}
Главный вопрос заключается в том, как сравнивать текущее значение АЦП с тем что сохранено, но с определенным разбросом (если считанное значение лежит в диапазоне от х до у, то записать в переменную А, то количество топлива, которое соответствует данному диапазону) Буду благодарен за любую помощь.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.02.2015, 00:32
Ответы с готовыми решениями:

Корректор уровня топлива в баке на Attiny13
Приветствую всех! Хочется посоветоваться как правильно реализовать прибор, который будет переключать показания штатного показометра топлива...

Согласование датчика топлива ГАЗ и прибора Тойота
Вот такая проблема. Есть Волга, в неё установлен мотор, АКПП и доска приборов Тойота Краун. Требуется согласовать датчик уровня топлива...

Разработка устройства коррекции показаний датчика топлива
Привет. Подвернулась мне возможность для одной конторы разработать устройство, которое впоследствии пойдет в мелкую серию. Кое-что...

8
0 / 0 / 0
Регистрация: 21.08.2011
Сообщений: 1,057
19.02.2015, 01:03
if (ADC_fuel > 10 && ADC_fuel<20) { real_fuel_val:=1;}
elsif (ADC_fuel > 20 && ADC_fuel<30) { real_fuel_val:=2;}

итд. Не оно?

Еще можно поиграться с округлением. Взять 10-битный диапазон и разбить на 8 поддиапазонов, округляя через сдвиг переменной.

И еще: код типа:
Code
1
2
3
4
5
 if(press_button)
{
adc_fuel();
}
fuel[i]=adc_data[1];
Это плохой код.
Хороший код:
Code
1
2
3
4
if(press_button)
{
fuel(i):=read_ADC();
}
Работайте с функциями, а не процедурами. Функции делайте универсальными. Т.е вместо двух readFuel(); readTemp(); напишите readADC(char channel); readADC(FUEL_CHANNEL); readADC(TEMP_CHANNEL);, где каналы АЦП можно задавать макросами. Избегайте глобальных переменных. Читайте Кормена. Не курите.
0
0 / 0 / 0
Регистрация: 27.06.2014
Сообщений: 35
19.02.2015, 02:32
Благодарю за ответ!
Цитата Сообщение от soumt_imobti
if (ADC_fuel > 10 && ADC_fuel<20) { real_fuel_val:=1;}
elsif (ADC_fuel > 20 && ADC_fuel<30) { real_fuel_val:=2;}
Это да, но мне ведь нужно сравнивать текущее значение ацп, с ранее записанным, а не с числами... то есть нужно что то типа:
if (adc_data[1]==fuel[i]+/-какое то значение) { real_fuel_val:=1;}
Где adc_data[1] - результат чтения канала АЦП,
fuel[i] - массив с ранее записанными константами, где i увеличиваеться до совпадения, только нужно чтобы либо каждый элемент массива fuel[] был не константой, а находился в некотором диапазоне (+/-какое то значение),
либо этот диапазон задавался при сравнении adc_data[1]==fuel[i].
Возможно я не корректно пояснил...Давайте по порядку:
АЦП работает по прерыванию в режиме Frii Running:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#defyme FIRST_ADC_INPUT 0     //Первый кнал ADC ADC0
#defyme LAST_ADC_INPUT 1      //Следующийй канал ADC ADC1
unsykned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1]; //Переменная хранения ADC данных
//Обслуживания прерывания для автоматического сканирования каналов
interrupt [ADC_INT] void adc_isr(void)
{
static unsykned char input_index=0;
adc_data[input_index]=ADCW; //Чтение результата АЦП преобразования
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT)) //Селективный выбор
input_index=0;                                     //следующего входа АЦП
ADMUX=(FIRST_ADC_INPUT | (ADC_VREF_TYPE & 0xff))+input_index;
delay_us(10);  //Выдержка времени для стабилизации входного напряжения
ADCSRA|=0x40; //Старт АЦП преобразования
}
Считываю циклично два канала(вольтметр, датчик уровня)
Для вольтметра имеется функция, которую я вызываю в нужном мне месте:
Code
1
2
3
4
5
void adc_VOLT(void)
{
data = adc_data[0]*4;  //Запись в переменную результата ADC 0-го канала
volt = (5/10.23)*data;
}
Дальше определенным образом я буду переходить в режим калибровки и там значение adc_data[1] будет по моей команде записываться в массив fuel[i++]. Когда все значения записаны, сохраняем все это в EEPROM.
В нормальном режиме работы нужно текущее значение adc_data[1] сравнивать с значениями из массива fuel[]. Но как я уже писал, есть большая вероятность того, что не одно из значений не сойдется, так как текущее значение АЦП (которое отвечает определенному количеству топлива) может отличаться от сохраненного (отвечающего ЭТОМУ же количеству топлива) в некотором диапазоне.
Цитата Сообщение от soumt_imobti
Еще можно поиграться с округлением. Взять 10-битный диапазон и разбить на 8 поддиапазонов, округляя через сдвиг переменной.
Боюсь моих знаний на это пока не достаточно((
Цитата Сообщение от soumt_imobti
Работайте с функциями, а не процедурами. Функции делайте универсальными. Т.е вместо двух readFuel(); readTemp(); напишите readADC(char channel); readADC(FUEL_CHANNEL); readADC(TEMP_CHANNEL);, где каналы АЦП можно задавать макросами. Избегайте глобальных переменных. Читайте Кормена. Не курите.
Спасибо, обязательно учту.
0
0 / 0 / 0
Регистрация: 12.04.2013
Сообщений: 241
19.02.2015, 02:46
Вам уже намекают, но Вы всё никак не можете избавится от оператора "==".
В предыдущих намёках была лишь одна огрешность, её я подправил
if ( ADC_fuel<ee_1) { real_fuel_val:=1;} { real_fuel_val:=0;}
else if (ADC_fuel >= ee1_1 && ADC_fuel<ee_2) { real_fuel_val:=1;}
else if (ADC_fuel >= ee_2 && ADC_fuel<ee_3) { real_fuel_val:=2;}
........................................ ............
else if (ADC_fuel >= ee_101 && ADC_fuel<=ee_102) { real_fuel_val:=100;}

где ee_1 ....... ee_102 - значения записанные в еепроме при калибровке.
0
0 / 0 / 0
Регистрация: 21.08.2011
Сообщений: 1,057
19.02.2015, 03:15
Цитата Сообщение от somyo.95
Боюсь моих знаний на это пока не достаточно
Глаза боятся, руки делают.
Про сравнение с интервалом уже объяснили.
Теперь о прерываниях:
Code
1
2
3
interrupt [ADC_INT] void adc_isr(void)
{....
delay_us(10);  //Выдержка времени для стабилизации входного напряжения
НЕТ, нет, и нет! Обработчик прерывания должен быть максимально быстр! В прерывании устанавливаем флаг ADC_NEW_VOTUE, и в главном цикле запускаем функцию измерения.
Если нужно усреднение, то в обработчике прерывания пишем ADC_val+=ADCW; ADC_count++; if (ADC_count==10){ ADC_XUJARIM_OBRABOTKU=1; ADC_count=0;}, и в ф-ции измерения (которая ждёт флаг==1) делим измеренное на 10. Если нужна задержка - запускаем ее опять же вне прерывания.
Все эти премудрости относятся к хорошему стилю. Без них прога работать будет, но только до некого уровня сложности.
0
0 / 0 / 0
Регистрация: 27.06.2014
Сообщений: 35
19.02.2015, 10:07
Цитата Сообщение от otixdos
if ( ADC_fuel<ee_1) { real_fuel_val:=1;} { real_fuel_val:=0;}
else if (ADC_fuel >= ee1_1 && ADC_fuel<ee_2) { real_fuel_val:=1;}
else if (ADC_fuel >= ee_2 && ADC_fuel<ee_3) { real_fuel_val:=2;}
Спасибо, теперь я понял! У меня например 30 литров, можно ли построить такую функцию, чтобы
не писать 60+ строк...:
Code
1
2
3
4
5
6
eeprom unsykned int ee[30];
usykned char a=0;
if ( ADC_fuel<ee[a]) { real_fuel_val:=[a];}
else if (ADC_fuel >= ee[a] && ADC_fuel<ee[a+1]) { real_fuel_val:=a+1;}
a++;
if(a>30)a=0;
Будет ли она работать должным образом?
Цитата Сообщение от otixdos
НЕТ, нет, и нет!
Спасибо, про усреднение понял. Но вот не понятно как запускать функцию измерения из основного цикла. Я так понимаю: сделали замер--выставляем флаг(в прерывании)--в основном цикле опрашиваем флаг(если есть - округляем там, еще чего то делаем)--сбрасываем флаг. Этот же флаг опрашиваем и в прерывании(но у нас ведь еще вольтметр), или пусть сканирует непрерывно, а мы будем выхватывать нужное нам измерение только тогда когда нужно? Можете еще раз на "пальцах" объяснить?
0
0 / 0 / 0
Регистрация: 10.04.2014
Сообщений: 879
19.02.2015, 10:58
А не проще снять характеристику датчика, зависимость показаний ацп от количества топлива
Аппроксимировать функцию, хоть через эксэль, и уже её вычислять
А еще учтите что это всё для сферического коня в вакууме
У нас не на столько дороги ровные, на кочках оно вам такое покажет!!!
Нужно как-то программно сглаживать

Еще такой момент. Вроде датчики топлива - проволочные. То есть характеристика не наклонная а ступеньками.
Может не все такие. На всякий случай
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 2,309
19.02.2015, 12:00
Да. Вот идея с апроксимацией самая надежная в таком случае. Просто поплавок на валу резюка дают несколько нелинейный результат. Потому апроксимировать его нужно полиномом второй, а то и третьей степени. А считать количество топлива из этого полинома на МК уже сложно (если это не Sortix-M4 какой нибудь). Если апроксимировать прямой - то это гораздо проще, но будут ошибки (особенно по краям - когда бак почти пустой, и когда он почти полный).

Еще можно попробовать апроксимировать экспонентой и считать с фиксированной точкой.
0
0 / 0 / 0
Регистрация: 21.08.2011
Сообщений: 1,057
19.02.2015, 12:19
Цитата Сообщение от somyo.95
Но вот не понятно как запускать функцию измерения из основного цикла. Я так понимаю: сделали замер--выставляем флаг(в прерывании)--в основном цикле опрашиваем флаг(если есть - округляем там, еще чего то делаем)--сбрасываем флаг. Этот же флаг опрашиваем и в прерывании(но у нас ведь еще вольтметр), или пусть сканирует непрерывно, а мы будем выхватывать нужное нам измерение только тогда когда нужно?
Пусть нам нужны средние значения из последних 10 измерений АЦП на 1 и 2 канале, которые читаем каждые Х миллисекунд. Выбор канала сделан правильно, но думаю удобнее будет использовать прерывание от таймера, а не от АЦП. Т.е. настраиваем таймер на прерывание каждые Х/количество каналов миллисекунд, в прерывании записываем текущее значение АЦП и переключаем АЦП на следующий канал. Каждый канал пишется в свой массив циклично, т.е. если массив значений заполнен то пишем с нулевого элемента. Таким образом у нас в массиве всегда лежит последних 10 значений измерения с интервалом Х.
В главной программе нам уже не нужны никакие флаги. Мы берём среднее из массива, пересчитываем его в литры/вольты и показываем пользователю или записываем где-то. Плюс такого подхода в том что таймер с ацп собирают данные самостоятельно, и главная прога не нуждается ни в задержках, ни во флагах и может исполняться с любой частотой без потери данных. Динные из массива вместо обычного округления можно прогонять через фильтр (НЧ, Калмана, любой). Это должно повысить качество измерений.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.02.2015, 12:19
Помогаю со студенческими работами здесь

указатель уровня топлива в приборку
давно надо было так сделать. чтобы не мусорить везде, решил все же выделиться в отдельную тему :-) итак. есть некая приборная доска, в...

Определение фактов заправок по датчику уровня топлива
Есть сигнал с датчика уровня топлива в баке. Нужно определить все факты заправок. ( выделены зеленым на графике ). Я пробовал использовать...

Контроль трех-электродного датчика уровня и управление насосом
Здравствуйте! Я в программировании полный профан и прошу помощи, собственно вот скетч(это управление перистальтическим насосом): ...

Преобразование сигнала датчика уровня
Проблема простая, но додуматься как решить не получается. Построил схему, в конце которой выводится интегрируемое по времени значение от...

Опрос множества электродов кондуктометрического датчика уровня воды
Есть схема кондуктометрического датчика уровня воды. Нужно одним экземпляром этой схемы и МК AVR опрашивать несколько электродов. ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru