Температура
|
Выходной код (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 - диоды Шоттки, с меньшим
падением напряжения на них., 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. Фаза определения состояния аккумулятора
. Разрядка аккумулятора
. Предзарядка аккумулятора
. Плавное увеличение тока зарядки
. Быстрая зарядка
. Дозарядка
. Отключение аккумулятора
В фазе определения наличия аккумулятора АЦП микроконтроллера измеряет
напряжение на клеммах. Если напряжение меньше ~0.1 В, то зарядка не начинается
и на индикатор выдается сообщение об ошибке (возможные ошибки будут описаны
позже). Такой способ не совсем удобен, т.к. сильно разряженные (долго не
использовавшиеся) аккумуляторы придется вначале немного подзарядить. В фазе
определения состояния сперва измеряется температура аккумуляторов.
Использование в качестве датчика DS18B20 в пластиковом корпусе позволяет
значительно упростить программу и увеличить точность измерений, но приводит к
некоторым трудностям при его прилаживании к аккумулятору. Если температура не
выходит за пределы допустимой (больше 5 и меньше 40 градусов по Цельсию), через
аккумулятор устанавливается ток 0.1*С, где С - емкость аккумулятора. Если
напряжение зарядки при этом более 1.85 В, зарядка дальше не происходит,
появляется сообщение об ошибке. Такая проверка позволяет определить, что вместо
аккумулятора вставили батарейку, которую заряжать не рекомендуется. Этим тестом,
фактически, измеряется внутренне сопротивление заряжаемого элемента.
Аккумулятор справился, отключается ток, опять измеряется напряжение. Если оно
меньше 1 В на банку (в батареи) - переходим в режим дозарядки, в котором этот
самый 1В/банка достигается путем зарядки постоянным током 0.2*С. Если
напряжение не растет - опять сообщение об ошибке. В предыдущем пункте измерили
напряжение, оказалось больше 1.7В/банку или меньше 0.4В/банку - опять ошибка.
Последними свойствами обладают старые или испорченные аккумуляторы. Если вдруг
все прошло нормально и ошибки не появились, переходим или в разрядку (если
установлен такой режим), или в фазу 4 - плавное увеличение тока до 1С. При
разрядке аккумуляторы разряжаются на резистор, пока напряжение на каждом не достигнет
1В. Польза - устранения эффекта памяти, которым сильно страдают NiCd, и не
очень сильно (по заверениям производителей) NiMh.лучше разряжать полностью
перед каждой зарядкой, 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
градусов).
. "INC TEMP" Температура быстро растет не в режиме
быстрой зарядки.
. "HI VOLTAGE" Высокое напряжение (более 1.85 В) на
одной банке.
. "HI RESIST" Высокое внутреннее сопротивление банки.
. "CURRENT" Невозможно установить ток, т.е. при
увеличении напряжения зарядки до максимума, ток не достиг требуемого значения.
. "LO VOLTAGE" Слишком низкое напряжение на аккумуляторе
(менее 0.4 В на банку в фазе определения состояния)
. "NO U INC" Напряжение при подзарядке не растет
. "LO TEMP" Слишком низкая температура (менее 5
градусов)
. "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
градусов).
. "INC TEMP" Температура быстро растет не в режиме
быстрой зарядки.
. "HI VOLTAGE" Высокое напряжение (более 1.85 В) на
одной банке.
. "HI RESIST" Высокое внутреннее сопротивление банки.
. "CURRENT" Невозможно установить ток, т.е. при
увеличении напряжения зарядки до максимума, ток не достиг требуемого значения.
. "LO VOLTAGE" Слишком низкое напряжение на аккумуляторе
(менее 0.4 В на банку в фазе определения состояния)
. "NO U INC" Напряжение при подзарядке не растет
. "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^*=1char 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|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
};
struct
{char second; //секундыchar minute; //минуты
}time; //времени
t;PrevTemp = 0, Temp = 0;Voltage=0 , MaxVoltage =
0;Uacc[3]={0,0,0};Current = 0;char STATUS, TYPE, DISCHARGE = 0, POINT;int
NUMBER = 2;int C_CURRENT = 700;char DISCHARGE_CURRENT = 0;
ResetTime() { t.second = 0; t.minute = 0;}
//функция записи
символа в LCDLCDWriteByte(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;|=((byte>>2) & 0x3C);|=
(1<<WR1);&= ~(1<<WR1);
}
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()
{char i;(0x0F); //установка адреса 0F(0x11); //запись
в младший бит 1
LCDAddress(0x00); //запись
во все позиции 0
for(i=0; i<=9; i++)(0x00);
}
//функция ввода символаLCDPutChar(char byte,char dot)
{((byte <= 57)&&(byte >= 48))
byte-=48;if((byte>=65)&&(byte<=86)) byte-=55;= Decode[byte]; //декодирование символа(dot) byte|=(1<<DOT_MT);(byte); //вывод на ЖКИ
}
//вывод строки
символовLCDPutsf(flash char *str)
{k;(k = *str++) {LCDPutChar(k,0);} //посимвольный вывод строки
}
//вывод на монитор значения силы тока
void LCDPutUC(unsigned char uc, unsigned char address)
{int i=100;char zero_flag=1;(address); //указываем
адрес
if(uc == 0) LCDPutChar(0,0); //если равна 0 то выводим 0
else
{((uc/i) && zero_flag) zero_flag=0;(!zero_flag)
LCDPutChar((char)(uc/i+48),0); //иначе выводим значение%=i;/=10;
}while(i);
}
//вывод на монитор значения напряженияLCDPutUI(unsigned int ui, unsigned
char address)
{int i = 1000;char zero_flag=1;(address);
//указываем адрес
if(ui == 0) LCDPutChar(0,0); //если равна 0 то
выводим 0
else
{((ui/i) && zero_flag) zero_flag=0;(!zero_flag)
LCDPutChar((char)(ui/i+48),0); //иначе выводим значение%=i;/=10;
}while(i);
}
//очистка LCDLCDClear()
{char i;(0x00); //адрес 0 сегмента(i=0; i<=9; i++)(0x00); //вывод 10
нулей на экран
}
//определение максимума и минимума напряжения
void StableADC()
{V[4];i;Vmax, Vmin;
// выполнять, пока значения АЦП стабильно. (Vmax <= (Vmin+1))(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++)
{(V[i] > Vmax) Vmax=V[i];(V[i] < Vmin) Vmin=V[i];
}
}
}
// USART приемник обслуживания прерывания[USART_RXC] void usart_rx_isr(void)
{
}
// USART передатчик обслуживания прерывания[USART_TXC] void usart_tx_isr(void)
{
}
//чтение АЦПint ReadADC()
{int s = 0;char i;
(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);
}
//запуск таймераStartTimer()
{&= ~(1 << TOIE2);|= (1 << AS2);= 0x00;=
0x05;(ASSR & TCN2UB);|= (1 << TOIE2);
}
//остановка таймераStopTimer()
{&= ~(1 << TOIE2);|= (1 << AS2);= 0x00;(ASSR
& TCN2UB);|= (1 << TOIE2);
}
void StopPWM(void) // останавливает ШИМ в автономной
позиции
{((TCCR1B & (1 << CS10))&&(OCR1AL != 0))
{(OCR1AL == 1)
{(TCNT1 > 2); // ожидание ШИМ == 1(TCNT1 < 2); // ожидание ШИМ == 0
}
/*регистр OCR1AL входит в состав блока сравнения. Во
время работы таймера/счетчика производится непрерывное сравнение этого регистра
с регистром TCNT1 и в случае равенства
устанавливается соответствующий флаг*/
else
{
while(TCNT1 > OCR1AL);
// ожидание ШИМ == 1
while(OCR1AL > TCNT1);
// ожидание ШИМ == 0
}
TCCR1B &= ~(1 << CS10); // включить ШИМ
}
}
//запускает ШИМ
inline void StartPWM(void)
{B |= (1 << CS10);
}
//параметры аккумулятораint Battery(unsigned char parameter)
{(parameter)
{(TEMPERATURE): //если передан параметр температуры((int)(ds18b20_temperature(0)*10)); //считываем с термометра значение;(VOLTAGE): //если напряжение= VOLTAGE;(); //
запускаем АЦП и считываем значения
break;(CURRENT): //мощность= CURRENT; //сохраняем;
}
(ReadADC());
}
//вывод ошибкиError(unsigned char error)
{(); //останавливаем таймер(OCR1AL == 0xFF) OCR1AL =
0x80;(); //останавливает ШИМ(); //очищаем
ЖКИ(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" Нет аккумуляторов(1):("TIME
OVER");;(2):("HIGH TEMP");;(9):("LO
TEMP");;(3):("INC TEMP");;(4):("HI
VOLTAGE");;(5):("HI RESIST");;(6):("CURRENT");;(7):("LO
VOLTAGE");;(8):("NO U INC");;(10):("NO ACC");;
}(1);
}
//установка токаSetCurrent(unsigned int I)
{int temp;
{= Battery(CURRENT); //заносим значение в батарею
//ожидание окончания
if ((temp < (I - 1))&&(OCR1AL < 0xFF))
{AL++;
}if (temp > (I + 1))
{
OCR1AL--;
}
//если не возможно установить ток, то вывод ошибки
if(OCR1AL == 0xFF) Error(6);
}while((temp>(I + C_CURRENT/20))||(temp<( I -
C_CURRENT/20)));(temp);
}
//передача начального напряженияSendUSART(int data)
{int i = 1000;
{
UDR =
(data/i) + 48; //регистр данных
while(!(UCSRA & (1 << TXC))); //ожидаем
завершения передачи
UCSRA |= (1 << TXC);%= i;/= 10;
}while (i);
}
//вывод времениShowTime(unsigned int address)
{(address); //устанавливаем адрес(t.minute/10, 0); //выводим минуты(t.minute%10,
1);(t.second/10, 0); //выводим
секунды(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");}
;QUALIFICATION:= Battery(TEMPERATURE); //температура батареи(Battery(TEMPERATURE) < TEMP_MIN) Error(9); //если меньше норм.(Battery(TEMPERATURE) > TEMP_MAX)
Error(2); //если больше
норм.= Temp;
(); //запуск ШИМ(C_CURRENT/10); //установка тока( Battery(VOLTAGE) > U_ACC_185 * NUMBER) Error(5);(); //остановка ШИМа= Battery(VOLTAGE); //напряжение батареи(Voltage > U_ACC_MAX *
NUMBER) Error(4);(Voltage < U_ACC_CRITICAL * NUMBER) Error(7);(Voltage >
U_ACC_DISCHARGE * NUMBER)
{(DISCHARGE == 1)
{AL = 0x00;BL = DISCHARGE_CURRENT; //ток разрядки=
DISCHARGING; //статус разрядки
}STATUS = RAMP; //понизить
}if(Voltage < U_ACC_MIN * NUMBER)
{(); //перезапускаем таймер= PRECHARGE; //зарядка
}STATUS = RAMP;;DISCHARGING:_ms(10); //задержка= Battery(VOLTAGE); //напряжение на батарее(Voltage, 2); //установка напряжения
ShowTime(6); //вывод времени
if(Voltage <= U_ACC_DISCHARGE * NUMBER)
{BL = 0x00;= RAMP;(C_CURRENT/10); //установка тока(); //сброс времени;
}(); //запуск шим;PRECHARGE:=
Battery(VOLTAGE); //напряжение батареи(Voltage, 3); //вывод напряжения(Voltage >= U_ACC_MIN * NUMBER)
{= RAMP;(C_CURRENT/5); //установка напряжения(); //сброс времени
break;
}
if(t.minute >= 30) Error(8); //ошибка напряжение не растет
StartPWM(); //запуск шим
SetCurrent(C_CURRENT/5); //установка напряжения
break;RAMP:();(!(t.second % 5))OCR1AL++;(6); //вывод времени=
Battery(CURRENT); //ток на батарее(Current, 2); //вывод на экран(Current >= C_CURRENT)
{(); //сброс времени=
FASTCHARGE; //быстрая зарядка
}
break;
case FASTCHARGE:
//время истекло(90 мин) и окончание зарядки не определено
if(t.minute > FASTCHARGE_TIME) Error(1);|= (1 <<
BIT2);_ms(5); //задержка&= ~(1 << BIT2);= Battery(VOLTAGE); //напряжение(!t.second)
{_ms(1000);();= Battery(VOLTAGE);[0] = Uacc[1];[1] =
Uacc[2];[2] = Voltage;(Voltage > U_ACC_MAX * NUMBER) Error(4);(t.minute >
5)
{(DiffU > (Uacc[0] - 2 * Uacc[1] + Uacc[2])) {STATUS =
TOPOFFCHARGE; ResetTime(); break;}(Voltage < MaxVoltage) {STATUS =
TOPOFFCHARGE; ResetTime(); break;}= Battery(TEMPERATURE);((Temp - PrevTemp)
>= 10) {STATUS = TOPOFFCHARGE; ResetTime(); break;}(Battery(TEMPERATURE)
> TEMP_MAX) {STATUS = TOPOFFCHARGE; ResetTime(); break;}(MaxVoltage <
Voltage) MaxVoltage = Voltage;
}(Voltage);
}(8);();= SetCurrent(C_CURRENT);(Current, 5);(Temp/10,
2);;TOPOFFCHARGE: //считать верх(6);(t.minute >= 10)
{(t.minute >= 30) {STATUS = MAINTENANCE;
break;}();(C_CURRENT/10);
}(Temp/10, 2);;MAINTENANCE: //ремонт;ERROR:;
}(!t.second)
{= Battery(TEMPERATURE);(Battery(TEMPERATURE) < TEMP_MIN)
Error(9);= Temp;
}
();
}
FastChargeLiIon()
{();();(STATUS,0);(STATUS)
{PRESENCE:(Battery(VOLTAGE) > 10) STATUS = STABLECURRENT;{
LCDAddress(3); LCDPutsf("NO ACC");};(STABLECURRENT):();=
Battery(VOLTAGE);(Voltage, 2);(Battery(VOLTAGE) >= U_ACC_420)
{= STABLEVOLTAGE;
}();= SetCurrent(C_CURRENT);(Current,
6);;(STABLEVOLTAGE):(Battery(VOLTAGE) < U_ACC_420 * NUMBER)
OCR1AL++;(Battery(VOLTAGE) > U_ACC_420 * NUMBER) OCR1AL--;(Battery(CURRENT)
< MIN_CURRENT) STATUS = MAINTENANCE;= Battery(VOLTAGE);(Voltage, 2);=
Battery(CURRENT);(Current, 6);;(MAINTENANCE):
;
}(!t.second)
{= Battery(TEMPERATURE);(Battery(TEMPERATURE) < TEMP_MIN)
Error(9);(Battery(TEMPERATURE) > TEMP_MAX) Error(2);
}();
}
Charge()
{(TYPE == NiMH) FastChargeNiMH(); FastChargeLiIon();
}
// При переполнении Таймера 2, обслуживается прерывание
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{.second++;(t.second == 60) { t.second = 0; t.minute++; }();
}
main(void)
{
= 0xAA; //устанавливается частота RC генератора=0x00;=0x06;=0x38;=0x00;=0xBC;=0xFC;
=0x00;
// инициализируем таймер/счетчик 1
// Часы источник: системное время
// Значение часов: 8000,000 kHz
// Режим: быстрого верхнего ШИМ=00FFh
// OC1A выхода: Non-Inv.
// OC1B выхода:
Non-Inv.A=0xA1;B=0x08;H=0x00;L=0x00;AH=0x00;AL=0x00;BH=0x00;1BL=0x00;
// инициализация USART
// параметры связи: 8 Data,
1 Stop, не обинаковы
// USART приемник: On
// USART передатчик: On
// USART режим: асинхронный
// USART скорость передачи данных: 9600
UCSRA=0x00;
//UCSRB=0xD8;
UCSRB=0x18; // нет прерывания
UCSRC=0x86;=0x00;=0x33;
=0x80;=0x00;
&= ~(1 << TOIE2);|= (1 << AS2);= 0x00;=
0x00;(ASSR & TCN2UB);|= (1 << TOIE2);
// инициализация АЦП
// тактовая частота АЦП: 125,000 kHz
// опорное напряжение АЦП: Int., cap. on AREF
ADMUX
= 0xC0;
ADCSRA
= 0x86;
delay_ms(2000); //ожидание стабилизации МК
#asm("sei")
();();= CHOOSETYPE;
(1)
{(!(PINC & (1 << BUTTON1)))
{_ms(100);(!(PINC & (1 << BUTTON1)))
{(STATUS == IFDISCHARGE) STATUS = CHOOSETYPE;STATUS++;
}
}(!(PINC & (1 << BUTTON2)))
{_ms(100);(!(PINC & (1 << BUTTON2)))
{(STATUS)
{(CHOOSETYPE):(TYPE == NiMH) TYPE = LiIon;TYPE =
NiMH;;(CHOOSENUMBER):(NUMBER == 6) NUMBER =
1;NUMBER++;;(CHOOSECURRENT):(C_CURRENT == 1200) C_CURRENT = 50;C_CURRENT +=
50;;(IFDISCHARGE):(DISCHARGE == 0) DISCHARGE = 1;DISCHARGE = 0;;
}
}
}(!(PINC & (1 << BUTTON3)))
{_ms(100);(!(PINC & (1 << BUTTON3)))
{= Battery(TEMPERATURE);(Temp > TEMP_MAX) Error(2);(Temp
< TEMP_MIN) Error(9);_CURRENT = C_CURRENT * 10 / 18;_CURRENT = 0xFF /
NUMBER;= PRESENCE;();(1);
}
}();(0);(STATUS == CHOOSETYPE) POINT = 1;POINT = 0;(TYPE ==
NiMH) LCDPutChar('N', POINT);LCDPutChar('L', POINT);('I', 0);
(STATUS == CHOOSENUMBER) POINT = 1;POINT = 0;(3);(NUMBER +
48, POINT);
(STATUS == CHOOSECURRENT) POINT = 1;POINT = 0;(C_CURRENT/10,
5);('0',POINT);
(STATUS == IFDISCHARGE) POINT = 1;POINT = 0;(9);(DISCHARGE ==
1) LCDPutChar('1', POINT);LCDPutChar('I',POINT);_ms(50);
};
}