DeepEdit!

Программирование баз данных на Oracle, техническая документация, литература, статьи и публикации

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

Сбор данных в реальном времени

Автор: Антон Фогелар (Anton Vogelaar)

В технике часто бывает нужно делать физические данные доступными одновременно для одного или более приложений. Для упрощения программирования таких функций здесь представлен пример, иллюстрирующий, как можно это делать, с использованием СУБД Interbase/Firebird, обеспечивающей маршалинг, атомарность, изоляцию и долговечность данных. Эта статья описывает модульный подход, начиная от измерения температуры и заканчивая сохранением данных в базу. Она также будет служить документом по написанию программ для использования с DelphiDevBoard 

Маршрут сигнала от датчика до хранилища данных выглядит примерно так:
Датчик температуры.
Аналого-цифровой преобразователь (АЦП).
Передатчик.
Приложение, осуществляющее сбор данных.
Реляционная СУБД (система управления базами данных).
1.        Датчик температуры.
В этом примере температура должна измеряться с точностью не менее 0,1 градуса Цельсия и записываться вместе с датой и временем измерения. Был выбран температурный датчик DS18B20 от Maxim, имеющий диапазон от -55 до +125 градусов Цельсия с разрешением 1/16 градуса. Он вполне удовлетворяет предъявленным требованиям.
2.        Аналого-цифровой преобразователь (АЦП).
Датчик DS18B20 имеет встроенный 12-битный АЦП.
Диапазоны цифровых данных: от        1100 1001 0000 = $FC90 = -
880 эквивалентно -55,0 градусам Цельсия) до
%0000 0000 0000 0000 = $0000 = 0 для нуля градусов и далее до %0000 0111 1101 0000 = $07D0 = 2000 (эквивалентно +125 градусам Цельсия).
То есть, значение на выходе преобразователя в 16 раз больше значения в градусах по Цельсию.
3.        Передатчик.
В качестве передатчика используется плата DelphiDevBoard (см. страницу 38). Для работы передатчика используется его собственное ПО. Оно содержит следующие компоненты:
Драйвер датчика температуры. Принимает цифровые данные от датчика и преобразует их в целое число.
Сервер ввода-вывода. Это фоновое приложение срабатывает 8 раз в секунду, вызывая драйвер и записывая принятое число в переменную типа record: Var Inputs:  Tinputs; место его хранения - Inputs.Temp.
M485aServer, работает в фоновом режиме и обеспечивает передачу данных по запросу через через порт RS232. Используемый открытый протокол: M485a.
4.        Приложение сбора данных.
Для сбора данных используется ПК под управлением Windows и приложения на Delphi. Так как большинство современных ПК не имеют портов RS232, для подключения к передатчику используется USB-адаптер. Для облегчения взаимодействия с передатчиком DelphiDevBoard поставляется с библиотекой lib485a.dll, реализующей протокол M485a. Задачи этого приложения - получить температуру, добавить дату и время и сохранить всё это в базе данных, в качестве которой используется БД Interbase/Firebird. Этот модульный проект Delphi - dta_collector.dpr - содержит 4 слоя:
Презентационный слой.
Бизнес-слой.
Коммуникационный слой.
Сохраняющий слой.
Презентационный слой
Исходный код GUI можно прочитать в файле UGUI.pas, а на
скриншоте показано, как расположены элементы управления. Управление этим приложением осуществляется экземпляром контроллера TContr, определённом в бизнес-слое.
Контроллер создаётся в методе OnCreate главной формы (называемой GUI) и уничтожается в её методе OnDestroy.
В верхнем левом углу присутствует SpeedButton с красной/зелёной пиктограммой, обозначающей статус (включено/выключено). Обработчик события OnClick вызывает private-методы главной формы (GUI) GoOnline и GoOffLine.
Эти методы включают и выключают отображение панели, показывающей измеренные данные, и вызывают методы контроллера Start и Stop.
Этот класс также содержит public-метод Refresh, заполняющий визуальные компоненты числами, полученными из нижележащих слоёв.

