Рефераты - Афоризмы - Словари
Русские, белорусские и английские сочинения
Русские и белорусские изложения
 

Автоматическое зарядное устройство

Работа из раздела: «Коммуникации, связь, цифровые приборы и радиоэлектроника»

/

Техническое задание к курсовому проекту

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

Управление устройством выполняется с помощью простейшей пяти клавишной клавиатуры, с клавишами: “Установка”, ”+”, “-”, “Задать”, “Режим”. Отображение выполняется на активном однострочном LCD дисплее. При этом выводятся на экран режимы: разряд/заряд, напряжение на аккумуляторе, зарядный ток. Микроконтроллер за счет гибкого управления должен реализовывать ускоренный режим зарядки с экспоненциальным изменением зарядного тока от max до min значения.

В процессе эксплуатации с каждым новым циклом заряда-разряда рабочее вещество внутри аккумулятора постепенно изменяет свою структуру в сторону уменьшения площади активной поверхности, что приводит к уменьшению реальной емкости, для предотвращения этого эффекта предусмотрен режим автоматического разряда аккумулятора, а для предотвращения эффектов сульфации и деградации пластин используется импульсный режим зарядов аккумуляторов.

Введение

Использование микроэлектронных средств в изделиях производственного и культурно-бытового назначения приводит не только к повышению технико-экономических показателей изделия (стоимости, потребляемой мощности, габаритных размеров) и позволяет многократно сократить сроки разработки и отодвинуть сроки «морального старения» изделий, но придает им принципиально новые потребительские качества (расширенные функциональные возможности, модифицируемость, адаптивность и т.д.).

За последние годы микроэлектроники бурное развитие получило направление, связанное с выпуском однокристальных микроконтроллеров (ОМК), которые предназначены для «интеллектуализации» оборудования различного назначения. ОМК представляют собой приборы, конструктивно выполненные в виде БИС, и включающие в себя все составные части «голой» микроЭВМ: микропроцессор, память программы, память данных, также программируемые интерфейсные схемы для связи с внешней средой. Использование микроконтроллеров в системах управления обеспечивает достижение исключительно высоких показателей эффективности при столь низкой стоимости (во многих применениях система может состоять только из одной БИС микроконтроллера), что микроконтроллерам, видимо, нет разумной альтернативной базы для построения управляющих и регулирующих систем. К настоящему времени более двух третей мирового рынка микропроцессорных средств составляют именно ОМК.

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

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

Рис. 1. Функциональная схема разрабатываемого устройства

На рис. 1 Приняты обозначения:

ДТ - датчик температуры, используемый для снятия температурных характеристик с аккумулятора, для определения состояния пригодности.

ДI - датчик тока, используется для измерения силы тока проходящей через аккумулятор, для обеспечения зарядки батареи.

ДU - датчик напряжения, используется для измерения падения напряжения на аккумуляторе, для определения заряда батареи.

БК - блок клавиатуры, включает в себя кнопку перезагрузки микроконтроллера, при ошибке зарядки, кнопка выбора состояния параметра, кнопка изменения параметра, кнопка принятия параметров.

БП - блок питания, обеспечивает питание схемы.

ЖКИ - специализированный жидкокристаллический дисплей, необходимый для отображения параметров работы системы, введённых пользователем.

МК - управляющий микроконтроллер. Он считывает информацию датчиков температуры, напряжения, тока, а также введённые пользователем при помощи клавиатуры параметры. В зависимости от считанной информации микроконтроллер посылает сигналы.

Данная функциональная схема отражает основные элементы необходимые для построения автоматического зарядного устройства. Для определения состояния зарядки аккумулятора используются компаратор 1 и компаратор 2, датчики тока, напряжения и тока.

Далее в зависимости от управляющих команд задаваемых пользователем контроллер выполняет принятие решение о выполнение управляющих действий.

Описание принципиальной схемы

Обоснование выбора микропроцессора.

В начале работы я проанализировал свойства нескольких контроллеров: AVR, PIC, МК-51 и ATmega8. При этом я учитывал, что контроллер должен удовлетворять требованиям к разрабатываемому устройству по следующим параметрам:

· количество портов,

· объем памяти,

· число таймеров,

· реализуемые функции,

· желательно знакомая архитектура.

· Соотношение цены и качества.

Описание МК AVR.

AVR ядро базируется на усовершенствованной RISC архитектуре. Имеется регистровый файл быстрого доступа, который содержит 32 регистра общего назначения. Они непосредственно связанны с арифметико-логическим устройством (ALU), и мощной системой команд. При совершении одного тактового цикла из регистрового файла извлекаются два операнда. При этом выполняется команда, и результат записывается в регистр назначения. Производительность такой высокоэффективной архитектуры почти в десять раз больше, чем стандартные CISC микроконтроллеры.

Описание МК PIC16С745.

Другой микроконтроллер PIC 16С745. У данного контроллера все команды состоят из одного слова (14 бит шириной). Их исполнение происходит за один цикл (200 нс при 20 МГц), исключая команды перехода. Они выполняются за два цикла (400 нс). Имеется прерывание, которое срабатывает от четырех источников, и восьмиуровневый аппаратный стек. Уменьшение общей стоимости системы происходит засчёт высокой нагрузочной способности (25 мА макс. втекающий ток, 20 мА макс. вытекающий ток) линий ввода/вывода, которая упрощает внешние драйверы. Возможна работа с тремя таймерами и каналом I2C.

Описание МК 51.

При создании микроконтроллеров семейства МК-51 используется гарвардская архитектура, при которой память программ (ПЗУ) и память данных (ОЗУ) имеют раздельное адресное пространство. При использовании такой архитектуры для обращения к ячейкам памяти разного типа используются разные типы команд. Объём максимального размера адресного пространства для каждого типа памяти составляет 64 Кбайта. Но только 4 Кбайта ПЗУ и 128 байт ОЗУ располагаются непосредственно на кристалле МК 8051 АН. Существует возможность подключения внешней памяти МК семейства MCS-51 (т. е. архитектура является открытой). Следовательно, память программ и память данных могут быть увеличены посредством подключения дополнительных микросхем памяти, если это необходимо. МК-51 имеет четыре 8-разрядных параллельных порта ввода/вывода и два 16-разрядных программируемых таймера. В отличии от 51 контроллеры 52 серии имеет больший объем ОЗУ, 3 таймера, возможность работы по шине I2C. Это позволяет подключить внешнее ПЗУ и достаточное количество портов (4Ч8).

Описание ATmega8.

Как и все микроконтроллеры AVR фирмы Atmel, микроконтроллеры семейства Mega являются 8 - битными микроконтроллерами, предназначенными для использования во встраиваемых приложениях. Они изготавливаются по малопотребляющей КМОП - технологии, которая в сочетании с усовершенствованной RISC - архитектурой позволяет достичь наилучшего соотношения стоимость/быстродействие/энергопотребление.

Микроконтроллеры описываемого семейства являются наиболее развитыми представителями микроконтроллеров AVR общего применения.

