Введение.
Счётчик электрической энергии (электрический счётчик) — прибор для измерения расхода электроэнергии. По своей конструкции электросчетчик может быть электромеханическим и электронным. В электромеханическом счетчике магнитное поле неподвижных токопроводящих катушек влияет на подвижный элемент из проводящего материала. Подвижный элемент представляет собой диск, по которому протекают токи, индуцированные магнитным полем катушек. Количество оборотов диска в этом случае прямо пропорционально потребленной электроэнергии. Механические счётчики электроэнергии постоянно вытесняются с рынка электронными счетчиками из-за отдельных недостатков: отсутствие дистанционного автоматического снятия показаний, однотарифность, погрешности учёта, плохая защита от краж электроэнергии. Электронным называется электросчетчик, в котором переменный ток и напряжение воздействуют на твердотельные (электронные) элементы для создания на выходе импульсов, число которых пропорционально измеряемой активной энергии. Счетный механизм представляет собой электромеханическое (имеет преимущество в областях с холодным климатом, при условии установки прибора на улице) или электронное устройство, содержащее как запоминающее устройство, так и дисплей.
Важной особенностью электронного счетчика является наличие специального выхода для подключения внешних устройств контроля. Более дорогие модели позволяют получать хранимую в электросчетчике информацию непосредственно с компьютера. Однако большинство бытовых электронных счетчиков имеет обычный импульсный выход, электрически изолированный от измеряемого напряжения.
Как правило, такие выходы остаются без использования, так как без использования дополнительных устройств подключение к этому сигналу не имеет смысла. Необходимо устройство, которое будет производить подсчет передаваемых электросчетчиком импульсов. После продолжительного поиска в сети Интернет нам не удалось обнаружить простых устройств, позволяющих дистанционно считывать показания с электросчетчика.
Было принято решение разработать и изготовить подобное устройство самостоятельно, а дополнительно снабдить его еще несколькими полезными функциями.
Цель работы: разработать и изготовить прибор, позволяющий произвести запись количества потребленной электроэнергии в течение каждого часа и выводящий эту информацию визуально в виде графика, а также использовать его в качестве «удлинителя» циферблата электросчетчика.
Методы:
- теоретический анализ литературы по данной проблеме;
- эксперимент, наблюдение;
- разработка и сборка счетчика-анализатора;
- разработка программного обеспечения.
Задачи:
Изучить устройство и принципы работы электросчетчиков, определить формат передаваемых им данных.
Разработать принципиальную электрическую схему счетчика-анализатора.
Разработать и изготовить печатные платы для счетчика.
Определить способы и формат обмена данными с персональным компьютером.
Разработанное и изготовленное устройство подключается к импульсному выходу бытового электросчетчика и позволяет фиксировать общее количество потребленной энергии с точностью до 0,001 кВт*ч, при том, что точность циферблата на самом счетчике всего 0,1 кВт*ч. Эта функция позволяет использовать прибор в качестве «удлинителя» для электросчетчика, установленного в неудобном месте. Также устройство записывает количество энергии, потребленной в течение каждого часа в энергонезависимую память и способно передавать эти данные в персональный компьютер для дальнейшей обработки и анализа. Дополнительно прибор может отслеживать выход объема потребляемой энергии за указанные границы и подавать сигнал об этом, включая внешние реле.
Устройство прибора удобно рассматривать по его структурной схеме, приведенной на рисунке 1.
Работой прибора управляет центральный процессор, задачей которого является фиксация импульсов, приходящих от электросчетчика, пересчет их в кВт*ч и увеличение общего счетчика энергии в соответствии с пришедшей информацией. Начальное значение счетчика в приборе устанавливается при первом подключении прибора вместе с текущими временем и датой с помощью подключения к компьютеру. Кроме этого, также задается коэффициент, показывающий сколько импульсов передается на 1 кВт*ч, зависящий от модели электросчетчика. Далее электросчетчик и счетчик-анализатор начинают работать параллельно и очень важно, чтобы все импульсы, приходящие от электросчетчика, были учтены. Проблемы могут возникнуть в случае отключения питания прибора и тогда значения на циферблате электросчетчика и дисплее нашего прибора будут различаться. Чтобы этого избежать, каждое изменение количества потребленной энергии ЦПУ сохраняет в ячейках энергонезависимой памяти с быстрым доступом. Для обеспечения сохранности этой информации в схему добавлена встроенная батарея, также использующаяся для питания часов.
Рис. 1. Структурная схема устройства.
При возобновлении питания прибора последние сохраненные данные восстанавливаются из памяти, а работа продолжается без потери данных.
На ЖК-дисплее отображаются текущее значение энергии, дата и время. По окончании каждого часа значение энергии, потраченное за последний час, сохраняется в постоянной энергонезависимой памяти вместе с информацией о дате и времени. Далее эта информация передается в компьютер и может быть использована для изучения и анализа потребления электроэнергии в разрезе часа или суток.
С помощью клавиатуры можно переключать режимы работы устройства.
Принципиальная схема прибора показана на рисунке 2.
Рис. 2. Принципиальная схема счетчика-анализатора.
В качестве ЦПУ используется микроконтроллер IC1 AT89C2051-24PI, работающий на частоте 22,1184 МГц, стабилизированной кварцевым резонатором ZQ1. Такая частота была выбрана для возможности обмена последовательными данными с компьютером на скорости до 115200 бод. Цепь на элементах R1, VD1 и C3 производит сброс микроконтроллера в начальное состояние при подаче питания. Сигнал с электросчетчика подается непосредственно на вывод 6 микроконтроллера.
Микросхема IC3 представляет собой часы реального времени, точность которых стабилизируется кварцевым резонатором ZQ2, а за счет батарейки BAT1 часы будут идти даже при отсутствии основного питания. Кроме часов в микросхеме имеется 48 ячеек быстрой энергонезависимой памяти, которую мы используем для хранения промежуточных результатов.
В качестве постоянной энергонезависимой памяти использована микросхема IC2 объемом 32 килобайта. Такого объема достаточно чтобы хранить без потерь до 1,5 лет информации о потребленной электроэнергии. Далее старые данные будут постепенно затираться более новыми.
Светодиод VD2 добавлен для индикации работы устройства. При каждом импульсе, пришедшем с электросчетчика светодиод меняет свое состояние на противоположное. По частоте мигания VD2 можно визуально оценить частоту приходящих импульсов, а значит, и текущую нагрузку на электросеть.
Многооборотный подстроечный резистор R2 используется для настройки контрастности ЖК-дисплея. Резисторная сборка RP1 используется для подтягивания напряжения на выходах микроконтроллера к источнику питания для получения стабильных логических уровней. Резисторы R8 и R9 добавлены в схему для согласования уровней при подключении преобразователя USB-Serial для осуществления обмена данными с компьютером.
На диодах VD3-VD6 и кнопках SW1-SW4 собрана матричная клавиатура. Сигнал опроса кнопок, появляющийся по очереди на выводах 12-15 микроконтроллера в случае нажатия кнопок подается на вывод 7 и так вычисляется какая из кнопок была нажата.
Транзисторы VT1 и VT2 используются в качестве выходов с открытым коллектором для управления внешними устройствами подачи сигналов при наступлении заранее заданных условий.
Прибор питается от внешнего стабилизированного источника напряжением 5 вольт.
Конструкция. Устройство собрано на печатной плате, разработанной в компьютерной программе Sprint Layout. Рисунок печатной платы был распечатан на лазерном принтере и перенесен на стеклотекстолит с помощью ламинатора (фото 1).
Фото 1. Печатная плата счетчика-анализатора.
Микропроцессор и микросхема IC2 установлены в панели для возможности перепрограммирования или чтения информации при необходимости. Также панель установлена для батарейки BAT1. На фото 2 представлено устройство в сборе.
Фото 2. Счетчик-анализатор потребленной электроэнергии в сборе.
Фото 3. Счетчик-анализатор в корпусе.
Радиодетали для устройства были взяты от старого кассового аппарата, ЖК-дисплей – от копировального аппарата, а панелька под батарейку – со старой материнской платы компьютера. Дисплей соединен с платой шлейфом, отрезанным от старого дисковода.
Конструкция собрана в корпусе из пластика, на переднюю панель вынесены дисплей и светодиод. На боковых сторонах расположены разъемы для подключения кабеля от электросчетчика и разъем для связи с компьютером (фото 3).
Для питания устройства используется зарядное устройство от сотового телефона с USB выходом, подключенное к прибору с помощью кабеля, срезанного со старой компьютерной USB мыши.
Для работы с устройством используется специальное приложение для персонального компьютера, позволяющего установить время в приборе, начальное значение общего счетчика энергии и некоторых настроек.
Рис. 3. Приложение для работы с устройством.
Рис. 4. График потребления электроэнергии в жилом доме посуточно.
Рис. 5. График почасового потребления электроэнергии 11.09.2017.
Также с помощью приложения можно получить данные из постоянной энергонезависимой памяти и построить на их основании графики потребления. Пример загрузки данных из устройства показан на рисунке 3.
Полученные из устройства данные сохраняются на компьютере и работу по изучению и анализу можно проводить не подключаясь к прибору. Для примера рассмотрим записанные устройством данные в жилом доме в течение нескольких суток. Нажатие на кнопку «Построить график» отображает информацию, показанную на рисунке 4.
Щелкнув по любому из зеленых столбцов, можно получить расшифровку суточной информации с разбивкой по каждому часу. На рисунке 5 показан график почасового потребления электроэнергии 11 сентября 2017 года.
Вывод.
В своей работе мы использовали различные источники информации (научная и учебная литература, Интернет). В процессе работы мы изучили устройство и принцип работы электросчетчика и способ передачи данных на внешние устройства, были изучены принципы работы микроконтроллера, способы его программирования и обмена данными. Также был освоен метод разработки и изготовления печатных плат с помощью лазерного принтера и ламинатора.
Описанный счетчик-анализатор электроэнергии может быть использован в быту в качестве «удлинителя» циферблата электросчетчика, часов, а также для изучения количества потребленной электроэнергии с целью экономии и более равномерного распределения нагрузки. Кроме этого, устройство можно использовать на предприятиях, где повышенное и/или пониженное потребление электроэнергии ведет к крупным штрафам. В продаже имеются промышленные электросчетчики, обладающие такими функциями, но их цена в сотни раз превышает стоимость представляемого устройства.
Литература:
Иванов Б.С. "Электроника в самоделках",-М.: ДОСААФ, 2001г.
Галле К. "Как проектировать электронные схемы" - М.: ДМК Пресс, 2009г.
И.В.Левин «Справочник конструктора точных приборов» издание третье, Издательство «Машиностроение», Москва.
В.О. Шпаковский, «Для тех, кто любит мастерить», Москва, Просвещение
Бродин В.Б., Шагурин И.И. Микроконтроллеры. Архитектура, программирование, интерфейс. – М.: Издательство ЭКОМ, 1999
Паронджанов В. Д. "Учись писать, читать и понимать алгоритмы. Алгоритмы для правильного мышления. Основы алгоритмизации." – М.: ДМК Пресс, 2012г.
http://www.atmel.com – сайт производителя микроконтроллеров
Уитсон Дж. "500 практических схем на ИС": Пер. с англ. - М.: Мир, 1992г.
Токхейм Р. "Основы цифровой электроники": Пер. с англ.- М.: Мир, 1988г.
http://turbo51.com/
Белкин В.Г., Бондаренко В.К. «Справочник радиолюбителя-конструктора» издательство: Москва «Радио и связь».
Приложение 1. Исходный код микропрограммы контроллера на языке Pascal.
program pwmeter;
Uses I2C, LCD;
DEVICE_ID = $2475;
SystemClock = 22118400;
CLOCK_FREQ = 1000; //Hz
RTC_ADDR = $D0; //DS1307
EEPROM_ADDR = $A0; //24C16
EEPROM_SIZE = 32768; //байт
RTC_WATTS_OFFSET = $8;
RTC_TICKS_OFFSET = $10;
RTC_HOUR_OFFSET = $18;
BaudRateSerial = 57600;
STR_BUFFER_SIZE = 12;
BaudRateTimerValue = - SystemClock div 12 div 32 div BaudRateSerial;
ClockTimerValue = - SystemClock div 12 div CLOCK_FREQ;
WattsPerImpulse = 10;
type
TStrBuffer = packed record
Index: Byte;
Len: Byte;
case Byte of
0: (Data: array[0..STR_BUFFER_SIZE-1] of Byte);
1: (Chr: array[0..STR_BUFFER_SIZE-1] of Char);
end;
TStorageHeader = packed record
Complete:Byte;
Day:Byte;
Month:Byte;
Year:Byte;
Counter:TDword;
end;
TStorage = packed record
case Byte of
0: (Header: TStorageHeader);
1: (Dword0,Dword1: TDword);
2: (Bytes: array[0..7] of Byte);
end;
TSerialState = (ssIdle,ssGetDate,ssSetDate,ssGetPower,ssSetPower,ssReadMemory,
ssGetOptions,ssSetOptions,ssResetMemory);
var
//P1.0 - LCD_D4
//P1.1 - LCD_D5
//P1.2 - LCD_D6
//P1.3 - LCD_D7
LCD.LCD_RS: Boolean absolute P1.4;
LCD.LCD_E: Boolean absolute P1.5;
Relay1: Boolean absolute P1.6;
Relay2: Boolean absolute P1.7;
I2C.SDA:Boolean absolute P3.5;
I2C.SCL:Boolean absolute P3.4;
Led: Boolean absolute P3.7;
Input: Boolean absolute P3.2;
Kbd: Boolean absolute P3.3;
CounterChanged: Boolean; volatile;
DataActual:Boolean;
SecondFlag:Boolean;
DataReceived:Boolean;
EE_Dword:TDword;
Day_Dword:TDword;
WattCounter:TDword;
Storage: TStorage absolute $18;
Buffer: TStrBuffer;
TmpBuf: array[0..3] of Byte;
SecCounter:Word;
TickPrescaller:Byte; volatile;
I2C_Device_Addr:Byte;
SerialState:TSerialState;
LastReceivedByte:Byte;
SerialReceiveCounter:Byte;
SerialBuffer: array[0..7] of Byte absolute $10;
SerialMemSendAddr:Word;
EEPROM_BaseAddr:Word absolute EE_Dword.Word1;
PulsesPer10W:Byte absolute EE_Dword.Byte0;
EEPROM_LastHour:Byte absolute EE_Dword.Byte1;
LastHour: Byte absolute Day_Dword.Byte0;
LastDay: Byte absolute Day_Dword.Byte1;
HourWatts: Word absolute Day_Dword.Word1;
function Dword2Str(Data:LongInt;Dot:Byte):Byte;assembler;
asm
mov R7,Buffer.Len
mov R1,#Buffer.Data
mov A,Dot
clr C
rlc A
mov A,#' '
jc @@Clear
mov A,#'0'
@@Clear:
mov @R1,A
inc R1
djnz R7,@@Clear
mov A,Buffer.Len
add A,#Buffer.Data-1
mov R1,A
mov R5,#0
@@Loop2:
clr A
mov R6,#32
@@Skip:
lcall @@Shift
jnz @@Start
djnz R6,@@Skip
ret
@@Loop1:
lcall @@Shift
@@Start:
subb A,#10
jc @@Back
mov R0,#Data
inc @R0
sjmp @@Next
@@Back:
add A,#10
@@Next:
djnz R6,@@Loop1
add A,#30h
mov @R1,A
dec R1
inc R5
mov A,Dot
anl A,#7Fh
xrl A,R5
jnz @@NoDot
mov @R1,#'.'
inc R5
dec R1
@@NoDot:
mov A,#0
mov R0,#Data
mov R7,#4
@@Test:
orl A,@R0
djnz R7,@@Test
jnz @@Loop2
mov A,R5
ret
@@Shift:
mov R0,#Data
mov R7,#4
clr c
@@Shft:
xch a,@R0
rlc a
xch a,@R0
inc R0
djnz R7,@@Shft
rlc a
ret
end;
procedure I2C_ReadByte(Addr:Word;Cnt:Byte;Buff:PByte);
var
i:Byte;
begin
Start_I2C;
Send_I2C_Byte(I2C_Device_Addr and $FE);
if I2C_Device_Addr=EEPROM_ADDR then Send_I2C_Byte(Hi(Addr));
Send_I2C_Byte(Lo(Addr));
Start_I2C;
Send_I2C_Byte(I2C_Device_Addr or $01);
for i:=0 to Cnt-1 do begin
Buff^:=Receive_I2C_Byte;
Inc(Buff);
if iCnt-1 then Send_I2C_Ack;
end;
Send_I2C_ClockPulse;
Stop_I2C;
end;
procedure I2C_WriteByte(Addr:Word;Cnt:Byte;Data: PByte);
var
i:Byte;
begin
Start_I2C;
Send_I2C_Byte(I2C_Device_Addr and $FE);
if I2C_Device_Addr=EEPROM_ADDR then Send_I2C_Byte(Hi(Addr));
Send_I2C_Byte(Lo(Addr));
for i:=0 to Cnt-1 do begin
Send_I2C_Byte(Data^);
Inc(Data);
end;
Stop_I2C;
if I2C_Device_Addr=EEPROM_ADDR then Delay_ms(10);
end;
procedure SerialSendByte(Bt:Byte);
begin
TI:=False;
SBUF:=Bt;
while not TI do ;
end;
procedure Timer_1ms_Handler; Interrupt Timer0; Using 1; { 1 ms interrupt }
begin
TL0 := Lo (ClockTimerValue);
TH0 := Hi (ClockTimerValue);
if DelayTimer 0 then Dec(DelayTimer);
if SecCounter 0 then Dec(SecCounter);
if SecCounter = 0 then begin
SecCounter:=CLOCK_FREQ;
SecondFlag:=True;
end
end;
procedure Int0Handler; Interrupt External0; Using 1; { Input Pulses }
begin
Inc(TickPrescaller,WattsPerImpulse);
Led:=not Led;
if TickPrescaller>=PulsesPer10W then begin
Dec(TickPrescaller,PulsesPer10W);
Inc(WattCounter.Dword);
Inc(HourWatts);
CounterChanged:=True;
end;
end;
function IncBufferIndex:Boolean;
begin
Result:=Buffer.Index(STR_BUFFER_SIZE-1);
if Result then Inc(Buffer.Index);
end;
procedure LCD_SendStr;
var
i:Byte;
begin
for i:=0 to Buffer.Len-1 do LCD_WriteByte(LCD_DATA_BYTE,Buffer.Data[i]);
end;
procedure BCD_To_Str(BCD:Byte);
begin
Buffer.Data[Buffer.Index]:=$30+(BCD shr 4);
IncBufferIndex;
Buffer.Data[Buffer.Index]:=$30+(BCD and $0F);
IncBufferIndex;
end;
procedure BCD_To_Byte(var Data:Byte);
begin
Data:=10*(Data shr 4)+(Data and $0F);
end;
procedure ClearStrBuffer;
var
i:Byte;
begin
Buffer.Index:=0;
for i:=0 to STR_BUFFER_SIZE-1 do Buffer.Data[i]:=0;
end;
function UpdateTime:Boolean;
begin
LCD_WriteByte(LCD_CMD_BYTE,$C0);
ClearStrBuffer;
I2C_Device_Addr:=RTC_ADDR;
I2C_ReadByte(0,3,@TmpBuf);
BCD_To_Str(TmpBuf[2]);
if (TmpBuf[0] and 1)=0 then Buffer.Chr[Buffer.Index]:=':'
else Buffer.Chr[Buffer.Index]:=' ';
IncBufferIndex;
BCD_To_Str(TmpBuf[1]);
Buffer.Len:=5;
LCD_SendStr;
BCD_To_Byte(TmpBuf[2]);
Result:=TmpBuf[2]LastHour;
if Result then LastHour:=TmpBuf[2] else begin
EEPROM_LastHour:=LastHour;
I2C_WriteByte(RTC_TICKS_OFFSET,4,@EE_Dword);
end;
end;
function UpdateDate:Boolean;
begin
LCD_WriteByte(LCD_CMD_BYTE,$C6);
ClearStrBuffer;
I2C_Device_Addr:=RTC_ADDR;
I2C_ReadByte(4,3,@TmpBuf);
BCD_To_Str(TmpBuf[0]);
Buffer.Chr[Buffer.Index]:='.';
IncBufferIndex;
BCD_To_Str(TmpBuf[1]);
Buffer.Chr[Buffer.Index]:='.';
IncBufferIndex;
BCD_To_Str($20);
BCD_To_Str(TmpBuf[2]);
Buffer.Len:=10;
LCD_SendStr;
Storage.Header.Day:=TmpBuf[0];
Storage.Header.Month:=TmpBuf[1];
Storage.Header.Year:=TmpBuf[2];
BCD_To_Byte(TmpBuf[0]);
Result:=TmpBuf[0]LastDay;
LastDay:=TmpBuf[0];
end;
procedure UpdateCounter;
begin
ClearStrBuffer;
LCD_WriteByte(LCD_CMD_BYTE,$80);
Buffer.Len:=11;
Dword2Str(WattCounter.Dword,$3);
LCD_SendStr;
LCD_WriteByte(LCD_DATA_BYTE,ord(' '));
LCD_WriteByte(LCD_DATA_BYTE,ord('k'));
LCD_WriteByte(LCD_DATA_BYTE,ord('W'));
LCD_WriteByte(LCD_DATA_BYTE,ord('*'));
LCD_WriteByte(LCD_DATA_BYTE,ord('h'));
end;
procedure LoadParameters;
begin
I2C_Device_Addr:=RTC_ADDR;
I2C_ReadByte(RTC_WATTS_OFFSET,4,@WattCounter);
I2C_ReadByte(RTC_HOUR_OFFSET,4,@Day_Dword);
I2C_ReadByte(RTC_TICKS_OFFSET,4,@EE_Dword);
I2C_ReadByte(0,1,@TmpBuf);
if TmpBuf[0] and $80 = $80 then begin
PulsesPer10W:=32;
EEPROM_BaseAddr:=0;
I2C_WriteByte(RTC_TICKS_OFFSET,4,@EE_Dword);
WattCounter.Dword:=0;
I2C_WriteByte(RTC_WATTS_OFFSET,4,@WattCounter);
HourWatts:=0;
LastHour:=0;
LastDay:=0;
I2C_WriteByte(RTC_HOUR_OFFSET,4,@Day_Dword);
TmpBuf[0]:=0;
I2C_WriteByte(0,1,@TmpBuf);
end;
DataActual:=True;
end;
procedure SaveStorageHeader;
var
i:Byte;
begin
Storage.Header.Complete:=0;
TmpBuf[0]:=0;
TmpBuf[1]:=0;
TmpBuf[2]:=0;
TmpBuf[3]:=0;
Storage.Header.Counter:=WattCounter;
EEPROM_BaseAddr:=EEPROM_BaseAddr+(SizeOf(TStorageHeader)+48);
if EEPROM_BaseAddr+(SizeOf(TStorageHeader)+48) > EEPROM_SIZE then
EEPROM_BaseAddr:=0;
I2C_Device_Addr:=EEPROM_ADDR;
I2C_WriteByte(EEPROM_BaseAddr,4,@Storage.Dword0);
I2C_WriteByte(EEPROM_BaseAddr+4,4,@Storage.Dword1);
for i:=0 to 11 do I2C_WriteByte((8+4*i)+EEPROM_BaseAddr,4,@TmpBuf);
end;
procedure SaveHourData;
begin
I2C_Device_Addr:=EEPROM_ADDR;
I2C_ReadByte(EEPROM_BaseAddr,1,@TmpBuf);
if TmpBuf[0]>23 then SaveStorageHeader;
TmpBuf[0]:=Lo(HourWatts);
TmpBuf[1]:=Hi(HourWatts);
I2C_WriteByte(EEPROM_BaseAddr+(SizeOf(TStorageHeader)+2*EEPROM_LastHour),2,@TmpBuf);
TmpBuf[0]:=EEPROM_LastHour; //CurrentHour
I2C_WriteByte(EEPROM_BaseAddr,1,@TmpBuf);
end;
procedure SerialPutToBuffer;
begin
if DataReceived then begin
DataReceived:=False;
Dec(SerialReceiveCounter);
SerialBuffer[SerialReceiveCounter]:=LastReceivedByte;
end;
end;
procedure SerialHandler; Interrupt Serial; Using 1; { Serial interrupt }
begin
if RI then begin
LastReceivedByte:=SBUF;
{TI:=False;
SBUF:=LastReceivedByte;
while TI do;
TI:=False;}
RI:=False;
if SerialState=ssIdle then case LastReceivedByte of
ord('D'): begin
SerialState:=ssSetDate;
SerialReceiveCounter:=6;
end;
ord('P'): begin
SerialState:=ssSetPower;
SerialReceiveCounter:=5;
end;
ord('m'): begin
SerialState:=ssReadMemory;
SerialReceiveCounter:=0;
SerialMemSendAddr:=0;
end;
ord('R'): begin
SerialState:=ssResetMemory;
SerialReceiveCounter:=0;
end;
end else DataReceived:=True;
end;
end;
procedure ExecuteSerialCmd;
var
i:Byte;
t:Word;
begin
if SerialReceiveCounter>0 then SerialPutToBuffer else case SerialState of
ssSetDate: begin
I2C_Device_Addr:=RTC_ADDR;
I2C_WriteByte(0,3,@SerialBuffer);
I2C_WriteByte(4,3,@SerialBuffer[3]);
SerialSendByte(1);
UpdateDate;
SerialState:=ssIdle;
end;
ssSetPower: begin
WattCounter.Byte0:=SerialBuffer[3];
WattCounter.Byte1:=SerialBuffer[2];
WattCounter.Byte2:=SerialBuffer[1];
WattCounter.Byte3:=SerialBuffer[0];
PulsesPer10W:=SerialBuffer[4];
CounterChanged:=True;
Day_Dword.Dword:=0;
I2C_Device_Addr:=RTC_ADDR;
I2C_WriteByte(RTC_TICKS_OFFSET,4,@EE_Dword);
I2C_WriteByte(RTC_WATTS_OFFSET,4,@WattCounter);
SerialSendByte(1);
SerialState:=ssIdle;
end;
ssResetMemory: begin
EEPROM_BaseAddr:=0;
I2C_Device_Addr:=RTC_ADDR;
I2C_WriteByte(RTC_TICKS_OFFSET,4,@EE_Dword);
SerialSendByte(1);
SerialState:=ssIdle;
end;
ssReadMemory: begin
t:=EEPROM_BaseAddr+(SizeOf(TStorageHeader)+48);
if SerialMemSendAddr=0 then begin
SerialSendByte(Lo(DEVICE_ID));
SerialSendByte(Hi(DEVICE_ID));
SerialSendByte(Lo(EEPROM_SIZE));
SerialSendByte(Hi(EEPROM_SIZE));
SerialSendByte(Lo(t));
SerialSendByte(Hi(t));
end;
I2C_Device_Addr:=EEPROM_ADDR;
I2C_ReadByte(SerialMemSendAddr,8,@SerialBuffer);
for i:=0 to 7 do SerialSendByte(SerialBuffer[i]);
Inc(SerialMemSendAddr,8);
if SerialMemSendAddr>t then SerialState:=ssIdle;
end;
end;
end;
procedure Init;
begin
P1:=$FF;
P3:=$FF;
TL0 := Lo (ClockTimerValue);
TH0 := Hi (ClockTimerValue);
TL1:=Lo(BaudRateTimerValue);
TH1:=Lo(BaudRateTimerValue);
TickPrescaller:=0;
ClearStrBuffer;
DataActual:=False;
SecCounter:=CLOCK_FREQ;
SecondFlag:=True;
CounterChanged:=True;
SerialState:=ssIdle;
DataReceived:=False;
PCON := $00;
SCON:=SCON_SERIAL_MODE_1+SCON_RECEIVE_ENABLED;
TMOD:=TMOD_TIMER1_MODE_2+TMOD_TIMER0_MODE_1;
TCON:=TCON_TIMER1_ENABLE+TCON_TIMER0_ENABLE+TCON_INT0_PULSE;
IE:=IE_GLOBAL+IE_TIMER0+IE_INT0+IE_UART;
end;
begin
Init;
LCD_Init;
LoadParameters;
UpdateDate;
repeat
if CounterChanged then begin
UpdateCounter;
I2C_Device_Addr:=RTC_ADDR;
I2C_WriteByte(RTC_WATTS_OFFSET,4,@WattCounter);
I2C_WriteByte(RTC_HOUR_OFFSET,4,@Day_Dword);
CounterChanged:=False;
end;
if SecondFlag then begin
if UpdateTime then begin
SaveHourData;
HourWatts:=0;
if UpdateDate then begin
SaveStorageHeader;
end;
I2C_Device_Addr:=RTC_ADDR;
I2C_WriteByte(RTC_HOUR_OFFSET,4,@Day_Dword);
I2C_WriteByte(RTC_TICKS_OFFSET,4,@EE_Dword);
end;
SecondFlag:=False;
end;
ExecuteSerialCmd;
until False;
end.
28