{ Контроллер напряжений (АК5) 5.105.198} unit MI1201AGM_Voltmeter_Emulator; interface USES SysUtils, TimeInterval_Emulator, MI1201AGM_Hardware_Emulator, MI1201AGM_Controller_Emulator; const cDataSignature='Voltmeter emulator data. '^M^L; cRegistrySubPath='Voltmeter'; cValidPorts=[$CF,$CD,$CE,$C7,$C8]; cValidReadPorts=[$CF,$CD,$CE]; cValidWritePorts=[$C7,$C8]; type tDataSignature=array[1..Length(cDataSignature)] of char; tFlag=(b0,b1,fNegative,fReady); tFlags=set of tFlag; tByteCounter=0..1; tInternalFlag=(ifDataReady, ifGetDataEachTime); tInternalFlags=set of tInternalFlag; tValue=double; tValueDecadeNumber=0..3; tDecadeValue=0..9; tDecadeValues=array[tValueDecadeNumber] of tDecadeValue; // Данные, сохраняющиеся между измерениями tData=record Signature:tDataSignature; Channel:tVoltmeterPoint; IFlags:tInternalFlags; cLo,cHi:tByteCounter; // счетчики выдачи данных в порты MeasureTimeout:word; end; // Данные, НЕсохраняющиеся между измерениями tTmpData=record Flags:tFlags; // аппаратные флаги Value:tValue; // значение напряжения Data:word; // данные вольтметра DecadeValues:tDecadeValues; // данные подекадно выдачи данных в порты end; tVoltmeter=class(tController) private prTimer:tTimeIntervalX; prData:tData; prTmpData:tTmpData; function CheckTimer:boolean; procedure DataGet; procedure SetChannel(c:tVoltmeterPoint); function ChannelHi:byte; function ChannelLo:byte; function GetReady:boolean; property MeasureTimeout:word read prData.MeasureTimeout write prData.MeasureTimeout; protected // обязательные процедуры function SubPath:string; override; procedure prOutByte(b:Byte; port:word); override; function prInByte(port:word):Byte; override; function CheckData(Data:pointer):boolean; override; function DataSize:integer; override; function SetData(aData:pointer):boolean; override; function GetData(aData:pointer):boolean; override; // прочие процедуры function SetControlFlag(AFlag:tInternalFlag):tInternalFlags; function ClrControlFlag(AFlag:tInternalFlag):tInternalFlags; public // обязательные процедуры constructor Create(Hardware:tMi1201HardwareEmulator); destructor Destroy; override; procedure ReInit; override; procedure SetDefaultData; override; function ValidPort(APort:word):boolean; function ValidReadPort(APort:word):boolean; function ValidWritePort(APort:word):boolean; // прочие процедуры // Функции аппаратной эмуляции - выполняют полный набор операций // Аппаратные флаги function Flags:byte; // Запуск измерения procedure Strobe; // Канал измерения property Channel:tVoltmeterPoint read prData.Channel write SetChannel; // Сигнал готовности измерения property Ready:boolean read GetReady; // Функции доступа к данным и управления - не изменяют существующие данные, только считывают текущие // Величина сигнала property Value:tValue read prTmpData.Value; // Подекадная разбивка сигнала property ValueDecadest:tDecadeValues read prTmpData.DecadeValues; // Флаги управления property ControlFlags:tInternalFlags read prData.IFlags; end; implementation USES Emulator_Registry; function tVoltmeter.SetData(aData:pointer):boolean; begin Result:=Inherited SetData(aData); if Inherited SetData(aData) then begin Inc(Cardinal(aData),Inherited DataSize); Result:=CheckData(aData); if Result then begin Move(aData^,prData,DataSize); end; end; end; function tVoltmeter.GetData(aData:pointer):boolean; begin Result:=Inherited GetData(aData); if Result then begin Inc(Cardinal(aData),Inherited DataSize); Result:=CheckData(aData); if Result then begin Move(prData,aData^,SizeOf(prData)); end; end; end; function tVoltmeter.DataSize:integer; begin Result:=Inherited DataSize + SizeOf(prData); end; function tVoltmeter.SubPath:string; begin Result:=cRegistrySubPath; end; function tVoltmeter.CheckData(Data:pointer):boolean; begin Result:=Inherited CheckData(Data) and TRUE; end; procedure tVoltmeter.SetDefaultData; begin prData.Signature:=cDataSignature; prData.MeasureTimeout:=10; prTimer.Clear; end; constructor tVoltmeter.Create(Hardware:tMi1201HardwareEmulator); begin prTimer:=tTimeIntervalX.Create; Inherited; end; destructor tVoltmeter.Destroy; begin Inherited; prTimer.Free; end; procedure tVoltmeter.ReInit; begin end; procedure tVoltmeter.Strobe; begin prTimer.Clear; prTimer.Start(MeasureTimeout); Exclude(prTmpData.Flags,fReady); ClrControlFlag(ifDataReady); end; procedure tVoltmeter.SetChannel(c:tVoltmeterPoint); begin prData.Channel:=c; Strobe; end; function tVoltmeter.Flags:byte; begin CheckTimer; DataGet; Flags:=Byte(prTmpData.Flags); end; function tVoltmeter.ChannelHi:byte; begin DataGet; ChannelHi:=(prTmpData.Data shr (8+4*prData.cHi)); if prData.cHi=1 then begin Dec(prData.cHi); end else begin Inc(prData.cHi); end; end; function tVoltmeter.ChannelLo:byte; begin DataGet; ChannelLo:=(prTmpData.Data shr (4*prData.cLo)); if prData.cLo=1 then begin Dec(prData.cLo); end else begin Inc(prData.cLo); end; end; function tVoltmeter.GetReady:boolean; begin Result:=(Ord(fReady) and Flags) <>0; end; procedure tVoltmeter.DataGet; var v:double; i,j,n:integer; k:byte; begin if ifDataReady in ControlFlags then Exit; v:=Hardware.Voltage(prData.Channel); prTmpData.Value:=v; if v<0 then begin Include(prTmpData.Flags,fNegative); v:=-v; end else begin Exclude(prTmpData.Flags,fNegative); end; if v>100 then begin Byte(prTmpData.Flags):=(Byte(prTmpData.Flags) and ($FF-3)) or 3; i:=9999; end else if v>10 then begin Byte(prTmpData.Flags):=(Byte(prTmpData.Flags) and ($FF-3)) or 3; i:=Round(v*100); end else if v>1 then begin Byte(prTmpData.Flags):=(Byte(prTmpData.Flags) and ($FF-3)) or 2; i:=Round(v*1000); end else if v>=0.1 then begin Byte(prTmpData.Flags):=(Byte(prTmpData.Flags) and ($FF-3)) or 1; i:=Round(v*10000); end else begin Byte(prTmpData.Flags):=(Byte(prTmpData.Flags) and ($FF-3)); i:=Round(v*100000); end; n:=1000; prTmpData.Data:=0; for k:=3 downto 0 do begin j:=i div n; i:=i mod n; n:=n div 10; prTmpData.Data:=prTmpData.Data or (j shl (k*4)); prTmpData.DecadeValues[k]:=j; end; if (ifGetDataEachTime in ControlFlags) then SetControlFlag(ifDataReady); end; function tVoltmeter.CheckTimer:boolean; begin Result:=prTimer.Expired; if Result then begin Include(prTmpData.Flags,fReady); end; end; procedure tVoltmeter.prOutByte(b:Byte; port:word); begin port:=port and $FF; case Port of $C7: begin {строб измерений} Strobe; end; $C8: begin {Данные для коммутации подаваемого напряжения} SetChannel(tVoltmeterPoint(b)); end; else if port in cValidReadPorts then begin WriteToInvalidPort:=TRUE; if ExceptionOnInvalidPort then raise EInvalidPort.CreateEx(ClassName,Port); end else begin InvalidPort:=TRUE; if ExceptionOnInvalidPort then raise EInvalidPort.CreateEx(ClassName,Port); end; end; end; function tVoltmeter.prInByte(port:word):Byte; begin port:=port and $FF; Result:=$FF; case Port of $CF: begin {чтения признаков: полярности, готовности, предела. см. рис.1} Result:=Flags; end; $CD: begin {чтения данных с вольтметра (3 и 4 тетрада)} Result:=ChannelHi; end; $CE: begin {чтения данных с вольтметра (3 и 4 тетрада)} Result:=ChannelLo; end; else if port in cValidWritePorts then begin ReadFromInvalidPort:=TRUE; if ExceptionOnInvalidPort then raise EInvalidPort.CreateEx(ClassName,Port); end else begin InvalidPort:=TRUE; if ExceptionOnInvalidPort then raise EInvalidPort.CreateEx(ClassName,Port); end; end; end; function tVoltmeter.ValidPort(APort:word):boolean; begin Result:= ((APort and $FF00)=cBasePort) and ((APort and $FF) in cValidPorts); end; function tVoltmeter.ValidReadPort(APort:word):boolean; begin Result:= ((APort and $FF00)=cBasePort) and ((APort and $FF) in cValidReadPorts); end; function tVoltmeter.ValidWritePort(APort:word):boolean; begin Result:= ((APort and $FF00)=cBasePort) and((APort and $FF) in cValidWritePorts); end; function tVoltmeter.SetControlFlag(AFlag:tInternalFlag):tInternalFlags; begin Result:=prData.IFlags; Include(prData.IFlags,AFlag); end; function tVoltmeter.ClrControlFlag(AFlag:tInternalFlag):tInternalFlags; begin Result:=prData.IFlags; Exclude(prData.IFlags,AFlag); end; end. { Контроллер напряжений (АК5) 5.105.198 г========T================T=====================================¬ ¦ Адрес ¦ ПОРТ ¦ ¦ ¦ порта +-------T--------+ Назначение ¦ ¦ ¦чтение ¦запись ¦ ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ $C7 ¦ - ¦ + ¦ строб измерений ¦ ¦ ¦ ¦ ¦ ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ $C8 ¦ - ¦ + ¦ ¦ ¦ ¦ ¦ ¦ Данные для коммутации подаваемого ¦ ¦ ¦ ¦ ¦ напряжения: ¦ ¦ ¦ ¦ 0¦ 0000 0000 - напряжение ИМЧ ¦ ¦ ¦ ¦ 1¦ 0000 0001 - ускоряющее напряжение ¦ ¦ ¦ ¦ 2¦ 0000 0010 - ток электромагнита ¦ ¦ ¦ ¦ 3¦ 0000 0011 - напряжение умножителя ¦ ¦ ¦ ¦ 4¦ 0000 0100 - напряжение антидинатрона¦ ¦ ¦ ¦ 5¦ 0000 0101 - напряжение опоры ПНЧ ¦ ¦ ¦ ¦ 6¦ 0000 0110 - напряжение УПТ 1 ¦ ¦ ¦ ¦ 7¦ 0000 0111 - напряжение УПТ 2 ¦ ¦ ¦ ¦ 8¦ 0000 1000 - напряжение УПТ 3 ¦ ¦ ¦ ¦ 9¦ 0000 1001 - напряжение УПТ 4 ¦ ¦ ¦ ¦ 10¦ 0000 1010 - напряжение УПТ 5 ¦ ¦ ¦ ¦ 11¦ 0000 1011 - напряжение УПТ 6 ¦ ¦ ¦ ¦ 12¦ 0000 1100 - напряжение УПТ 7 ¦ ¦ ¦ ¦ 13¦ 0000 1101 - напряжение УПТ 8 ¦ ¦ ¦ ¦ 14¦ 0000 1110 - напряжение УПТ-У ¦ ¦ ¦ ¦ 15¦ 0000 1111 - напряжение линзы ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ $CF ¦ + ¦ - ¦ чтения признаков: полярности, ¦ ¦ ¦ ¦ ¦ готовности, предела. см. рис.1 ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ $CD ¦ + ¦ - ¦ чтения данных с вольтметра ¦ ¦ ¦ ¦ ¦ (3 и 4 тетрада) ¦ ¦--------+-------+--------+-------------------------------------¦ ¦ $CE ¦ + ¦ - ¦ чтения данных с вольтметра ¦ ¦ ¦ ¦ ¦ (1 и 2 тетрада) 1 тетрада - младшая ¦ L========¦=======¦========¦=====================================- Порт $CF - чтение признаков: полярности, готовности, предела. ---T--T--T--T--T--T--T--¬ ¦D7¦D6¦D5¦D4¦D3¦D2¦D1¦D0¦ LT-+T-+T-+T-+T-+T-+T-+-T- L--+T-+--- ¦ ¦ L---+---- предел измерения не использ. ¦ ¦ 00 - 100 mV xx.xx ¦ ¦ 01 - 1 V .xxxx ¦ ¦ 10 - 10 V x.xxx ¦ ¦ 11 - 100 V xx.xx ¦ L----------- полярность ¦ 0 - положит. ¦ 1 - отрицат. L-------------- готовность 0 - не готов 1 - готов рис.1 Порядок работы 1) Выбрать измеряемый канал ($C8) 2) Произвести запись в порт $C7 3) После установки бита D3 порта $CF в 1, прочитать данные. }