Внутренне данный контроллер полностью функционален, имеет 8 Кб встроенной flash - памяти программ, оперативная память (статическое ОЗУ) объемом 1 Кб, EEPROM - память данных, объемом 512 б, многоканальный 10 - битный АЦП последовательного приближения, имеющий как несимметричные, так и дифференциальные выходы, два 8 - битных (Т0, Т2) и один 16 - битный (Т1) таймер/счетчик. Имеется 3 порта ввода/вывода (порты B, D - 8 - битные, порт С - 7 - битный), 3 канала ШИМ.

Внимательно изучив свойства приведённых выше микроконтроллеров, а также сравнивая их с перечисленными требованиями (которые вытекают из совокупности необходимых параметров для разрабатываемого устройства), я сделал вывод, что наилучшим выбором будет использование ATmega8, так как у него наиболее доступная цена, при этом достаточное количество портов, памяти и функций. Следовательно, с ней мне будет наиболее удобно выполнять курсовую работу.

Выбор элементов схемы

1). Сначала рассмотрим выбор датчика температуры.

Выбирая датчик температуры, я проанализировал существующие аналоговые и цифровые датчики я пришел к выводу, что использование аналогового датчика требует дополнительных элементов: усилителя и АЦП, что заметно усложняет схему, поэтому я предпочел цифровой вариант, в виде чипа DS18B20. Для выполнения моего курсового задания необходима точность +/-1, а эти датчики сертифицированы как измерительные приборы и обеспечивают точность до 0.1. Соответственно, возможно их использование в качестве надёжного средства измерения. При этом не требуется АЦП, так как выполнение операции преобразования полученных данных в цифровой вид ими обеспечивается самостоятельно. Второй важный момент, то что данный датчик может быть подключен по однопроводной сигнальной линии и передает данные по протоколу 1-Wire. 1-Wire -- двунаправленная шина связи для устройств с низкоскоростной передачей данных (обычно 15,4 Кбит/с, максимум 125 Кбит/с), в которой данные и питание передаются по одной линии (то есть всего используются два провода -- один для заземления, а второй для питания и данных; в некоторых случаях используют и отдельный провод питания). Разработана корпорацией Dallas Semiconductor и является её зарегистрированной торговой маркой. Благодаря обеспечению возможности адресного обращения возможно использование одной линии связи для всех датчиков.

Инициализация: сигнал сброса и присутствия

Все сеансы связи микроконтроллера с датчиком DS18B20 начинаются с сигнала сброса. Микроконтроллер на 480 мкс «проваливает» 1-Wire шину в ноль, а затем «отпускает» ее. Если к шине подключен термометр DS18B20, то он обнаруживает положительный перепад и после паузы в 15-60 мкс отвечает микроконтроллеру импульсом присутствия -- «проваливает» шину в ноль на время от 60 до 240 мкс.

Запись данных на 1-Wire шине

Обмен данными по 1-Wire шине происходит последовательно, младшим битом вперед. Передача или прием одного бита данных выполняются в течении фиксированного промежутка времени, так называемого тайм слота. Различают тайм слоты записи и тайм слоты чтения. Длительность всех тайм слотов должна быть > 60 мкс, а пауза между тайм слотами > 1 мкс.

Для передачи нуля микроконтроллер «проваливает» 1-Wire шину на время от 60 до 120 мкс. Затем «отпускает» ее и перед записью следующего бита выдерживает паузу >1 мкс.

Для передачи единицы микроконтроллер «проваливает» 1-Wire шину на время от 1 до 15 мкс, «отпускает» ее и выдерживает паузу. Пауза должна быть такой, чтобы длительность тайм слота была > 60+1 мкс.

Чтение данных на 1-Wire шине

DS18B20 является подчиненным устройством и может передавать данные, только когда микроконтроллер формирует на 1-Wire шине тайм слоты чтения. Для формирования тайм слота чтения микроконтроллер «проваливает» 1-Wire шину на время от 1 до 15 мкс, а затем «отпускает» ее, передавая управление состоянием 1-Wire шины датчику DS18B20. Если DS18B20 передает ноль, он удерживает шину в «проваленном» состоянии (в состоянии логического нуля) до конца тайм слота. Если он передает 1, он оставляет шину в «подтянутом» состоянии.

Микроконтроллер может считывать данные датчика DS18B20 через 15 мкс после начала тайм слота чтения.

Датчик DS18B20 имеет следующие отличительные особенности:

1. Точность ±0.5°C от -10°C до +85°C,

2. Разрешение от 9 до 12 бит, которое настраивается пользователем,

3. Передача данных посредством 1-проводного последовательного интерфейса,

4. 64-битный уникальный и неизменяемый серийный номер,

5. Многоточечное считывание,

6. Рабочее напряжение от 3.0В до 5.5В,

7. Вариант датчика с запиткой с линии данных (DS18B20-PAR),

8. O-92, 150mil 8-контактный SOIC, или 1.98мм x 1.37мм корпус с шариковыми выводами (±2.0°C).

Назначение выводов

Данные в микросхеме DS18B20 считываются через 1-проводную последовательную шину в дополнительном от 9 до 12 битном (программируется пользователем) коде с ценой младшего разряда от 0.5°C до 0.0625°C. Она является термометром с цифровым вводом/выводом, работающим с точностью ±0.5°C.

Если использовать в качестве термостата, то во внутренней энергонезависимой памяти (EEPROM) располагаются программируемые пользователем установки по повышению температуры (TH) и по понижению температуры (TL). Но эти два байта энергонезависимой памяти (EEPROM), зарезервированные для установок, могут быть использованы для энергонезависимого хранения информации общего назначения, если термостатирование не требуется. Я планирую использовать данные регистры для хранения установленного режима и температуры и при выключении.

У каждой микросхемы DS18B20 имеется уникальный и неизменяемый 64-битный серийный номер, используемый как узловой адрес датчика. При этом появляется возможность сосуществовать множеству микросхем DS18B20 на одной 1 проводной шине. Микросхема DS18B20 может быть локально запитана от 3.0В до 5.5В или она может быть сконфигурирована таким образом, чтобы быть запитанной посредством 1-проводной линии данных.

Далее процедура сброса повторяется и теперь для выборки измеренной температуры необходимо передать команду 0xCD после чего передается номер конкретного термометра. А далее посылаем команду Read Scratchpad - BEh. Если не требуется точность 0.1 градуса, то тогда достаточно считать первые два байта. Первый байт содержит знак, если температура « +», то он заполнен 000000000-ми, если «-«, то 11111111-ми. Если температура отрицательна, то значение температуры передается в инверсном дополнительном коде, что требует преобразования температуры.

Для DS18S20 температура представляется в виде 9-битного значения в дополнительном коде. Поскольку это значение занимает 2 байта, все разряды старшего байта равны знаковому разряду. Дискретность представления температуры составляет 0.5°C.

Таблица Зависимость выходного кода от температуры

Температура

Выходной код (Binary)

Выходной код (Hex)

Ст. байт

Мл. байт

+125°C

0000 0000

1111 1010