(* ======= Interface ===== *)

Interface
Uses Windows Messages ,  SysUtils Variants ,  Classes ,
Graphics Controls Forms, Dialogs StdCtrls ExtCtrls Buttons,  ToolWin,  ComCtrls UDomain;
Type TGUI        = Class   (TForm)
TBar        : TToolBar;
BtnGo        : TSpeedButton;
PnlMain : TPanel;
LbTemp        : TLabel;
LbPotm        : TLabel;
ShTot        : TShape;
ShTemp        : TShape;
ShPotm        : TShape;
Label1 : TLabel;
Label2 : TLabel;
Label3 : TLabel;
LbLog        : TLabel;
Shape1        : TShape;
Procedure        BtnGoClick Sender TObject);
Procedure        FormHide      Sender  :  TObject);
Procedure        FormShow      Sender  :  TObject);
Private
Contr TContr;
Procedure        GoOnLine;
Procedure        GoOffLine;
Public
Procedure        Refresh  STemp,  SPotm,  SLog  :  String);
End;
Var       GUI TGUI ;

(* ======= Implementation ============================= *)

Implementation

{$R *.dfm}

(* ===== Private ================================= *)

Procedure TGUI GoOnLine; Begin
Try Contr. Start;
PnlMain. Visible  := True; Except
GoOffLine; Raise End; End;
Procedure TGUI GoOffLine;
Begin
BtnGo. Down        := False;
PnlMain. Visible  := False; Contr. Stop;
End;

(* ==== Public ================================= *)

Procedure TGUI Refresh STemp, SPotm, SLog : String); Begin
LbTemp. Caption := STemp; LbPotm. Caption := SPotm; LbLog. Caption    := SLog;
End;

(* ====== Form ================================== *)

Procedure TGUI FormShow Sender TObject); Begin
Contr  := TContr. Create;
End;
Procedure TGUI FormHide Sender TObject); Begin
GoOffLine;
Contr. Free;
End;
Procedure TGUI.BtnGoClick  (Sender  :  TObject); Begin
If BtnGo. Down Then GoOnLine Else GoOffLine; End;

(* ==== End =================================== *)

End.
Unit UDomain; Interface
Uses      ExtCtrls, SysUtils UDB;
Type       TContr   = Class Private
Timer        :  TTimer ;
DB        TDB;
NLog        :  Integer;
Procedure DoTimer  Sender  :  TObject); Public
Constructor Create; Destructor    Destroy;  Override; Procedure Start; Procedure Stop;
End;

(* =========== Implementation ============== *)

Implementation
Uses      UGUI ;
Type        TStr80    = String  [80];

(* =========== DLL procedures ============== *)

Procedure M485a_Open  Port  :  Integer);
External 'lib485a.dll'; Procedure M485a_Close; External 'lib485a.dll';
Procedure M485a_ProdID    (Var ProdID      :  TStr80);
External 'lib485a.dll';
Procedure M485a_ProdIDF  (Var ProdID      :  TStr80);
External 'lib485a.dll';
Procedure M485a_Vars        (Var MainVars   :  TStr80);
External 'lib485a.dll'; Procedure M485a_RdRam     N, MAddr Word; Var Buf);
External 'lib485a.dll'; Procedure M485a_WrRam     N, MAddr Word; Var Buf);
External 'lib485a.dll'; Procedure M485a_RdEe      N, MAddr Word; Var Buf);
External 'lib485a.dll'; Procedure M485a_WrEe       N, MAddr Word; Var Buf);
External 'lib485a.dll';

(* =========== Public ====================== *)

Constructor TContr. Create; Begin
Inherited;
DB := TDB. Create;
DB.Open  ('192.168.0.16:/db/test.fdb');
End;
Destructor TContr. Destroy; Begin
DB. Close; FreeAndNil DB); Inherited;
End;
Procedure TContr. Start; Begin
M485a_Open (1);
Timer  := TTimer. Create   (Nil); Timer. Interval := 1000; Timer. OnTimer    := DoTimer; Timer. Enabled    := True;
End;
Procedure TContr. Stop; Begin
If Timer = Nil Then exit;
Timer. Enabled  := False;  FreeAndNil   Timer);
M485a_Close; End;

