Индикатор заряда аккумулятора
Если Вам хоть немного понравилась моя первая
статья "светофор", и у Вас появился интерес что — либо создавать на
микроконтроллерах, то можно процесс обучения перевести из теории и моделей,
немного в практическое русло. То есть будем создавать и модель, и реальное
устройство (как говорят «в железе»). Можно было бы конечно реализовать и
«светофор» в «железе», но практической пользы от него (кроме как игрушка для
ребёнка) нет, зато есть польза от созданных нами моделей в 2-х программах
проектирования.
Одному моему знакомому понадобился индикатор заряда 12В аккумулятора. Я предложил ему что-либо выбрать из готовых схемотехнических решений, благо их очень много. Но ему ничего не понравилось.
Итак, передо мной стояла задача:
1. простота
конструкции;
2. дешевые
компоненты;
3. низкий
потребляемый ток;
4. интуитивно
понятная индикация степени заряда аккумулятора;
5. как можно больше
уровней контроля ( не лишь — «заряжен», «норма» и «разряжен»);
6. использование
проекта для данной статьи.
В качестве индикаторного устройства
для визуального контроля уровня заряда решил использовать RGB светодиод (три светодиода в одном
корпусе), а уровни заряда решил индицировать цветом свечения светодиода. Поскольку
нужно низкое потребление тока, решил включать светодиод один раз в две секунды.
Теперь с цветом индикации, принимаем:
1. светодиод
выключен (заряд полный);
2. белый;
3. сине-зелёный
(бирюзовый);
4. синий;
5. зелёный;
6. сине-красный
(фиолетовый);
7. красно-зелёный
(оранжевый);
8. красный (срочно
нужно зарядить).
В качестве управляющего устройства выберем дешевый Attiny13A, у него «борту» есть десяти битный АЦП. Ещё, нам необходимо
рассчитать делитель напряжения, поскольку нам нужно контролировать напряжение
от максимума 14.7В, а максимум напряжения на входе АЦП Attiny13A равен 5В. Расчёт производим по формуле, (рис.1):
Рис.1.
Можно посчитать на онлайн-калькуляторе, например: /me/calc/divider_calc.php
Я исходил из тех номиналов, которые
были у меня в наличии. Вы можете подбирать свои, но помните, что устройство
наше должно потреблять как можно меньший ток. У меня получилось 12кОм, и
6.2кОм.
Теперь можно приступить к созданию
схемы в ISIS Proteus. Я не буду словами описывать процесс создания схемы,
поскольку прочитав первую статью «светофор», Вы уже кое-что научились делать
сами. Но на всякий случай прилагаю видео создания модели схемы.
Рис.2
Что нового для Вас в этом видео?
1. POT-HG – аналоговый примитив потенциометра;
2. R4(1), R5(2) — Щуп напряжения, в процессе симуляции показывает
напряжение в той точке схемы, куда прикреплён, относительно GROUND (корпуса);
3. RV1(2) — генератор DC, генератор постоянного напряжения
(напряжение задаём в правке его свойств);
Для удобства проектирования печатной
платы, можно сделать так: вход ADC (АЦП), расположить с одной стороны микросхемы (выв.2); выходы на светодиоды – с
другой стороны (выв.5,6,7), порт В0(GREEN), В1(BLUE), В2(RED), соответственно.
Ну, можно на бумаге или где то ещё набросать реальную схему.
Я воспользовался простенькой программой “Rusplan”(рис.3).
Рис.3
HL3 – Green; HL2 – Blue; HL1 – Red.
Добавилась цепь: D1, D2, R6 – Обрывной резистор, диод и стабилитрон, для защиты от переполюсовки
и превышения входного напряжения. Так сказать «на всякий случай».
Закончим теперь нашу модель в “Proteus”. Соединим порты микроконтроллера
соответственно порт В0, В1, В2 с нужными светодиодами, и порт В3 (будем
конфигурировать его как АЦП) к выходу нашего делителя напряжения.
Рис.4
Пора заняться управляющей программой. Но, перед этим
словесно опишем алгоритм работы индикатора.
1. Нам нужно разбить наш диапазон
(10.0В – 14.7В) на 8 частей:
4.7 / 8 = 0.59 , примем шаг 0.6В.
2. Запишем соответствие цвет –
напряжение:
НЕ ГОРИТ — от 14.7 до (14.7 — 0.6) = 14.1;
БЕЛЫЙ – от 14.1 до 13.5;
БИРЮЗОВЫЙ – от 13.5 до 12.9;
СИНИЙ – от 12.9 до 12.3;
ЗЕЛЁНЫЙ – от 12.3 до 11.7;
ФИОЛЕТОВЫЙ – от 11.7 до 11.1;
ОРАНЖЕВЫЙ – от 11.1 до 10.5, можно выделить первое
предупреждение о зарядке (дополнительным миганием);
КРАСНЫЙ – от 10.5 — ……, можно выделить последнее
предупреждение о зарядке (дополнительным миганием).
3. Рассчитаем теперь напряжения после делителя (на входе
АЦП).
Формула нам уже знакома, лишь вместо U1 будем подставлять наши значения,
получим:
НЕ ГОРИТ — от 5.00 до 4.80;
БЕЛЫЙ – от 4.80 до 4.60;
БИРЮЗОВЫЙ – от 4.60 до 4.40;
СИНИЙ – от 4.40 до 4.19;
ЗЕЛЁНЫЙ – от 4.19 до 3.99;
ФИОЛЕТОВЫЙ – от 3.99 до 3.78;
ОРАНЖЕВЫЙ – от 3.78 до 3.58, можно выделить первое
предупреждение о зарядке (дополнительным миганием);
КРАСНЫЙ – от 3.58 — 0.00, можно выделить последнее
предупреждение о зарядке (дополнительным миганием).
Ну вот, всё что нужно у нас уже есть. Запускаем Flowcode AVR. Напомню, что сохраняемый файл проекта (к примеру “indicator”) должен находится в корневом
каталоге любого из дисков в папке с названием, состоящим из лишь латинских
букв, и в имени файла должны использоваться лишь латинские буквы.
Сразу поставим бесконечный цикл что бы контроллер
не закончил выполнение программы, и не забыть это сделать потом. Конфигурируем
вход, выбираем «входы», «ADC»
и наблюдаем, как на панели появилась крутилка (рис.5, 6).
Рис.5
Рис.6
Выбираем «свойства» «крутилки», мне лично нравятся большие
крутилки, поэтому я выберу максимальный размер. Выбираем «соединение»,
указываем: у нас вывод «2», это ADC3,
выбираем его (рис.7,8).
Рис.7
Рис.8
Сконфигурируем выходы (у нас
светодиоды), красный – порт В2, синий – порт В1, зелёный – порт В0. Для этого
выбираем: «выходы», «LED».
И соответственно в расширенных свойствах выбираем цвет светодиода и его
полярность. В прошлой статье мы включали светодиоды с общим катодом, давайте
сейчас включим их с общим анодом, значит, выбираем: “polarity”, “LOW” . А в свойствах соединения указываем
соответствующие порты для каждого из них (рис. 9-17).
Рис.9
Рис.10
Рис.11
Рис.12
Рис.13
Рис.14
Рис.15
Рис.16
Рис.17
Теперь у нас вход, и выходы сконфигурированы.
Приступим к реализации самого алгоритма. Изначально у нас все светодиоды
выключены. Перетягиваем в тело бесконечного цикла «макрос компонента», в
свойствах выбираем «LED0», ну и «OFF». Что значит — выключить красный
светодиод. Повторяем эти действия для остальных светодиодов. После поставим
задержку – 2 секунды (вспоминаем, что мы включаем индикацию 1 раз в две
секунды). Соответственно «Delay»,
и ставим необходимое время паузы (см. видео, и рис.18).
Рис.18
Далее нужно считать
данные с ADC (АЦП). Перетягиваем «макрос
компонента», «свойства», выбираем «ADC0». В правой колонке видим надписи — «ReadAsByte, ReadAsInt, ReadAsVoltage, ReadAsString». Дело в том что напряжение на входе
АЦП можно прочитать по разному. Во «Флаукоде» переменные бывают такими: INT (-32768…….32767), BYTE (0……255), STRING, FLOATING POINT ( с
плавающей точкой ). В Attiny13
АЦП десятиразрядный, это значит, что максимальное значение считанного с АЦП
кода будет равно 1023. То есть на входе АЦП у нас напряжение от 0 до 5В, а на
выходе будет код, от 0 до 1023. Что бы использовать максимальную точность
измерения напряжения нужно использовать переменную типа INT, если не нужна большая точность,
можно использовать тип BYTE,
тогда соответственно: на входе 0….5в, а переменная будет принимать значения от
0….255. Давайте, используем все десять разрядов (0….1023) и пересчитаем наши
напряжения (стр.5) в коды АЦП.
1. НЕ ГОРИТ – 5.0В….4.8В
1023….982.
2. БЕЛЫЙ – 4.8В…..4.6В
982…..941.
3. БИРЮЗОВЫЙ – 4.60В….4.40В
941….900.
4. СИНИЙ
– 4.40В….4.19В
900….857.
5. ЗЕЛЁНЫЙ –
4.19В….3.99В
857….816.
6. ФИОЛЕТОВЫЙ –
3.99В….3.78В
816….773.
7. ОРАНЖЕВЫЙ – 3.78В….3.58В
773….733.
8. КРАСНЫЙ – 3.58В….0.00В
733….0.
Продолжим. В правой колонке видим надписи — «ReadAsByte, ReadAsInt, ReadAsVoltage, ReadAsString». Естественно выбираем «ReadAsInt», далее кликаем «variables» , нам нужно обозначить нашу
переменную(рис.19,20,21).
Рис.19
Рис.20
Рис.21
Теперь у нас код АЦП после каждого измерения хранится в
переменной типа INT под именем «u_input» (рис.22).
Рис.22
Ну и не забываем писать комментарии что бы, не запутаться
самому, и не запутать других (рис.23).
Рис.23
Если наш считанный с АЦП код меньше
или равен 982 (4.8В), включаем белый цвет (все три светодиода). Используем «decision», оператор ветвления. Перетянем его
и в свойствах укажем сравнение значения переменной «u_input», с числом
982 (рис.24,25).
Рис.24
Рис.25
Далее, если «u_input» менше или
равно 941, цвет у нас бирюзовый, соответственно включаем синий и зелёный
светодиод (рис.26).
Рис.26
Далее, по аналогии проделываем те же
действия, но с другими значениями и светодиодами. Подробно думаю, нет смысла
описывать, но приложу видео.
Вот что у нас получилось (рис.27).
Рис.27
Теперь давайте, вспомним последние два пункта нашего
алгоритма. Когда напряжение на аккумуляторе ниже 11.1В. неплохо бы выделить
дополнительным миганием светодиодов соответствующего цвета предупреждение о
том, что аккумулятор нуждается в зарядке.
Как «мигать» светодиодами? Вы можете придумать и сами. Ну
а я, сделал три коротких вспышки на оранжевом, (красный, зелёный) и, пять
коротких вспышек на красном. В прошлой статье это было: перетягиваем цикл,
выставляем количество циклов и т.д. (рис.28) .
Рис. 28
Далее мы должны проверить, что у нас получилось. Запускаем
симуляцию.
У кого не работает, не
расстраивайтесь. От машинальных ошибок никто не застрахован. Благо есть
отладка, можно пошагово выполнять программу и наблюдать за событиями и
переменными. Уверен, Вы справитесь! На рис.29 представлен алгоритм полностью.
Приступим к компиляции проекта. Для
того, чтобы длительности пауз совпадали с указанными в проекте, нужно выставить
частоту тактового генератора одинаковую, как в «протеусе», так и во «флаукоде»,
используем встроенный генератор с частотой 9.6Мгц (рис.30,31).
Рис.30
Рис.31
Далее компилируем проект (рис.32.33).
Рис.32
Рис.33
:1000000009C016C015C014C013C012C011C010C062
:100010000FC00EC011241FBECFE9CDBF10E0A0E677
:10002000B0E001C01D92AA37B107E1F702D01FC1AD
:10003000E7CFDF93CF930F92CDB7DEB714BE88E141
:100040000FB6F89481BD11BC0FBE40E659E063E8DD
:1000500073E2BA9AC29AB99AC19AB89AC09A30E031
:100060001EC0CA010197F1F72F5F2A3FD1F720E0A8
:10007000CA010197F1F72F5F2A3FD1F720E0CA01AB
:100080000197F1F72F5F2A3FD1F720E0CA010197CE
:10009000F1F72F5F2A3FD1F73F5F323011F020E0B8
:1000A000E0CF97B3BB9866B977B9198203C089814D
:1000B0008F5F898389818832D0F3369A3699FECF53
:1000C00097BB84B1829586958695837090E025B123
:1000D00030E0220F331F220F331F282B392B309390
:1000E0007900209378008091780090917900875D65
:1000F00093400CF0AECF80917800909179008E5AA9
:1001000093400CF09FC080917800909179008558C1
:1001100093400CF084C080917800909179008A55CA
:1001200093400CF06BC080917800909179008153DE
:1001300093400CF052C080917800909179008650E5
:1001400093400CF037C080917800909179008E5DDB
:100150009240B4F435E0BA9AC29820E0CA010197FF
:10016000F1F72F5F283CD1F7BA9AC29A20E0CA0172
:100170000197F1F72F5F283CD1F7315061F769CF34
:1001800033E0BA9AC298B89AC09820E0CA010197A1
:10019000F1F72F5F283CD1F7BA9AC29AB89AC09A61
:1001A00020E0CA010197F1F72F5F283CD1F73150C9
:1001B00041F74FCFBA9AC298B99AC19820E0CA01C4
:1001C0000197F1F72F5F2F3FD1F720E0CA01019788
:1001D000F1F72F5F2139D1F73CCFB89AC09820E0D2
:1001E000CA010197F1F72F5F2F3FD1F720E0CA0135
:1001F0000197F1F72F5F2139D1F72BCFB99AC19829
:1002000020E0CA010197F1F72F5F2F3FD1F720E0DF
:10021000CA010197F1F72F5F2139D1F71ACFB99AA7
:10022000C198B89AC09820E0CA010197F1F72F5FF2
:100230002F3FD1F720E0CA010197F1F72F5F213955
:10024000D1F707CFBA9AC298B99AC198B89AC0980C
:1002500020E0CA010197F1F72F5F2F3FD1F720E08F
:10026000CA010197F1F72F5F2139D1F7F2CEF89447
:02027000FFCFBE
:00000001FF
Полученный нами HEX код. Так называемая прошивка.
Программа на «СИ» находится в папке с файлами к статье.
Теперь запустим симуляцию в
«протеусе».
Печатную плату можете разработать свою, под
нужный корпус, размеры компонентов, и т.д. Я использовал широко известную
программу «Sprint layout5.1». Моя плата под ЛУТ (рис.34).
Рис.34
Прошивка микроконтроллера
Программатор у меня собран по этой схеме, есть ещё несколько,
но нравится мне этот (рис.35).
Рис.35
Софт для прошивки.
Рис.36
Можно использовать и другое, главное уметь им пользоваться.
Просили подробнее остановиться на «fuse bit». Fuse
bits называют область (4 байта) в AVR микроконтроллерах отвечающую за начальную
(глобальную) конфигурацию. Этими битами мы указываем микроконтроллеру, с каким
задающим генератором ему работать (внешним / внутренним), делить частоту генератора
на коэффициент или не нужно, использовать ножку сброса как сброс или как
дополнительный порт ввода-вывода, количество памяти для загрузчика и многое,
многое другое. У каждого контроллера свой набор фьюзов. Все фьюзы прописаны в
даташите на микроконтроллер. С завода, по умолчанию, фьюзы выставлены для работы
микроконтроллера от внутреннего задающего генератора. Ничего довешивать не
нужно подал питание, и он работает. Если нужно как-то изменить работу
микроконтроллера, например, заставить его работать от внешнего задающего
генератора, нужно изменить соответствующие фьюзы.
Физически
фьюз биты расположены в 4-х специальных байтах:
— Lock Bit Byte – лок биты для защиты программы
от копирования;
— Fuse Extended Byte – дополнительный байт –
особые функции;
— Fuse High Byte – старший байт;
— Fuse Low Byte – младший байт.
Исторически
так сложилось, что если фьюз равен:
0 – значит, запрограммирован / прошит / активен
1 – значит, НЕ запрограммирован / НЕ прошит / Не активен.
В программе которую я использовал (chipblasterAVR), галочка ставится напротив фьюза,
чтобы его запрограммировать (т.есть присвоить ему 0). А для наглядности
разработчики этой программы в правом окошке написали (на против галочки) — фьюз
«(название)=0». Если к примеру ошибится в программировании фьюзов, можно
лишиться (на время, конечно же) микроконтроллера. Основная и частая ошибка это RSTDSBL – фьюз который заведует выводом RESET. Дело в том, что в AVR вывод RESET можно использовать как порт ввода – вывода (если не
хватает портов), поэтому если по ошибке этот вывод микроконтроллера будет
запрограммирован как порт то, о последующей перепрошивке данного
микроконтроллера по ISP,
последовательными программаторами придется забыть. Для таких случаев (если
собираетесь ошибаться), можно собрать параллельный программатор, или «fusebitdoctor» который у автора уже восстановил
множество «потерянных» AVR микроконтроллеров.
CKSEL – выбор тактового генератора для
микроконтроллера.
Для работы микроконтроллера (как и для любого
процессора) нужны тактовые импульсы. Источником тактового сигнала может быть:
– внутренний RC генератор. Никаких
дополнительных элементов не нужно. Удобно, но RC генератор имеет небольшую
точность работы (вплоть до 10% погрешности) и, кроме того, «плывет» от
температуры. Для некритичных по времени приложений вполне годиться.
– внешний кварцевый (или керамический)
резонатор. Нужен сам резонатор, плюс два конденсатора на 15-30пФ.
Соответственно, будут заняты две ножки микроконтроллера – XLAT1 и XLAT2.
Применяется там, где нужны точные замеры времени или частота работы
микроконтроллера выше, чем может дать внутренний RC генератор.
– ещё можно тактировать микроконтроллер от
внешнего источника тактового сигнала. Это может быть другой микроконтроллер
(для синхронизации работы) или внешняя схема, дающая нужный сигнал. Тактовый
сигнал подается на ножку XLAT1.
WDTON – включает Watch Dog Timer.
Для ответственных приложений, там, где
недопустимо зависание программы (будь то ошибка программы или злостная помеха),
применяют Watch Dog Timer. Это внутренний таймер микроконтроллера, работающий
от своего независимого генератора. При переполнении этого таймера
микроконтроллер сбрасывается и начинает выполнять программу с начала.
Программист должен в тесте программы (обычно в главном цикле) вставить специальную
команду обнуления этого таймера (WDR). Команда периодически выполняется и
обнуляет таймер, не давая ему переполнится. Если микроконтроллер «повис»
перестают выполняться команды обнуления, таймер переполняется и сбрасывает
микроконтроллер.
WDTON = 1 – Watch Dog Timer – отключен (можно
включить программно);
WDTON = 0 – Watch Dog Timer – включен
(программно выключить нельзя).
В обычных приложениях не нужен.
SCKDIV8 – деление тактовой частоты на 8.
Тут все просто:
SCKDIV8= 1 – микроконтроллер работает на частоте
задающего генератора;
SCKDIV8= 0 – микроконтроллер работает на частоте
в 8 раз меньше частоты задающего генератора.
SUT – задает скорость запуска микроконтроллера.
После снятия «сброса» (или подачи питания)
программа, записанная в микроконтроллер, начинает работать не мгновенно.
Микроконтроллер выжидает некоторое время, для того, чтобы нормально запустился
тактовый генератор, установилось напряжение питания и т.д. Время ожидания до
запуска программы и задают биты SUT1…0. Чаще всего нам не критична скорость
запуска, поэтому советую ставить на максимум.
RSTDISBL –разрешает использовать ножку Reset как ещё один порт ввода-вывода. Иногда нужная вещь, но нужно знать что после программирования RSTDISBL
микроконтроллер уже нельзя будет прошить последовательным программатором!
Потому без особой надобности не трогайте его.
RSTDISBL = 1 – ножка сброса работает как сброс;
RSTDISBL = 0 – ножка сброса работает как еще
один порт ввода-вывода, последовательное программирование отключено.
SPIEN –
разрешение на последовательное программирование.
По умолчанию запрограммирован (0) – разрешено
последовательное программирование.
SPIEN = 0 – разрешено последовательное
программирование;
SPIEN = 1 – запрещено последовательное
программирование.
BODLEVEL и BODEN – контроль напряжения питания
микроконтроллера (Brown-out Detector).
Если питание микроконтроллера опуститься к
минимально допустимому или чуть ниже, то работа микроконтроллерабудет
нестабильной. Возможны ошибочные действия, потеря данных, случайное стирание
EEPROM. Микроконтроллер умеет следить за уровнем своего питания (BODEN=0) и
когда оно достигает уровня, который задается битами BODLEVEL, сбрасывается и
держится в ресете пока уровень не поднимется до рабочего уровня. В
некритических приложениях можно не использовать.
SELFPRGEN – бит,
разрешающей программе производить запись в память программ. (AVR
микроконтроллеры могут во время своей работы изменять содержимое области
программ, то есть программировать сам себя).
SELFPRGEN = 1 – изменение области программ запрещено;
SELFPRGEN = 0 – разрешено изменение области
программ.
EESAVE –
защита EEPROM от стирания.
При подаче команды полного стирания
микроконтроллера (обычно осуществляется при каждом программировании кристалла)
стирается и EEPROM. Если Вы хотите чтобы EEPROM оставалось нетронутой –
активируйте этот фьюз. Это актуально если в EEPROM хранятся важные данные.
EESAVE = 1 – стирать EEPROM вместе с Flash;
EESAVE = 0 – оставлять EEPROM при очистке
нетронутым.
Это выдержки из даташита ATtiny13. Ищите его в файлах к статье, и
желательно изучайте.
Выставим фьюзы в нашем (конкретном)
случае, с выдержками из даташита и фотографиями для наглядности и понимания.
Рис.37
Первый у нас сверху CKSEL1, CKSEL0. По ссылке 5, читаем :«The default setting of CKSEL1..0 results in internal RC
Oscillator @ 9.6 MHz. See Table 18-3 on page 118 for details», по умолчанию эти биты настроены на
внутренний RC генератор с частотой 9.6МГц. И
детали настроек можно посмотреть на странице 118 даташита, в таблице 18-3. А
ниже (рис.38-41) показаны все варианты настроек CKSEL1, CKSEL0.
Рис.38
Рис.39
Рис.40
Рис.41
Рис.42
Вот так выглядит настройка CKSEL на работу от внутреннего генератора
с частотой 9.6МГц в чипбластере (слева), и в протеусе (справа), (рис.42).
Следующий фьюз SUT0, SUT1. The default value of SUT1..0 results in
maximum start-up time for the default clock source. See Table 18-3 on page 118
for details.
Выберем его по максимуму 64мс.
(рис.43, 44).
Рис.43
Рис.44
Остальные фьюзы:
CKDIV8 – делить тактовую частоту на 8 нам
не нужно, мы его не трогаем;
WDTON – сторожевой таймер нам не нужен, мы
его не трогаем;
EESAVE – защищать EEPROM от стирания нам тоже ни к чему, оставляем как есть;
RSTDSBL – мы не используем вывод 1
микроконтроллера в качестве порта ввода-вывода, и если не хотим остаться без
микроконтроллера, то его не трогаем;
BODLEVEL – питание у нас будет стабильное
(аккумулятор), этот фьюз нам тоже не нужен, оставляем как есть;
SPMEN – это переименованный SELFPRGEN, из нашей программы мы не залазим в
память программ, поэтому его тоже не трогаем.
Вот что у меня получилось, в
прозрачном корпусе герметизированном термоклеем (рис.47,48), надеюсь, у Вас
получится лучше!
Рис.45
Рис.46
Скачать файлы к статье
Автор: Владислав Калистратов (Vnkdn73@gmail.com)