00FAh

+25°C

0000 0000

0011 0010

0032h

+0.5°C

0000 0000

0000 0001

0001h

0°C

0000 0000

0000 0000

0000h

-0.5°C

1111 1111

1111 1111

FFFFh

-25°C

1111 1111

1100 1110

FFCEh

-55°C

1111 1111

1001 0010

FF92h

2) выбор ЖКИ.

Выбирая ЖК индикатор, я исходил из того, что мне понадобится только вывод текстовой информации. И поэтому остановил свой выбор на МТ10-Т7.

Жидкокристаллический модуль МТ10Т7-7 состоит из БИС контроллера и ЖК панели. Модуль может отображать 10 знакомест (цифр с точкой).

Любой сегмент любого знакоместа можно включать и выключать независимо от остальных сегментов. Структурная схема модуля представлена на рис.3.1. Регистры данных в БИС делятся на две тетрады: SGx(L) и SGx(H). Запись данных в знакоместо производится за два такта: сначала в младшую тетраду, затем в старшую. Младшая тетрада отвечает за сегменты g, e, d, а, а старшая - за сегменты h, b, c, d (см.рис.3.2).

Запись “H” вызывает высвечивание соответствующего сегмента, запись “L” вызывает его гашение.

Контрастность индикатора зависит от напряжения питания модуля. Управление контрастностью производится подключением внешнего резистора на вывод V0.

Квнеш.=0 - MAX контрастность,

Квнеш.= ? ( нет резистора) - MIN контрастность.

Назначение внешних выводов

Наим.

Назначение

1

A0