(* =========== Timer ======================= *)

Procedure TContr. DoTimer  Sender  :  TObject);
Var       S        TStr80 ;
STemp, SPotm        : String;
ITemp ,  IPotm        :  Integer ;
Begin
If Not Timer. Enabled        Then Exit;
M485a_Vars S);
STemp := Copy , 3,        4); SPotm := Copy , 7, 4);
ITemp  := StrToInt   ('$'  + STemp);IPotm  := StrToInt   ('$'  + SPotm);
STemp := Format ('%.1f C',    [ ITemp / 16]); SPotm := Format ('%.1f %%', [ IPotm / 10.23]);
Inc  NLog);
GUI Refresh STemp, SPotm, IntToStr NLog)); DB. Save ITemp, IPotm); End;

(* =========== End ========================= *)

End.
Бизнес- и коммуникационный слои
Функции обоих этих слоёв реализованы в модуле UDomain. Так как Windows является ОС, основанной на событиях, класс контроллера содержит экземпляр таймера, вызывающий событие OnTimer каждую секунду. Это событие присоединено к методу DoTimer. В TContr.DoTimer вызывается процедура M485a_Vars (S). Эта процедура базируется в библиотеке lib485a DLL и возвращает строковое представление записи Inputs в шестнадцатеричном формате.
Температура в 16-ричном представлении - это четыре символа, начиная с позиции 3.
Itemp  := StrToInt  ('$'  + Copy  (S, 3,  4)); возвращает температуру как целое число, поделив которое на 16, мы получим её значение в градусах Цельсия; символ '$' указывает функции StrToInt, что строка представлена в виде шестнадцатеричного числа. Это значение отправляется в GUI в виде строки, созданной с помощью Format   ('%.1f C',   [ITemp / 16]) при вызове метода GUI.Refresh. Также оно должно быть внесено в базу данных. Так как вся работа с базой данных осуществляется через класс TDB, достаточно вызвать метод DB.Save (ITemp). Создание и освобождение объекта DB производится при создании и уничтожении контроллера.

Сохраняющий слой
Этот слой содержит все функции, необходимые для сохранения измеренных данных в базе данных Interbase/Firebird. Используются объекты TIbDatabase, TIbTransaction и TIbSql, так как TIbSql - это простейший класс для работы с данными. Объекты эти классов создаются и уничтожаются методами TDB.Open и TDB.Close. Фактически функция сохранения реализована в методе TDB.Save и вложена в транзакцию. Unit UDB; Interface
Uses        ExtCtrls,   SysUtils,   IbDatabase,   IbSQL,  Classes;
Type        TDB        = Class
Private
IbDb        :   TIbDatabase;
IbTr        :  TIbTransaction;
IbSQL        :   TIbSQL;
Public
Procedure Open  (DbName  :  String); Procedure Close;
Procedure Save   (ITemp,  IPotm  :  Integer);
End;

(* =========== Implementation ============== *)

Implementation

(* =========== Public ====================== *)

Procedure TDB. Open DbName : String); Begin
IbDb := TIBDatabase. Create (Nil); IbTr := TIBTransaction. Create (Nil); IbSQL := TIBSQL. Create (Nil);
IbTr.DefaultDatabase   := IbDb;
With IbDb Do
Begin
Params.Add  ('user_name=SYSDBA'); Params.Add  ('password=masterkey');
DatabaseName        := DbName;
LoginPrompt        := False;
SQLDialect        := 3;
DefaultTransaction  := IbTr; Open;
End;
With IbSQL Do
Begin
Database        := IBDb;  Transaction  := IBTr;
End; End;
Procedure TDB.Close; Begin
IbDb.Close;  FreeAndNil   (IbSQL);  FreeAndNil   (IbTr);
FreeAndNil IbSQL); End;
Procedure TDB. Save   ITemp,  IPotm  :   Integer); Begin
IbTr. StartTransaction;
IbSQL.SQL.Text := Format ('insert into LOG (TEMP, POTM) values   (%s,  %s)',
[IntToStr   (ITemp),   IntToStr   (IPotm)]); IbSQL. ExecQuery; IbTr. Commit;
End;

