{ Контроллер ПНЧ 5.105.154 (преобразователь напряжение-частота) АК-9 с нормированным на 1 секунду сигналом } {--------------------------------------------------------------------------- The control units for mass-spectrometer MI1201-AGM (c) Copyright Aleksandrov O.E., 1998 Модуль управления масс-спектрометром МИ1201-АГМ (c) Собственность Александрова О.Е., 1998 Molecular Physics department 620002, Екатеринбург, К-2 USTU, Ekaterinsburg, K-2, 620002 УГТУ, RUSSIA Кафедра молекулярной физики phone 75-48-39 тел. 75-48-39 E-mail aleks@dpt.ustu.ru ----------------------------------------------------------------------------} Unit c_CVF; {$X+} INTERFACE USES c_Ctrl, c_Ctrl1, c_Bus; type tRegimeSwitchs=(frsBaseIsZero, frsInputIsEMU, frsDoNotInvertSignal); tRegime=set of tRegimeSwitchs; const cWorkRegime=[frsBaseIsZero, frsInputIsEMU, frsDoNotInvertSignal]; cCalibrationRegime0=[frsBaseIsZero, frsDoNotInvertSignal]; cCalibrationRegime1=[frsDoNotInvertSignal]; cDefaultRegime=cWorkRegime;{ Шина опоры: -9V; На вход ПНЧ подан сигнал с ЭМУ; Сигнал не инвертируется. } cFirstChannel =1; { номер первого канала } cLastChannel =9; { номер последнего канала } cWorkingChannels=[1..5, 9]; { рабочие каналы для МИ1201-АГМ } cSEMChannels =[9]; { каналы ВЭУ } cEMUChannels =cWorkingChannels-cSEMChannels; { каналы ЭМУ } cDefaultChannels=cWorkingChannels; cDefaultIntegrationTime=1000; { мс } cDefaultTimeOut=500; { мс } cDefaultDelayTime=100; { мс - задержка на срабатывание реле } type { Коды ошибок } tErrorCodes=({$I C_ErrCds.Inc}, ecFailResetController, ecFailResetChannel, ecFailResetTimer, ecFailResetRegime, ecFailInit, ecFailReadReady, ecFailStart, ecWaitReadyTimeOut, {11} ecFailReadChannel, ecFailCalibrate0, ecBadControllerState); tFlag=(fFastStart, fExInitDone, fInitialResetDone, fResetCtrlDone, fResetChannelsDone, fResetRegimeDone, fResetParametersDone, fCalibrationValid); tFlags=set of tFlag; tChannel=1..9; tChannelName=(cnPNC1,cnPNC2,cnPNC3,cnPNC4,cnPNC5,cnPNC6, cnReserved7,cnReserved8, cnSEM); tChannels=set of tChannel; tChannelNames=set of tChannelName; const cChannelU2V=1000; type tCalibrationData=record K:longint; A:longint; end; tChannelData=record Counter:longint; Calibration:tCalibrationData; end; tChannelsData=array[tChannel] of tChannelData; tCountersData=array[tChannel] of longint; { Запись управляющих слов } tControlPortsNumber=1..6; tControlPorts=record case byte of 1:(owLo123, owHi123, owLo456, owHi456, owLo789, owHi789:word); 2:(Port:array[tControlPortsNumber] of word); end; tDataPort=record rwLo, rwHi:word; end; { Чтение данных } tDataPortsNumber=1..18; tDblDataPortsNumber=1..9; tDataPorts=record case byte of 1:(rwLo1, rwHi1, rwLo2, rwHi2, rwLo3, rwHi3, rwLo4, rwHi4, rwLo5, rwHi5, rwLo6, rwHi6, rwLo7, rwHi7, rwLo8, rwHi8, rwLo9, rwHi9:word); 2:(Port:array[1..18] of word); 3:(DblPort:array[1..9] of tDataPort); end; tPorts=record { Управление контроллером } rwReset_Start, rwGate_ResetInt, owRegime, rwReady_SuspendCount, { Управление таймером } owTimerControl, rwTimerChannel1, rwTimerChannel0:word; { Запись управляющих слов } owCtrl:tControlPorts; { Чтение данных } rwData:tDataPorts; end; tData=record Flags:tFlags; Ports:tPorts; Regime:tRegime; IntegrationTime:word; Channels:tChannels; ActiveChannelsCount:word; ChlData:tChannelsData; RegimeDelayTime:word; end; tTmpCtrlData=record end; tCtrl=object(c_Ctrl1.tCtrl) function Name:tName; virtual; { НЕисполняемые функции (без ввода/вывода в порты)} { Инициализация (без ввода/вывода в порты)} constructor InitDefault(var Bus:c_Bus.tCtrl); constructor Init(var Bus:c_Bus.tCtrl; Ports:tPorts); destructor Done; { Установка параметров (без ввода/вывода в порты)} procedure Regime(x:tRegime); procedure IntegrationTime(x:word); procedure RegimeDelayTime(x:word); function CurRegimeDelayTime:word; procedure ActiveChannels(x:tChannels); procedure FastMode(x:boolean); { Чтение текущих значений счетчиков (последнее измерение, без ввода/вывода в порты)} function Channel(x:tChannel):longint; { счетчик без преобразований } function ChannelU(x:tChannel):longint; { напряжение [В]*10e-3 требует калибровки } { Чтение текущих значений параметров (без ввода/вывода в порты)} procedure CurActiveChannels(var x:tChannels); procedure CurRegime(var x:tRegime); function CurIntegrationTime:word; function CurFastMode:boolean; { среднее по каналам счетчиков X без преобразования } function CurAverageOverChannels(x:tChannels):longint; function CurAverageOverActiveChannels:longint; procedure SetNoError; virtual; procedure SetErrorCode(ec:tErrorCode); { Текст сообщения об ошибке (без ввода/вывода в порты)} function ErrorMessage(en:tErrorCode):string; virtual; { Сохранение/восстановление состояния контроллера } function DataSize:word; procedure Save(var DataPtr:pointer); procedure exRestore(var DataPtr:pointer); { Исполняемые функции (ввод/вывод в порты)} procedure exInit; virtual; procedure exDone; virtual; procedure exCalibrate(U0, U1:longint); { калибровка счетчиков } function CalibrationValid:boolean; { TRUE - правильная калибровка счетчиков } procedure ClearCalibrationValid; { } procedure exGetData; { запуск измерения и чтение данных} procedure exStart; { запуск измерения } function exReady:boolean; { проверка готовности к чтению данных } procedure exRead; { чтение данных (с ожиданием готовности) } procedure exRegime; { установка режима } procedure exResetAll; { полный аппаратный сброс и инициализация } procedure exDetectCtrl(var x:tCtrlAlive); virtual; private prBusPtr:c_Bus.tCtrlPtr; prData:tData; { prTmpData:tTmpCtrlData;} procedure AllCounters(var x:tCountersData); { СКРЫТЫЕ Исполняемые функции (ввод/вывод в порты)} procedure exInitialReset; procedure exResetCtrl; procedure exWaitTime(t:longint); { ожидание готовности к чтению данных } procedure exWait; { ожидание готовности к чтению данных } procedure exWaitShort; { ожидание готовности (короткий интервал) } procedure exResetRegime; { реальная установка режима } procedure exResetParameters; procedure exResetChannels; procedure exResetTimer; procedure exStartCount; function exReadChannel(x:tChannel):longint; end; IMPLEMENTATION USES DataSave, MiscFunc; const cCtrlAlive=3; { число портов <>$FF для "живого" контроллера, используется для детектирования наличия } cCVF_ReadyMask=1; cCVF_CountInProgress=1; cCNF_CountComplete=0; bitRegime_BaseVoltageIsZero= (1 shl 0); { иначе опора -9V} bitRegime_InputSignalIsMagnet=(1 shl 1); { иначе на вход подана шина опоры } bitRegime_DoNotInvertSignal= (1 shl 2); { иначе входной сигнал инвертируется } cDefaultPorts:tPorts=( { Управление контроллером } rwReset_Start: $7C; rwGate_ResetInt: $7D; owRegime: $7E; rwReady_SuspendCount:$7F; { Управление таймером } owTimerControl:$78; rwTimerChannel1:$7A; rwTimerChannel0:$7B; { Запись управляющих слов } owCtrl:( owLo123:$60; owHi123:$64; owLo456:$68; owHi456:$6C; owLo789:$70; owHi789:$74 ); { Чтение данных } rwData:( rwLo1:$63; rwHi1:$67; rwLo2:$62; rwHi2:$66; rwLo3:$61; rwHi3:$65; rwLo4:$6B; rwHi4:$6F; rwLo5:$6A; rwHi5:$6E; rwLo6:$69; rwHi6:$6D; rwLo7:$73; rwHi7:$77; rwLo8:$72; rwHi8:$76; rwLo9:$71; rwHi9:$75 ) ); {------------------------------------------------------------------------} { Инициализация (без ввода/вывода в порты)} constructor tCtrl.Init(var Bus:c_Bus.tCtrl; Ports:tPorts); var i:tChannel; begin If Bus.ErrorCode=0 then begin Inherited Init; if ErrorCode<>0 then begin Fail; Exit; end; prBusPtr:=@Bus; prData.Ports:=Ports; prData.Flags:=[]; Regime(cDefaultRegime); IntegrationTime(cDefaultIntegrationTime); ActiveChannels(cDefaultChannels); TimeOut(cDefaultTimeOut); RegimeDelayTime(cDefaultDelayTime); for i:=tChannel(1) to tChannel(9) do with prData.ChlData[i] do begin Counter:=0; Calibration.K:=0; Calibration.A:=0; end; end else begin SetErrorCode(tErrorCode(ecBadBus)); end; end; constructor tCtrl.InitDefault(var Bus:c_Bus.tCtrl); begin Init(Bus, cDefaultPorts); end; destructor tCtrl.Done; begin Inherited Done; prData.Flags:=[]; end; function tCtrl.Name; begin Name:='CVF'; end; procedure tCtrl.exRestore; begin CheckExInitDone; Inherited exRestore(DataPtr); RestoreData(DataPtr, prData, SizeOf(prData)); if ErrorCode=0 then begin prData.Flags:=prData.Flags-[fResetCtrlDone, fResetChannelsDone, fResetRegimeDone, fResetParametersDone ]; exResetAll; end; end; procedure tCtrl.Save; begin Inherited Save(DataPtr); StoreData(DataPtr, prData, SizeOf(prData)); end; function tCtrl.DataSize:word; begin DataSize:=Inherited DataSize + DataSave.SizeOfData(SizeOf(prData)); end; {------------------------------------------------------------------------} { Установка параметров (без ввода/вывода в порты)} procedure tCtrl.Regime(x:tRegime); begin if prData.Regime<>x then begin prData.Regime:=x; Exclude(prData.Flags, fResetRegimeDone); end; end; procedure tCtrl.IntegrationTime(x:word); begin if prData.IntegrationTime<>x then begin prData.IntegrationTime:=x; Exclude(prData.Flags, fResetParametersDone); ClearCalibrationValid; end; end; procedure tCtrl.RegimeDelayTime(x:word); begin prData.RegimeDelayTime:=x; end; function tCtrl.CurRegimeDelayTime:word; begin CurRegimeDelayTime:=prData.RegimeDelayTime; end; procedure tCtrl.ActiveChannels(x:tChannels); var i:tChannel; begin if prData.Channels<>x then begin prData.Channels:=x; prData.ActiveChannelsCount:=0; for i:=1 to 9 do begin if not (i in x) then begin prData.ChlData[i].Counter:=0; end else begin Inc(prData.ActiveChannelsCount); end; end; { Exclude(prData.Flags, fParametersDone);} ClearCalibrationValid; end; end; procedure tCtrl.FastMode(x:boolean); begin if x then Include(prData.Flags,fFastStart) else Exclude(prData.Flags,fFastStart); end; {------------------------------------------------------------------------} { Чтение текущих значений параметров (без ввода/вывода в порты)} function tCtrl.Channel(x:tChannel):longint; begin Channel:=prData.ChlData[x].Counter; end; function tCtrl.CurAverageOverChannels(x:tChannels):longint; { среднее по каналам счетчиков X без преобразования } var i:tChannel; c, c1:longint; count:word; ac:tChannels; begin c:=0; CurActiveChannels(ac); x:=x*ac; count:=0; for i:=1 to 9 do if (i in x) then Inc(count); if Count>0 then begin c1:=0; for i:=1 to 9 do if (i in x) then with prData.ChlData[i] do begin Inc(c, (Counter div count)); Inc(c1, (Counter mod count)); end; c:=c+(c1 div Count); end; CurAverageOverChannels:=c; end; function tCtrl.CurAverageOverActiveChannels:longint; { среднее по каналам счетчиков X без преобразования } var i:tChannel; c, c1:longint; begin c:=0; if prData.ActiveChannelsCount>0 then begin c1:=0; for i:=1 to 9 do if (i in prData.Channels) then with prData.ChlData[i] do begin Inc(c, (Counter div prData.ActiveChannelsCount)); Inc(c1, (Counter mod prData.ActiveChannelsCount)); end; c:=c+(c1 div prData.ActiveChannelsCount); end; CurAverageOverActiveChannels:=c; end; function tCtrl.ChannelU(x:tChannel):longint; begin with prData.ChlData[x] do ChannelU:=Calibration.K*Counter+Calibration.A; end; procedure tCtrl.CurRegime(var x:tRegime); begin x:=prData.Regime; end; function tCtrl.CurIntegrationTime:word; begin CurIntegrationTime:=prData.IntegrationTime; end; procedure tCtrl.CurActiveChannels(var x:tChannels); begin x:=prData.Channels; end; function tCtrl.CurFastMode:boolean; begin CurFastMode:=(fFastStart in prData.Flags); end; function tCtrl.CalibrationValid:boolean; { TRUE - правильная калибровка счетчиков } begin CalibrationValid:=(fCalibrationValid in prData.Flags); end; procedure tCtrl.ClearCalibrationValid; { } begin Exclude(prData.Flags, fCalibrationValid ); end; {------------------------------------------------------------------------} { Исполняемые функции (ввод/вывод в порты)} procedure tCtrl.exInitialReset; begin CheckExInitDone; if not (fInitialResetDone in prData.Flags) then exResetCtrl; end; procedure tCtrl.exInit; begin Inherited exInit; exResetAll; end; procedure tCtrl.exDone; begin CheckExInitDone; prData.Flags:=[]; Regime(cDefaultRegime); IntegrationTime(cDefaultIntegrationTime); ActiveChannels(cDefaultChannels); TimeOut(cDefaultTimeOut); exResetAll; Inherited exDone; end; procedure tCtrl.exGetData; begin exStart; exRead; end; procedure tCtrl.exCalibrate(U0, U1:longint); var N0:tCountersData; OldRegime:tRegime; i:byte; x:longint; begin CheckExInitDone; exWait; exResetCtrl; exWaitShort; if ErrorCode=0 then begin ClearCalibrationValid; CurRegime(OldRegime); Regime(cCalibrationRegime0); exGetData; AllCounters(N0); Regime(cCalibrationRegime1); exGetData; i:=cFirstChannel; while (ErrorCode=0) and (i<=cLastChannel) do begin if (i in prData.Channels) then with prData.ChlData[i] do begin {U = K*N + A} {N1=Counter} x:=Counter - N0[i]; if x<>0 then begin Calibration.K:=(U1-U0) div x; Calibration.A:=U1-Calibration.K*Counter; end else begin SetErrorCode(tErrorCode(ecFailCalibrate0)); end; end; Inc(i); end; if ErrorCode=0 then Include(prData.Flags, fCalibrationValid); Regime(OldRegime); exRegime; end; end; procedure tCtrl.exRegime; { установка рабочего режима } begin CheckExInitDone; exWait; exResetCtrl; exWaitShort; if ErrorCode=0 then begin exResetRegime; end; end; procedure tCtrl.exStart; begin CheckExInitDone; exWait; exResetRegime; exWaitShort; exResetCtrl; if (fFastStart in prData.Flags) then begin if not (fResetChannelsDone in prData.Flags) then exResetChannels; if not (fResetParametersDone in prData.Flags) then exResetParameters; end else begin exResetChannels; exResetParameters; end; exWaitShort; exStartCount; end; function tCtrl.exReady:boolean; begin CheckExInitDone; exReady:=False; if ErrorCode=0 then begin exReady:=((prBusPtr^.exInByte(prData.Ports.rwReady_SuspendCount) and cCVF_ReadyMask) = cCNF_CountComplete); if prBusPtr^.ErrorCode<>0 then begin SetErrorCode(tErrorCode(ecFailReadReady)); exReady:=False; end; end; end; procedure tCtrl.exRead; var i:tChannel; IntegrTime, HalfIntegrTime:longint begin CheckExInitDone; exWait; if ErrorCode=0 then begin IntegrTime:=CurIntegrationTime; HalfIntegrTime:=IntegrTime div 2; for i:=1 to 9 do begin if i in prData.Channels then begin prData.ChlData[i].Counter:= (exReadChannel(i)*1000+HalfIntegrTime) div IntegrTime; end; end; end; end; procedure tCtrl.exResetAll; begin CheckExInitDone; exResetCtrl; exWaitShort; exResetParameters; exResetChannels; exResetRegime; end; {------------------------------------------------------------------------} procedure tCtrl.SetNoError; begin prBusPtr^.SetErrorCode(0); Inherited SetNoError; end; procedure tCtrl.SetErrorCode(ec:tErrorCode); begin Inherited SetErrorCode(ec); if ec <> 0 then prData.Flags:=[]; end; { Текст сообщения об ошибке (без ввода/вывода в порты)} function tCtrl.ErrorMessage(en:tErrorCode):string; begin case tErrorCodes(en) of ecFailResetController: ErrorMessage:='Ошибка команды Reset контроллера (ПНЧ)'; ecFailResetChannel: ErrorMessage:='Ошибка команды ResetChannel (ПНЧ)'; ecFailResetTimer: ErrorMessage:='Ошибка команды ResetTimer (ПНЧ)'; ecFailResetRegime: ErrorMessage:='Ошибка команды ResetRegime (ПНЧ)'; ecFailInit: ErrorMessage:='Ошибка инициализации (ПНЧ)'; ecFailReadReady: ErrorMessage:='Ошибка чтения байта состояния ReadReady (ПНЧ)'; ecFailStart: ErrorMessage:='Ошибка запуска счета Start (ПНЧ)'; ecWaitReadyTimeOut: ErrorMessage:='Истекло время ожидания заверщения счета WaitReady (ПНЧ)'; ecFailReadChannel: ErrorMessage:='Ошибка чтения счетчиков (ReadChannel) (ПНЧ)'; ecBadControllerState: ErrorMessage:='Ошибочное состояние контроллера'; else ErrorMessage:=Inherited ErrorMessage(en)+' (ПНЧ)'; end; end; {------------------------------------------------------------------------} { * PRIVATE секция } { СКРЫТЫЕ Исполняемые функции (ввод/вывод в порты)} procedure tCtrl.AllCounters(var x:tCountersData); var i:tChannel; begin for i:=tChannel(1) to cLastChannel do with prData.ChlData[i] do begin x[i]:=Counter; end; end; procedure tCtrl.exResetChannels; var i:byte; const h3474B4:array[1..3] of byte=($34, $74, $B4); hFFFF :array[1..2] of byte=($FF, $FF); begin if ErrorCode=0 then begin with prBusPtr^ do begin for i:=Low(tControlPortsNumber) to High(tControlPortsNumber) do begin exOutBytes(prData.Ports.owCtrl.Port[i], h3474B4, 3); end; for i:=Low(tDataPortsNumber) to High(tDataPortsNumber) do begin exOutBytes(prData.Ports.rwData.Port[i], hFFFF, 2); end; end; if prBusPtr^.ErrorCode=0 then begin Include(prData.Flags, fResetChannelsDone); Exclude(prData.Flags, fResetParametersDone); end else begin SetErrorCode(tErrorCode(ecFailResetChannel)); end; end; end; procedure tCtrl.exResetParameters; begin exResetTimer; if ErrorCode=0 then begin Include(prData.Flags, fResetParametersDone); end; end; procedure tCtrl.exResetTimer; begin if ErrorCode=0 then begin with prBusPtr^ do begin exOutByte(prData.Ports.owTimerControl, $32); exOutBytes(prData.Ports.rwTimerChannel0, prData.IntegrationTime, 2); end; if prBusPtr^.ErrorCode<>0 then begin SetErrorCode(tErrorCode(ecFailResetTimer)); end; end; end; procedure tCtrl.exResetRegime; begin if (ErrorCode=0) and not (fResetRegimeDone in prData.Flags) then begin prBusPtr^.exOutByte(prData.Ports.owRegime, Byte(prData.Regime)); if prBusPtr^.ErrorCode<>0 then begin SetErrorCode(tErrorCode(ecFailResetRegime)); end else begin { задержка на срабатывание реле } prBusPtr^.Delay(CurRegimeDelayTime); Include(prData.Flags, fResetRegimeDone); end; end; end; procedure tCtrl.exResetCtrl; begin if ErrorCode=0 then begin prBusPtr^.exInByte(prData.Ports.rwReset_Start); if prBusPtr^.ErrorCode=0 then begin Include(prData.Flags,fInitialResetDone) end else begin SetErrorCode(tErrorCode(ecFailResetController)); end; end; end; procedure tCtrl.exWaitTime(t:longint); begin if ErrorCode=0 then begin if prBusPtr^.exWait(prData.Ports.rwReady_SuspendCount, cCVF_ReadyMask, cCNF_CountComplete, t)<>0 then begin SetErrorCode(tErrorCode(ecWaitReadyTimeOut)); end; end; end; procedure tCtrl.exWait; begin exWaitTime(prData.IntegrationTime+CurTimeOut); end; procedure tCtrl.exWaitShort; begin exWaitTime(CurTimeOut); end; procedure tCtrl.exStartCount; const ZW:word=0; begin if ErrorCode=0 then begin prBusPtr^.exOutByte(prData.Ports.rwGate_ResetInt, 0); prBusPtr^.exOutBytes(prData.Ports.rwReady_SuspendCount, ZW, 2); prBusPtr^.exOutByte(prData.Ports.rwReset_Start, 0); if prBusPtr^.exWait(prData.Ports.rwReady_SuspendCount, cCVF_ReadyMask, cCVF_CountInProgress, CurTimeOut)<>0 then begin SetErrorCode(tErrorCode(ecFailStart)); end; end; end; function tCtrl.exReadChannel(x:tChannel):longint; type tChannelInputData=record case byte of 0:(l:longint); 1:(w1,w2:word); 2:(b1,b2,b3,b4:byte); end; var d:tChannelInputData; begin exReadChannel:=0; if ErrorCode=0 then begin prBusPtr^.exInBytes(prData.Ports.rwData.DblPort[x].rwLo, d.w1, 2); prBusPtr^.exInBytes(prData.Ports.rwData.DblPort[x].rwHi, d.w2, 2); { d.l:=not d.l;} d.w1:=not d.w1; d.w2:=not d.w2; (* Inc(d.w1); { ??? может это лишнее? }*) Dec(d.w1); { ??? может это лишнее? } exReadChannel:=d.l; if prBusPtr^.ErrorCode<>0 then begin SetErrorCode(tErrorCode(ecFailReadChannel)); end; end; end; procedure tCtrl.exDetectCtrl(var x:tCtrlAlive); var c:word; begin c:=prBusPtr^.exScanNotFFports(prData.Ports, (SizeOf(prData.Ports) shr 1)); case c of cCtrlAlive:x:=aYes; 0: x:=aNo; else if c>=(cCtrlAlive shr 1) then x:=aMayBeYes else x:=aMayBeNo; end; end; END.