Последняя часть цикла статей о индикаторе расхода топлива. Первые две части находятся здесь и здесь.
Программа для контроллера получилась довольно комплексной, потому я постарался наполнить ее комментариями, насколько это возможно. Вдобавок, полагаю будет не лишним описать здесь весь принцип реализованного алгоритма.
Саму программу и файл прошивки можно сказать здесь.
Программа пользуется обоими таймерами, имеющимися на борту микропроцессора. Восьмибитный таймер, запущенный с делителем 1024 (т.е. работающий на частоте 8МГц/1024=7812Гц), при переполнении вызывает прерывание. За 1 секунду происходит примерно 30 таких прерываний, так что отсчитав 6 из них, можно точно отмерять промежутки времени в примерно 0.2 секунды. Это и есть те самые 0.2 секунды, задающие такт всей системе.
Шестнадцатибитный таймер использует внешнее прерывание для включения и выключения – он включается по спадающему и выключается по возрастающему фронту. Иными словами, таймер считает, когда инжектор открыт. Каждые 0.2 секунды главная функция программы сравнивает текущее значение таймера с максимально известным значением, и на основании этого сравнения, принимает решение, насколько заполнить индикатор. Теперь о максимальном значении – у программы есть два режима работы, в точности как у Терминатора – помните, у него был переключатель в мозгах, который позволял или запрещал Терминатору учиться новым вещам. Изначально программа учится – каждый раз, обнаружив новое значение таймера, которое больше предыдущего максимума, она запоминает его в энергонезависимую память EEPROM (в переменную maximum). Там-же хранится флаг (переменная learning), отвечающий за включение и отключение режима обучения – соответственно, когда этот режим выключен, программа не будет запоминать новые максимальные значения подсчетов таймера.
Возможность смены режима обучения была сделана вот для чего: как выяснилось, на максимальном “газе” (а-ля “pedal to the metal”) подача бензина столь велика, что после запоминания значений таймера в таких режимах работы, при обычном, спокойном стиле езды, индикатор заполняется всего на 2-3 деления из 10. Естественно, это не совсем удобно и устройство теряет смысл существования, при обычной езде, без гонок. Поэтому я обучил его немного газанув на разгоне, и отрубил обучающий режим. Теперь при прогреве например, горят 2 деления. При обычной езде – до 6ти, при резвом разгоне – 9-10, ну и если вообще притопить, то все 10 постоянно.
Для сброса сохраненного в EEPROM максимально известного значения таймера и переключения режимов обучения устройства, существует кнопка SW2 (смотрите схему). Если во время работы устройства подержать ее нажатой несколько секунд, то EEPROM обнулится. Если держать ее нажатой в момент инициализации микропроцессора (читай – подачи питания на устройство), то оно переключится на другой режим обучения.
Для визуализации процессов инициализации, запоминания в EEPROM новых значений и переключения режимов обучения реализованы простые схемы подмигивания индикатором – этим занимаются функции running_bar и blinking_bar.
Поскольку запись в EEPROM процесс довольно медленный, обнаружив необходимость записать в EEPROM новое значение таймера, программа ждет примерно минуту (300 циклов по примерно 0.2 секунды), прежде чем записать его (этим занимается переменная e_eprom_w_timer). Если в течении этой минуты будет обнаружено очередное, еще более высокое значение таймера, то отсчет минуты начинается заново.
Важный момент в работе шестнадцатибитного таймера – при выключении двигателя, таймер включается по спадающему фронту внешнего прерывания, и остается включенным. Это не есть хорошо, поскольку работа всего устройства будет скомпрометирована. Решение проблемы очень простое: таймер работает с делителем 64, т.е. на частоте 8МГц/64=125КГц, следовательно он переполнится примерно за 0.5 секунды. Включаем прерывание на переполнение этого таймера. Если такое прерывание наступает, то система понимает, что двигатель остановлен, вырубает таймер, обнуляет его, отменяет запись в EEPROM нового, нереального значения таймера (ведь он продолжает непрерывно считать почти полсекунды, думая что инжектор открыт) и инициализирует систему по новой (замещает неверные максимальные значения таймера правильными, из EEPROM).