Выбор адрес/данные: A0-`L''-адрес, A0=“H” данные

2

~WR2

Запись в модуль. Активный уровень “L”.

3

WR1

Запись в модуль. Активный уровень “H”

4

DB3

Шина адреса/данных

5

DB2

Шина адреса/данных

6

DB1

Шина адреса/данных

7

DB0

Шина адреса/данных

8

GND

Общий контакт.Земля.

9

V0

Управление контрастностью.

10

+E

Питание модуля.

11

+L

Не используется

12

-L

Не используется

Описание интерфейса ЖКИ модуля

Сначала на шине выставляется адрес необходимого знакоместа, который фиксируется в регистре адреса при низком уровне на входе АО соответствующим сигналом на входе WRx. Входы WR1 и WR2 защелкивают информацию, стоящую на шине, во внутренних регистрах статического типа. Внутри БИС эти входы объединены по схеме WR1 & WR2. Таким образом, информация запишется только при WR1=“H” и WR2=“L” одновременно. Такое решение позволяет осуществлять функцию CS (выбор кристалла) при большом количестве модулей на шине, или если на шине имеются другие устройства.

При записи адреса знакоместа указатель тетрады сбрасывается в положение SGx(L). Запись данных производится в младшую тетраду при высоком уровне сигнала на входе АО сигналом на входе WRx. По этому - же сигналу указатель тетрады данных переключается в положение SGx(H), сохраняя при этом тот-же адрес знакоместа. Данные в старшую тетраду SGx(H) записываются аналогично младшей тетраде SGx(L). После записи второй тетрады содержимое регистра адреса инкрементируется и можно записывать данные в следующее знакоместо без записи адреса.

По адресу 0Fh расположен триггер блокировки шины. Запись в него DB0=“L” вызывает блокировку записи в БИС адресов и данных на 30 сигналов WRx. Разблокировка шины производится записью DB0=“H” по адресу 0Fh.

После подачи питания содержимое регистров SGx неопределено, поэтому при включении питания необходимо делать программную очистку регистров. Состояние триггера блокировки тоже не определено, поэтому перед началом вывода информации на индикатор необходимо произвести разблокировку шины. Разблокировка шины производится записью DB0=“H” по адресу 0Fh.

Таблица истинности

Сигнал

Запись в регистр адреса

Запись в регистр данных

Хранение

A0

0

1

X

WR2

0

1

0

1

1

X

WR1

1

0

1

0

X

0

DB0-3

Адрес

Данные

X

Описание принципиальной схемы

Для зарядки аккумулятора используется ШИМ, в котором от микроконтроллера подается сигнал включение на транзистор и в зависимости от времени включения регулируется сила тока проходящая через него. В ШИМ использован полевой транзистор с P-каналом. Можно использовать любой подобный, только надо стремиться к тому, чтобы емкость затвора транзистора и сопротивление сток-исток были наименьшими. Фильтр (L1C4) должен обеспечивать приемлемый (небольшой) уровень пульсаций на аккумуляторе. Диоды D2 и D3 - диоды Шоттки, с меньшим падением напряжения на них.

R6, R8, R9, R10, R14, R15 резисторы - делители для нормальной работы АЦП микроконтроллера. При желании эти значения можно переписать под свои коэффициенты, а можно подобрать резисторы. Во время работы, индикатор показывает напряжение и ток в 'условных единицах', измеренных АЦП. Так, напряжение на индикаторе 82 соответствует 0.8 В на аккумуляторе, 190 соответствует 1.85 В. Реальный ток, текущий через аккумулятор (измеряется на R12), умножаем на 10/18 и получаем то, что должно быть на индикаторе. Т.е. подбор резисторов - делителей операционного усилителя сводится к следующему: измеряем напряжение на аккумуляторе, ток через него, подбираем резисторы так, чтобы измеренное соответствовало отображаемому на LCD.

Транзистор Q5 при разрядке периодически подключает аккумулятор к R11. Чем больше емкость аккумулятора, тем большее время за период резистор подключен. В устройстве разделено аналоговое и цифровое питание. АЦП микроконтроллера подключается через фильтр низких частот L2C9. При постоянных мощных пульсациях на аккумуляторе его лучше не исключать из схемы.

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

Для отображения информации используется LСD дисплей МТ10-Т7, подключенный по типовой схеме.

Микроконтроллер анализирует данные получаемые с термометра, нет ли перегрева батареи, если есть, схема выключается. Транзистор Q5 выполняет не только функцию разрядки аккумулятора, но и отключает его в отдельные периоды времени для снятия показаний. Транзисторы Q2, Q3, Q4 используются для предотвращения прохода обратных токов с транзистора Q1, которые повредили бы микропроцессор, т.к. конденсатор у базы транзистора Q1 большей емкости. Компараторы DA2 измеряют ток, текущий через батарею и R12, ток на этом резисторе равен реальному значению, которое потом сравнивается с тем которое на аккумуляторе.

Разработка алгоритма программы

Зарядное устройство позволяет заряжать от одного до шести Ni-Cd, Ni-Mh и Li-Ion аккумуляторов с емкостью от 50 до 1200 мА/час. При зарядке NiMh аккумуляторов выполняются следующие режимы:

1. Фаза определения наличия аккумулятора

2. Фаза определения состояния аккумулятора

3. Разрядка аккумулятора

4. Предзарядка аккумулятора

5. Плавное увеличение тока зарядки

6. Быстрая зарядка

7. Дозарядка

8. Отключение аккумулятора

В фазе определения наличия аккумулятора АЦП микроконтроллера измеряет напряжение на клеммах. Если напряжение меньше ~0.1 В, то зарядка не начинается и на индикатор выдается сообщение об ошибке (возможные ошибки будут описаны позже). Такой способ не совсем удобен, т.к. сильно разряженные (долго не использовавшиеся) аккумуляторы придется вначале немного подзарядить. В фазе определения состояния сперва измеряется температура аккумуляторов. Использование в качестве датчика DS18B20 в пластиковом корпусе позволяет значительно упростить программу и увеличить точность измерений, но приводит к некоторым трудностям при его прилаживании к аккумулятору. Если температура не выходит за пределы допустимой (больше 5 и меньше 40 градусов по Цельсию), через аккумулятор устанавливается ток 0.1*С, где С - емкость аккумулятора. Если напряжение зарядки при этом более 1.85 В, зарядка дальше не происходит, появляется сообщение об ошибке. Такая проверка позволяет определить, что вместо аккумулятора вставили батарейку, которую заряжать не рекомендуется. Этим тестом, фактически, измеряется внутренне сопротивление заряжаемого элемента. Аккумулятор справился, отключается ток, опять измеряется напряжение. Если оно меньше 1 В на банку (в батареи) - переходим в режим дозарядки, в котором этот самый 1В/банка достигается путем зарядки постоянным током 0.2*С. Если напряжение не растет - опять сообщение об ошибке. В предыдущем пункте измерили напряжение, оказалось больше 1.7В/банку или меньше 0.4В/банку - опять ошибка. Последними свойствами обладают старые или испорченные аккумуляторы. Если вдруг все прошло нормально и ошибки не появились, переходим или в разрядку (если установлен такой режим), или в фазу 4 - плавное увеличение тока до 1С. При разрядке аккумуляторы разряжаются на резистор, пока напряжение на каждом не достигнет 1В. Польза - устранения эффекта памяти, которым сильно страдают NiCd, и не очень сильно (по заверениям производителей) NiMh.

NiCd лучше разряжать полностью перед каждой зарядкой, NiMh - один раз за ~5 зарядок. После разрядки фаза 4, в которой, как уже было сказано, ток плавно увеличивается до 1C (опять же для аккумулятора так лучше, чем резко включить полный ток). В устройстве применяется только режим быстрой зарядки, т.е. током около 1С в течение часа. Считается, что после такой зарядки время жизни (количество циклов заряд-разряд) и емкость аккумулятора сохраняются лучше, чем при зарядке током 0.1*C в течение 12 часов. При достижении приблизительно 80% заряда, температура начинает резко повышаться для этого случая в схеме термодатчик. Резкое увеличение температуры является одним из критериев окончания зарядки. Вернемся к фазе быстрой зарядки. Зарядка происходит импульсами, длительностью около 1 сек, чередующимися с короткими (5 мс) интервалами разрядки. На отключенном в перерывах между импульсами аккумуляторе измеряется напряжение и температура. Если что-то выходит за пределы - прекращение зарядки и сообщение об ошибке.

Критериев нормального окончания зарядки 3:

· Уменьшение напряжения на аккумуляторе.

· Увелечение температуры аккумулятора более 40 градусов.

· Скорость роста температуры аккумулятора 1 градус/минуту и более.

Любой из случаев приводит к переходу в режим дозарядки - аккумулятор вначале остывает в течение 10 минут, затем заряжается током 0.1*С в течение еще 20 минут. Этот режим уравнивает аккумуляторы в батарее - полностью зарядившиеся тихонько греются, не очень хорошо зарядившиеся - заряжаются лучше. После этого зарядка закончена и аккумулятор отключается. Номер каждой фазы в такой же последовательности, как в списке, отображается на дисплее (первая цифра).
В режиме быстрой зарядки в течение первых 5 минут аккумулятор непредсказуем, поэтому критерии не проверяются и зарядка может остановиться только аварийно.

Есть более корректный способ определения окончания зарядки - определение уменьшения скорости нарастания напряжения на аккумуляторе, т.е. уменьшение градиента напряжения. Это требует цифровой обработки сигнала и более точного измерения напряжения. Что обеспечивает 10-битный АЦП.

Список ошибок:

1. 'TIME OVER' Истекло время быстрой зарядки (90 минут) и не сработал ни один из критериев окончания зарядки.

2. 'HIGH TEMP' Слишком высокая температура (выше 40 градусов).

3. 'INC TEMP' Температура быстро растет не в режиме быстрой зарядки.

4. 'HI VOLTAGE' Высокое напряжение (более 1.85 В) на одной банке.

5. 'HI RESIST' Высокое внутреннее сопротивление банки.

6. 'CURRENT' Невозможно установить ток, т.е. при увеличении напряжения зарядки до максимума, ток не достиг требуемого значения.

7. 'LO VOLTAGE' Слишком низкое напряжение на аккумуляторе (менее 0.4 В на банку в фазе определения состояния)

8. 'NO U INC' Напряжение при подзарядке не растет

9. 'LO TEMP' Слишком низкая температура (менее 5 градусов)

10. 'NO ACC' Нет аккумуляторов

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

Описание программы

В программе используется определение функций, которые выполняют основную работу микроконтроллера, главная функция main() объединяет их вместе и инициализирует регистры микроконтроллера.

Функция LCDWriteByte() осуществляет вывод символа на ЖК- индикатор, вывод осуществляется за 2 такта сначала младшая часть, затем старшая. Это связано с особенностями строения ЖК - индикатора.

Функция LCDAddress() осуществляет запись адреса символа в ЖК - индикаторе, указывается какой семи - сегментник используется, адрес от 0-9.

Функция LCDInit() осуществляет инициализацию ЖК - индикатора, для этого по адресу 0F в младший разряд записывается 1, что соответствует инициализации шины данных, затем выводятся 0 на все 10 позиций.

Функция LCDPutChar() осуществляет декодирование символа, т.е. переводит в форму восприятия ЖК - индикатора и выводит на экран.

Функция LCDPutsf() выводит строку символов, используя функцию LCDPutChar().

Функции LCDPutUC(), LCDPutUI() выводят значения мощности и силы тока, на экран ЖК - индикатора.

Функция LCDClear() очищает экран ЖК - индикатора, т.е. заполняет его нулями.

Функция StableADC() запускает АЦП и сохраняет значения максимального и минимального напряжения.

Функция ReadADC() начинает преобразование и сохраняет результат пока не поступит прерывание от компаратора.

Функция StartTimer() запускает таймер, для этого устанавливаются соответствующие регистры.

Функция StopTimer() останавливает таймер.

Функция StopPWM() останавливает ШИМ в автономной позиции, при этом тактовый сигнал микроконтроллера синхронизируется с внутренним таймером.

Функция StartPWM() запускает ШИМ.

В функции Battery() выбирается параметр: температуры, напряжения и мощности и в соответствии с ними выполняются преобразования.

Функция Error() выводит ошибки:

1. 'TIME OVER' Истекло время быстрой зарядки (90 минут) и не сработал ни один из критериев окончания зарядки.

2. 'HIGH TEMP' Слишком высокая температура (выше 40 градусов).

3. 'INC TEMP' Температура быстро растет не в режиме быстрой зарядки.

4. 'HI VOLTAGE' Высокое напряжение (более 1.85 В) на одной банке.

5. 'HI RESIST' Высокое внутреннее сопротивление банки.

6. 'CURRENT' Невозможно установить ток, т.е. при увеличении напряжения зарядки до максимума, ток не достиг требуемого значения.

7. 'LO VOLTAGE' Слишком низкое напряжение на аккумуляторе (менее 0.4 В на банку в фазе определения состояния)

8. 'NO U INC' Напряжение при подзарядке не растет

9. 'LO TEMP' Слишком низкая температура (менее 5 градусов)

10. 'NO ACC' Нет аккумуляторов

Функция SetCurrent() устанавливает мощность, подаваемая на батарею.

Функция SendUSART() передает начальное напряжение.

Функция ShowTime() выводит время.

Функция FastChergeNiMH() выполняет быструю зарядку батареи типа NiMH.

Функция FastChergeLiIon() выполняет быструю зарядку батареи типа LiIon.

зарядный устройство микропроцессор датчик

Приложение

Схема устройства

Приложение

Листинг программы

#include <mega8.h>

#include <delay.h>

#asm

.equ __w1_port = 0x18 ;PORTB

.equ __w1_bit = 0

#endasm

/* DS18B20 функциональная библиотека термометра*/

#include <ds18b20.h>

//#define NUMBER 6 // количество аккумуляторов

#define U_ACC_185 190 // 1.85 V

//#define U_ACC_MAX 174 // 1.7 V

#define U_ACC_MAX 180 // 1.7+ V

#define U_ACC_MIN 82 // 0.8 V

#define U_ACC_CRITICAL 41 // 0.4 V

#define C 550 // мощность аккумулятора

#define U_ACC_DISCHARGE 103 // 1 V

#define TEMP_MIN 50 // 5 градусов

#define TEMP_MAX 400 // 40 градусов

#define U_ACC_420 430 // 4.20 V

#define MIN_CURRENT 63 // пороговый ток для текущей LiIon

#define FASTCHARGE_TIME 90 // время быстрой зарядки в минутах

//#define C_CURRENT 70 // 1C мощность

#define RXB8 1 //8-й бит принимаемых данных

#define TXB8 0 //8-й бит передаваемых данных

#define UPE 2 //флаг ошибки контроля честности (если выявлена ошибка в данных //буфера приемника, если есть, то равен 1)

#define OVR 3 //флаг ошибки переполнения

#define FE 4 //флаг ошибки кодирования (при обнаружении равен 1)

#define UDRE 5 //флаг опустошения регистра данных (при пустом буфере //передатчика равен 1)

#define TXC 6 //флаг завершения передачи (после передачи всех битов равен 1)

#define RXC 7 //флаг завершения приема (при наличии не прочитанных данных //равен 1)

//биты регистра управления кнопками

#define BUTTON1 3

#define BUTTON2 4

#define BUTTON3 5

//биты регистра управления LCD

#define DB0 2

#define DB1 3

#define DB2 4

#define DB3 5

#define WR1 6

#define A0 7

#define BIT0 0

#define BIT1 1

#define BIT2 2

#define BIT3 3

#define BIT4 4

#define BIT5 5

#define BIT6 6

#define AS2 3 //установка режима (если 1 - то кварцевый генератор)

#define TOIE2 6 //флаг разрешения прерывания по переполнению таймера/счетчика 2

#define OCIE2 7 //флаг разрешения прерывания по событию «Совпадения» //таймера/счетчика 2

#define TCN2UB 2 //состояние обновления регистра (при записи флаг равен 1)

//биты регистра ADCSRA

#define ADEN 7 //разрешение АЦП (1 - включение)

#define ADSC 6 //запуск преобразования (1 - начать)

#define ADIF 4 //флаг прерывания от компаратора

#define ADIE 3 //разрешение прерывания от компаратора

#define CS10 0 //управление тактовым сигналом (определение источник сигнала

#define CS21 1 // таймера/счетчика)

#define DOT_MT 4

//делители для декодирования символов

#define a 0x08

#define b 0x20

#define c 0x40

#define d 0x04

#define e 0x02

#define f 0x80

#define g 0x01

#define h 0x10

#define VOLTAGE 0xC1

#define CURRENT 0xC0

#define TEMPERATURE 0xC2

#define NiMH 0

#define LiIon 1

#define PRESENCE 0 //наличие

#define QUALIFICATION 1 //ограничение

#define DISCHARGING 2 //разрядка

#define PRECHARGE 3 //заряд

#define RAMP 4 //снизить

#define FASTCHARGE 5 //быстрая зарядка

#define TOPOFFCHARGE 6 //считать верхнее

#define MAINTENANCE 7 //ремонт

#define ERROR 8 //ошибка

#define CHOOSETYPE 9 //выбрать тип

#define CHOOSENUMBER 10 //выбрать количество

#define CHOOSECURRENT 11 //выбрать ток

#define IFDISCHARGE 12 //если разряд

#define STABLECURRENT 13 //стабильный ток

#define STABLEVOLTAGE 14 //стабильное напряжение

//поразрядная дизъюнкция 0^0=0, 1^*=1

flash char Decode[]={

(a|b|c|d|e|f), //0 [0]

(b|c), //1

(a|b|g|e|d), //2

(a|b|c|d|g), //3

(f|g|b|c), //4

(a|f|g|c|d), //5

(a|f|e|d|c|g), //6

(a|b|c), //7

(a|b|c|d|e|f|g), //8

(a|b|c|d|g|f), //9 [9]

(e|f|a|b|c|g), //A [10]

(f|e|d|c|g), //B

(a|f|e|d), //C

(g|e|d|c|b), //D

(a|f|e|d|g), //E

(a|f|e|g), //F

(a|f|g|b|c), //G

(f|e|g|b|c), //H

(c), //I

(b|c|d), //J

(d), //K

(f|e|d), //L

(g), //M

(e|g|c), //N

(c|d|e|g), //O

(a|b|g|f|e), //P

(a|b|g|f|c), //Q

(e|g), //R

(a|f|g|c|d), //S

(f|e|g|d), //T

(f|e|d|c|b), //U

(e|d|c), //V [31]

(0) //SPACE

};

typedef struct

{

unsigned char second; //секунды

unsigned char minute; //минуты

}time; //времени

time t;

int PrevTemp = 0, Temp = 0;

int Voltage=0 , MaxVoltage = 0;

int Uacc[3]={0,0,0};

int Current = 0;

unsigned char STATUS, TYPE, DISCHARGE = 0, POINT;

unsigned int NUMBER = 2;

unsigned int C_CURRENT = 700;

unsigned char DISCHARGE_CURRENT = 0;

void ResetTime() { t.second = 0; t.minute = 0;}

//функция записи символа в LCD

void LCDWriteByte(unsigned char byte)

{

//задается состояние выводов

PORTD&=0xC3; //скопировать в порт D (11000011) //А0=1, WR1=1 режим записи данных в LCD

PORTD|=((byte<<2) & 0x3C); //заносим символ в порт D и в LCD

//3С:00111100

PORTD |= (1<<WR1); //загрузить младший бит в WR1

PORTD &= ~(1<<WR1); //инвертировать и скопировать в порт D

PORTD&=0xC3;

PORTD|=((byte>>2) & 0x3C);

PORTD |= (1<<WR1);

PORTD &= ~(1<<WR1);

}

void LCDAddress(unsigned char address)

{

PORTD &= 0xC3; // скопировать в порт D (11000011)

PORTD |= ((address<<2) & 0x3c); //копируется адрес

PORTD &= ~(1<<A0); //копируем в порт D

PORTD |= (1<<WR1); //загружаем в WR1

PORTD &= ~(1<<WR1);

PORTD |= (1<<A0);

}

//функция инициализации LCD

void LCDInit()

{

unsigned char i;

LCDAddress(0x0F); //установка адреса 0F

LCDWriteByte(0x11); //запись в младший бит 1

LCDAddress(0x00); //запись во все позиции 0

for(i=0; i<=9; i++)

LCDWriteByte(0x00);

}

//функция ввода символа

void LCDPutChar(char byte,char dot)

{

if((byte <= 57)&&(byte >= 48)) byte-=48;

else if((byte>=65)&&(byte<=86)) byte-=55;

byte = Decode[byte]; //декодирование символа

if(dot) byte|=(1<<DOT_MT);

LCDWriteByte(byte); //вывод на ЖКИ

}

//вывод строки символов

void LCDPutsf(flash char *str)

{

char k;

while(k = *str++) {LCDPutChar(k,0);} //посимвольный вывод строки

}

//вывод на монитор значения силы тока

void LCDPutUC(unsigned char uc, unsigned char address)

{

unsigned int i=100;

unsigned char zero_flag=1;

LCDAddress(address); //указываем адрес

if(uc == 0) LCDPutChar(0,0); //если равна 0 то выводим 0

else

do

{

if((uc/i) && zero_flag) zero_flag=0;

if(!zero_flag) LCDPutChar((char)(uc/i+48),0); //иначе выводим значение

uc%=i;

i/=10;

}while(i);

}

//вывод на монитор значения напряжения

void LCDPutUI(unsigned int ui, unsigned char address)

{

unsigned int i = 1000;

unsigned char zero_flag=1;

LCDAddress(address); //указываем адрес

if(ui == 0) LCDPutChar(0,0); //если равна 0 то выводим 0

else

do

{

if((ui/i) && zero_flag) zero_flag=0;

if(!zero_flag) LCDPutChar((char)(ui/i+48),0); //иначе выводим значение

ui%=i;

i/=10;

}while(i);

}

//очистка LCD

void LCDClear()

{

unsigned char i;

LCDAddress(0x00); //адрес 0 сегмента

for(i=0; i<=9; i++)

LCDWriteByte(0x00); //вывод 10 нулей на экран

}

//определение максимума и минимума напряжения

void StableADC()

{

int V[4];

char i;

int Vmax, Vmin;

// выполнять, пока значения АЦП стабильно. (Vmax <= (Vmin+1))

for (Vmax=10,Vmin= 0;Vmax > (Vmin+1);)

{

V[3] = V[2];

V[2] = V[1];

V[1] = V[0];

ADCSRA |= 0x40; // начало нового A/D преобразования

while (!(ADCSRA & (1<<ADIF))) // ожидание готовности АЦП

;

V[0] = ADCW;

Vmin = V[0]; // Vmin низкое напряжение

Vmax = V[0]; // Vmax высокое напряжение

/*сохранить максимальное и минимальное напряжение*/

for (i=0;i<=3;i++)

{

if (V[i] > Vmax) Vmax=V[i];

if (V[i] < Vmin) Vmin=V[i];

}

}

}

// USART приемник обслуживания прерывания

interrupt [USART_RXC] void usart_rx_isr(void)

{

}

// USART передатчик обслуживания прерывания

interrupt [USART_TXC] void usart_tx_isr(void)

{

}

//чтение АЦП

unsigned int ReadADC()

{

unsigned int s = 0;

unsigned char i;

for(i=0; i<=63; i++){

ADCSRA |= (1 << ADSC); //начать преобразования

while((ADCSRA & (1 << ADIF)) == 0); //ожидание прерывания от компаратора

s += ADCW; //сохраняем показания

delay_us(200);

}

ADCSRA |= (1 << ADIF); //копируем первый бит в ADIF

return (s >> 6);

}

//запуск таймера

void StartTimer()

{

TIMSK &= ~(1 << TOIE2);

ASSR |= (1 << AS2);

TCNT2 = 0x00;

TCCR2 = 0x05;

while(ASSR & TCN2UB);

TIMSK |= (1 << TOIE2);

}

//остановка таймера

void StopTimer()

{

TIMSK &= ~(1 << TOIE2);

ASSR |= (1 << AS2);

TCCR2 = 0x00;

while(ASSR & TCN2UB);

TIMSK |= (1 << TOIE2);

}

void StopPWM(void) // останавливает ШИМ в автономной позиции

{

if ((TCCR1B & (1 << CS10))&&(OCR1AL != 0))

{

if (OCR1AL == 1)

{

while(TCNT1 > 2); // ожидание ШИМ == 1

while(TCNT1 < 2); // ожидание ШИМ == 0

}

/*регистр OCR1AL входит в состав блока сравнения. Во время работы таймера/счетчика производится непрерывное сравнение этого регистра с регистром TCNT1 и в случае равенства устанавливается соответствующий флаг*/

else

{

while(TCNT1 > OCR1AL); // ожидание ШИМ == 1

while(OCR1AL > TCNT1); // ожидание ШИМ == 0

}

TCCR1B &= ~(1 << CS10); // включить ШИМ

}

}

//запускает ШИМ

inline void StartPWM(void)

{

TCCR1B |= (1 << CS10);

}

//параметры аккумулятора

unsigned int Battery(unsigned char parameter)

{

switch(parameter)

{

case(TEMPERATURE): //если передан параметр температуры

return ((int)(ds18b20_temperature(0)*10)); //считываем с термометра значение

break;

case(VOLTAGE): //если напряжение

ADMUX = VOLTAGE;

StableADC(); // запускаем АЦП и считываем значения

break;

case(CURRENT): //мощность

ADMUX = CURRENT; //сохраняем

break;

}

return (ReadADC());

}

//вывод ошибки

void Error(unsigned char error)

{

StopTimer(); //останавливаем таймер

if(OCR1AL == 0xFF) OCR1AL = 0x80;

StopPWM(); //останавливает ШИМ

LCDClear(); //очищаем ЖКИ

LCDAddress(0); //устанавливаем адрес равный 0

switch(error) //выбираем ошибку

{

//'TIME OVER' Истекло время быстрой зарядки (90 минут) и не сработал ни один //из критериев окончания зарядки.

//'HIGH TEMP' Слишком высокая температура (выше 40 градусов).

//'INC TEMP' Температура быстро растет не в режиме быстрой зарядки.

//'HI VOLTAGE' Высокое напряжение (более 1.85 В) на одной банке.

//'HI RESIST' Высокое внутреннее сопротивление банки.

//'CURRENT' Невозможно установить ток, т.е. при увеличении напряжения //зарядки до максимума, ток не достиг требуемого значения.

//'LO VOLTAGE' Слишком низкое напряжение на аккумуляторе (менее 0.4 В на //банку в фазе определения состояния)

//'NO U INC' Напряжение при подзарядке не растет

//'LO TEMP' Слишком низкая температура (менее 5 градусов)

//'NO ACC' Нет аккумуляторов

case(1):

LCDPutsf('TIME OVER');

break;

case(2):

LCDPutsf('HIGH TEMP');

break;

case(9):

LCDPutsf('LO TEMP');

break;

case(3):

LCDPutsf('INC TEMP');

break;

case(4):

LCDPutsf('HI VOLTAGE');

break;

case(5):

LCDPutsf('HI RESIST');

break;

case(6):

LCDPutsf('CURRENT');

break;

case(7):

LCDPutsf('LO VOLTAGE');

break;

case(8):

LCDPutsf('NO U INC');

break;

case(10):

LCDPutsf('NO ACC');

break;

}

while(1);

}

//установка тока

int SetCurrent(unsigned int I)

{

unsigned int temp;

do

{

temp = Battery(CURRENT); //заносим значение в батарею

//ожидание окончания

if ((temp < (I - 1))&&(OCR1AL < 0xFF))

{

OCR1AL++;

}

else if (temp > (I + 1))

{

OCR1AL--;

}

//если не возможно установить ток, то вывод ошибки

if(OCR1AL == 0xFF) Error(6);

}while((temp>(I + C_CURRENT/20))||(temp<( I - C_CURRENT/20)));

return (temp);

}

//передача начального напряжения

void SendUSART(int data)

{

unsigned int i = 1000;

do

{

UDR = (data/i) + 48; //регистр данных

while(!(UCSRA & (1 << TXC))); //ожидаем завершения передачи

UCSRA |= (1 << TXC);

data %= i;

i /= 10;

}while (i);

}

//вывод времени

void ShowTime(unsigned int address)

{

LCDAddress(address); //устанавливаем адрес

LCDPutChar(t.minute/10, 0); //выводим минуты

LCDPutChar(t.minute%10, 1);

LCDPutChar(t.second/10, 0); //выводим секунды

LCDPutChar(t.second%10, 0);

}

//режим быстрой зарядки

void FastChargeNiMH()

{

StopTimer(); //останавливаем таймер

StopPWM(); //останавливаем шим

LCDClear(); //очищаем экран

LCDAddress(0); //адрес равен 0

LCDPutChar(STATUS, 0); //выводим статус

switch(STATUS) //проверка значения статуса

{

case PRESENCE: //проценты

if (Battery(VOLTAGE) > 10) STATUS = QUALIFICATION;
//устанавливаем напряжение или выводим ошибку нет аккумулятора

else { LCDAddress(2); LCDPutsf('NO ACC');}

break;

case QUALIFICATION:

Temp = Battery(TEMPERATURE); //температура батареи

if(Battery(TEMPERATURE) < TEMP_MIN) Error(9); //если меньше норм.

if(Battery(TEMPERATURE) > TEMP_MAX) Error(2); //если больше норм.

PrevTemp = Temp;

StartPWM(); //запуск ШИМ

SetCurrent(C_CURRENT/10); //установка тока

if( Battery(VOLTAGE) > U_ACC_185 * NUMBER) Error(5);

StopPWM(); //остановка ШИМа

Voltage = Battery(VOLTAGE); //напряжение батареи

if(Voltage > U_ACC_MAX * NUMBER) Error(4);

if(Voltage < U_ACC_CRITICAL * NUMBER) Error(7);

if(Voltage > U_ACC_DISCHARGE * NUMBER)

{

if(DISCHARGE == 1)

{

OCR1AL = 0x00;

OCR1BL = DISCHARGE_CURRENT; //ток разрядки

STATUS = DISCHARGING; //статус разрядки

}

else STATUS = RAMP; //понизить

}

else if(Voltage < U_ACC_MIN * NUMBER)

{

ResetTime(); //перезапускаем таймер

STATUS = PRECHARGE; //зарядка

}

else STATUS = RAMP;

break;

case DISCHARGING:

delay_ms(10); //задержка

Voltage = Battery(VOLTAGE); //напряжение на батарее

LCDPutUI(Voltage, 2); //установка напряжения

ShowTime(6); //вывод времени

if(Voltage <= U_ACC_DISCHARGE * NUMBER)

{

OCR1BL = 0x00;

STATUS = RAMP;

SetCurrent(C_CURRENT/10); //установка тока

ResetTime(); //сброс времени

break;

}

StartPWM(); //запуск шим

break;

case PRECHARGE:

Voltage = Battery(VOLTAGE); //напряжение батареи

LCDPutUI(Voltage, 3); //вывод напряжения

if(Voltage >= U_ACC_MIN * NUMBER)

{

STATUS = RAMP;

SetCurrent(C_CURRENT/5); //установка напряжения

ResetTime(); //сброс времени

break;

}

if(t.minute >= 30) Error(8); //ошибка напряжение не растет

StartPWM(); //запуск шим

SetCurrent(C_CURRENT/5); //установка напряжения

break;

case RAMP:

StartPWM();

if(!(t.second % 5))OCR1AL++;

ShowTime(6); //вывод времени

Current = Battery(CURRENT); //ток на батарее

LCDPutUI(Current, 2); //вывод на экран

if(Current >= C_CURRENT)

{

ResetTime(); //сброс времени

STATUS = FASTCHARGE; //быстрая зарядка

}

break;

case FASTCHARGE:

//время истекло(90 мин) и окончание зарядки не определено

if(t.minute > FASTCHARGE_TIME) Error(1);

PORTB |= (1 << BIT2);

delay_ms(5); //задержка

PORTB &= ~(1 << BIT2);

Voltage = Battery(VOLTAGE); //напряжение

if(!t.second)

{

delay_ms(1000);

StableADC();

Voltage = Battery(VOLTAGE);

Uacc[0] = Uacc[1];

Uacc[1] = Uacc[2];

Uacc[2] = Voltage;

if(Voltage > U_ACC_MAX * NUMBER) Error(4);

if(t.minute > 5)

{

if(DiffU > (Uacc[0] - 2 * Uacc[1] + Uacc[2])) {STATUS = TOPOFFCHARGE; ResetTime(); break;}

if(Voltage < MaxVoltage) {STATUS = TOPOFFCHARGE; ResetTime(); break;}

Temp = Battery(TEMPERATURE);

if((Temp - PrevTemp) >= 10) {STATUS = TOPOFFCHARGE; ResetTime(); break;}

if(Battery(TEMPERATURE) > TEMP_MAX) {STATUS = TOPOFFCHARGE; ResetTime(); break;}

if(MaxVoltage < Voltage) MaxVoltage = Voltage;

}

SendUSART(Voltage);

}

ShowTime(8);

StartPWM();

Current = SetCurrent(C_CURRENT);

LCDPutUI(Current, 5);

LCDPutUI(Temp/10, 2);

break;

case TOPOFFCHARGE: //считать верх

ShowTime(6);

if(t.minute >= 10)

{

if(t.minute >= 30) {STATUS = MAINTENANCE; break;}

StartPWM();

SetCurrent(C_CURRENT/10);

}

LCDPutUI(Temp/10, 2);

break;

case MAINTENANCE: //ремонт

break;

case ERROR:

break;

}

if(!t.second)

{

Temp = Battery(TEMPERATURE);

if(Battery(TEMPERATURE) < TEMP_MIN) Error(9);

PrevTemp = Temp;

}

StartTimer();

}

void FastChargeLiIon()

{

StopTimer();

LCDClear();

LCDPutUC(STATUS,0);

switch(STATUS)

{

case PRESENCE:

if (Battery(VOLTAGE) > 10) STATUS = STABLECURRENT;

else { LCDAddress(3); LCDPutsf('NO ACC');}

break;

case(STABLECURRENT):

StopPWM();

Voltage = Battery(VOLTAGE);

LCDPutUI(Voltage, 2);

if(Battery(VOLTAGE) >= U_ACC_420)

{

STATUS = STABLEVOLTAGE;

}

StartPWM();

Current = SetCurrent(C_CURRENT);

LCDPutUI(Current, 6);

break;

case(STABLEVOLTAGE):

if(Battery(VOLTAGE) < U_ACC_420 * NUMBER) OCR1AL++;

if(Battery(VOLTAGE) > U_ACC_420 * NUMBER) OCR1AL--;

if(Battery(CURRENT) < MIN_CURRENT) STATUS = MAINTENANCE;

Voltage = Battery(VOLTAGE);

LCDPutUI(Voltage, 2);

Current = Battery(CURRENT);

LCDPutUI(Current, 6);

break;

case(MAINTENANCE):

break;

}

if(!t.second)

{

Temp = Battery(TEMPERATURE);

if(Battery(TEMPERATURE) < TEMP_MIN) Error(9);

if(Battery(TEMPERATURE) > TEMP_MAX) Error(2);

}

StartTimer();

}

void Charge()

{

if(TYPE == NiMH) FastChargeNiMH();

else FastChargeLiIon();

}

// При переполнении Таймера 2, обслуживается прерывание

interrupt [TIM2_OVF] void timer2_ovf_isr(void)

{

t.second++;

if(t.second == 60) { t.second = 0; t.minute++; }

Charge();

}

void main(void)

{

OSCCAL = 0xAA; //устанавливается частота RC генератора

PORTB=0x00;

DDRB=0x06;

PORTC=0x38;

DDRC=0x00;

PORTD=0xBC;

DDRD=0xFC;

MCUCR=0x00;

// инициализируем таймер/счетчик 1

// Часы источник: системное время

// Значение часов: 8000,000 kHz

// Режим: быстрого верхнего ШИМ=00FFh

// OC1A выхода: Non-Inv.

// OC1B выхода: Non-Inv.

TCCR1A=0xA1;

TCCR1B=0x08;

TCNT1H=0x00;

TCNT1L=0x00;

OCR1AH=0x00;

OCR1AL=0x00;

OCR1BH=0x00;

OCR1BL=0x00;

// инициализация USART

// параметры связи: 8 Data, 1 Stop, не обинаковы

// USART приемник: On

// USART передатчик: On

// USART режим: асинхронный

// USART скорость передачи данных: 9600

UCSRA=0x00;

//UCSRB=0xD8;

UCSRB=0x18; // нет прерывания

UCSRC=0x86;

UBRRH=0x00;

UBRRL=0x33;

ACSR=0x80;

SFIOR=0x00;

TIMSK &= ~(1 << TOIE2);

ASSR |= (1 << AS2);

TCNT2 = 0x00;

TCCR2 = 0x00;

while(ASSR & TCN2UB);

TIMSK |= (1 << TOIE2);

// инициализация АЦП

// тактовая частота АЦП: 125,000 kHz

// опорное напряжение АЦП: Int., cap. on AREF

ADMUX = 0xC0;

ADCSRA = 0x86;

delay_ms(2000); //ожидание стабилизации МК

#asm('sei')

LCDInit();

ResetTime();

STATUS = CHOOSETYPE;

while (1)

{

if(!(PINC & (1 << BUTTON1)))

{

delay_ms(100);

if(!(PINC & (1 << BUTTON1)))

{

if(STATUS == IFDISCHARGE) STATUS = CHOOSETYPE;

else STATUS++;

}

}

if(!(PINC & (1 << BUTTON2)))

{

delay_ms(100);

if(!(PINC & (1 << BUTTON2)))

{

switch(STATUS)

{

case(CHOOSETYPE):

if(TYPE == NiMH) TYPE = LiIon;

else TYPE = NiMH;

break;

case(CHOOSENUMBER):

if(NUMBER == 6) NUMBER = 1;

else NUMBER++;

break;

case(CHOOSECURRENT):

if(C_CURRENT == 1200) C_CURRENT = 50;

else C_CURRENT += 50;

break;

case(IFDISCHARGE):

if(DISCHARGE == 0) DISCHARGE = 1;

else DISCHARGE = 0;

break;

}

}

}

if(!(PINC & (1 << BUTTON3)))

{

delay_ms(100);

if(!(PINC & (1 << BUTTON3)))

{

Temp = Battery(TEMPERATURE);

if(Temp > TEMP_MAX) Error(2);

if(Temp < TEMP_MIN) Error(9);

C_CURRENT = C_CURRENT * 10 / 18;

DISCHARGE_CURRENT = 0xFF / NUMBER;

STATUS = PRESENCE;

StartTimer();

while(1);

}

}

LCDClear();

LCDAddress(0);

if(STATUS == CHOOSETYPE) POINT = 1;

else POINT = 0;

if(TYPE == NiMH) LCDPutChar('N', POINT);

else LCDPutChar('L', POINT);

LCDPutChar('I', 0);

if(STATUS == CHOOSENUMBER) POINT = 1;

else POINT = 0;

LCDAddress(3);

LCDPutChar(NUMBER + 48, POINT);

if(STATUS == CHOOSECURRENT) POINT = 1;

else POINT = 0;

LCDPutUI(C_CURRENT/10, 5);

LCDPutChar('0',POINT);

if(STATUS == IFDISCHARGE) POINT = 1;

else POINT = 0;

LCDAddress(9);

if(DISCHARGE == 1) LCDPutChar('1', POINT);

else LCDPutChar('I',POINT);

delay_ms(50);

};

}

ref.by 2006—2019
contextus@mail.ru