(* ============ End ========================  *)

End.
5. Реляционная система управления базами данных (СУБД).
Установка Interbase/Firebird устанавливает движок базы данных, а не саму БД, которую мы будем использовать. База данных может быть создана с помощью консольного приложения ibsql. 

(примечание переводчика: эта утилита может иметь название isql.exe в некоторых дистрибутивах).

Чтобы автоматизировать этот процесс и иметь возможность восстановить базу данных при обнаружении ошибок или при установке на другом компьютере, все операторы включены в файл-скрипт create_db.sql.
Этот скрипт выполняется командой: IBSQL -q -i create_db.sql. Скрипт содержит комментарии, команды создания базы данных, создания таблиц, триггеров и генераторов для реализации автоинкрементных полей, и данные-примеры для заполнения таблицы.
SQL-скрипт
create_db.sql
/* 

Script creating a firebird database table.

Copyright by Vogelaar Electronics, Bunschoten Netherlands. Rev. 0.10 2010-09-17 Initial release Usage: # In -s / opt/firebird/bin/isql / usr/local/sbin/fbisql

#

       

cd //path of script/

#

       

fbisql -q -i create_db.sql 

/* 
/*==================== connect ==================== /*
set sql dialect 3;
create database "localhost:/db/test.fdb"
user  'SYSDBA' password 'masterkey'; 
/* =================== tables ===================== */
create table LOG  (
ID        integer      not null primary key,
STAMP        timestamp not null,
TEMP        integer ,
POTM        integer,
REM      varchar   (20)); 
/* =================== generators and triggers ==== */
create generator AI_LOG; set generator AI_LOG to 0; set term л  ;
create trigger TR_BILOG for LOG before insert as begin
if   (NEW.ID        is null)   then NEW.ID gen_id   (AI_LOG,  1); if   (NEW.STAMP is null)   then NEW.STAMP CURRENT_TIMESTAMP end л
set term ;  л
/* =================== populate =================== */
insert into LOG values (null, null, 100, 200, 'none'); insert into LOG values (null, null, 150, 250, null);
commit; Маршалинг
В компьютерной науке, маршалинг (по аналогии с сериализацией) - это процесс преобразования представления объекта в памяти в формат данных, пригодный для сохранения или передачи). Он обычно используется, когда данные должны перемещаться между различными частями программы для ПК, либо из одной программы в другую.
Маршалинг - это процесс, используемый для связи с удаленными объектами с помощью объекта (сериализованный объект - сериализация). Онупрощает сложные связи, используя для взаимодействия пользовательские/сложные объекты вместо примитивных.
Процесс, обратный маршалингу, называется демаршалинг (напоминает десериализацию). - wiki
Атомарность
В СУБД атомарность является одним из ACID-свойств транзакции. В атомарной транзакции последовательность операций с базами данных либо целиком подтверждается, либо целиком отменяется. Гарантия атомарности предотвращает внесение в базу лишь части необходимых обновлений, что может причинить неприятности, большие, чем полный отказ от этих изменений. Этимология фразы берёт свое начало в классической греческой концепции фундаментального и неделимого элемента (см. атом). Пример атомарности - это заказ билета на самолёт, в процессе которого требуются два действия: оплата и резервирование места. Потенциальный пассажир должен либо:
оплатить и забронировать место; ИЛИ
не платить и не бронировать место.
Система бронирования не считает приемлемым для клиента оплату билета без обеспечения места, либо бронирование места без успешной оплаты. - wiki

 


курительные смеси купить . подшипники







jAntivirus