{ Контроллер развертки 5.105.178 (АК-8) } {--------------------------------------------------------------------------- The control units for mass-spectrometer MI1201-AGM (c) Copyright Aleksandrov O.E., 1999 Molecular Physics department, USTU, Ekaterinsburg, K-2, 620002, RUSSIA phone 75-47-15 E-mail: aleks@dpt.ustu.ru Модуль управления масс-спектрометром МИ1201-АГМ (c) Собственность Александрова О.Е., 1999 620002, Екатеринбург, К-2, УГТУ, Кафедра молекулярной физики тел. 75-47-15 E-mail: aleks@dpt.ustu.ru ----------------------------------------------------------------------------} Unit c_Roll; {$X+} INTERFACE USES c_Ctrl, c_Ctrl1, c_Bus, {$IfNDef Seg16} sysutils,{$EndIf} MITypes; const cMaxSingleStepCount=255; { максимальное число импулсов, выдаваемое за раз } cInitialSingleStepCount=1; { начальное значение числа импулсов, выдаваемых за раз } cDefaultAutoTuning=False; { автоcтабилизация магн. поля } cDefaultResetRetryCount=200; { количество повторных попыток аппаратного сброса контроллера эл.магнита, при неудачах } cDefaultResetRetryDelay=50; { миллисекунд. Задержка повтора попытки аппаратного сброса при неудаче } cDefaultTimeOut=2000; { миллисекунд. Ожидание готовности } cOverloadLimitTime=200; { миллисекунд. Ожидание готовности развертки, трактуемое как перегрузка} cDefaultReverseDelay=0; { миллисекунд. Задержка перед выдачей импульсов, при смене полярности импульсов на противоположную } cRepeatWaitDelay=2; { миллисекунд. Задержка для проверки стабильности сигнала "ГОТОВ"} cDefaultFrequency=64000; { Гц - частота импульсов развертки } cCounterRange=1000000; {максимальный диапазон счетчика импульсов} type { Коды ошибок } tErrorCodes=({$I C_ErrCds.Inc}, ecFailExInit, ecFailReadFlags, ecFailResetCtrl, ecFailAutoTuning, ecDoSmallStepInOutError, exDoSmallStepFTimeOutBefore, exDoSmallStepFTimeOutAfter, exDoSmallStepFTimeOutAfterUpLimit, ecBadControllerState); { Внутренние флаги } tFlag=( fFast_exInit, fHandleLimit, fSimplified_exInit, fLogarithmicFineTune, fAutoTuning, fIgnoreAutoTuning); tFlags=set of tFlag; tRunTimeFlag=(fResetDone, fIgnoreHardwareLimits, fLastScrollUp, fScrollOccured, fLimitReached); tRunTimeFlags=set of tRunTimeFlag; tPolarity=1..2; { 1 - отрицательная; 2 - положительная } tAutoTuning=0..1; tCtrlFlag=(fScrollInProgress, fScrollDownAvailable, fScrollUpAvailable, fRoll, f4, f5, f6, f7); tCtrlFlags=set of tCtrlFlag; tPort=(powCounter, prwReset_Polarity, prwFlags_AutoTuning); tPortsArray=array[tPort] of Byte; tPorts=record case byte of 0:(owCounter, rwReset_Polarity, rwFlags_AutoTuning:word); 1:(Ports:array[tPort] of word); end; tCounterData=record Value:tMagnetCounter; { общий счетчик импульсов } end; tData=record {внутренние} Flags:tFlags; Counter:tCounterData; {внешние параметры} Ports:tPorts; { порты контроллера } Amplitude:word; { амплитуда FineTune } Decrement:word; { затухание FineTune } ResetRetryCount:word; { число попыток аппаратного сброса } ResetRetryDelay:word; { мс, задержка повтора попыток аппаратного сброса } ReverseDelay:word; { мс, задержка перед началом выдачи импульсов противоположной полярности } OverloadLimitTime:word; { мc, ожидание готовности развертки, трактуемое как перегрузка} RepeatWaitDelay:word; { мс, задержка повторной проверки сигнала "Готов" } DelayAfterStartRoll:word; { мс, задержка после старта развертки } PortsData:tPortsArray; {данные из портов при выходе из программы} end; tStepCounter=0..cMaxSingleStepCount; tTmpData=record BusPtr:c_Bus.tCtrlPtr; Flags:tRunTimeFlags; SingleStepCount:tStepCounter; { текущий шаг развертки [импульсы]} CounterValue:tMagnetCounter; { текущее значение счетчика импульсов } end; {srOverloadN позволяет судить об интенсивности перегрузки} TStepResult=(srOK, srError); type { Контроллер } 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; function AutoTuning:boolean; { текущее значение счетчика импульсов } function Counter:tMagnetCounter; { Переустановка глобального счетчика импульсов } procedure CounterRefine(x:tMagnetCounter); { Параметры прокрутки магнита } { число попыток и интервал повтора аппаратного сброса контроллера } procedure ResetRetry(Count, DelayTime:word); procedure CurResetRetry(var Count, DelayTime:word); { задержка при смене направления изменения магн. поля } procedure ReverseDelay(x:word); function CurReverseDelay:word; { достигнут предел изменения поля (верхний либо нижний )} function LimitReached:boolean; { достигнут нижний предел изменения поля. !!! Применима только в случае LimitReached=TRUE } function LowLimit:boolean; function UpLimit:boolean; { включение быстрой инициализации без прокрутки магнита по полному аппаратному диапазону } procedure FastExInitSet(x:boolean); function FastExInit:boolean; procedure SimpleExInitSet(x:boolean); function SimpleExInit:boolean; { Установка магнита с затуханием амплитуды - для искоренения гистерезисных эффектов. Amplitude - начальная амплитуда колебаний; Decrement - затухание; Logarithmic - логарифмическое затухание. } procedure FineTune(Amplitude, Decrement:word; Logarithmic:boolean); procedure CurFineTune(var Amplitude, Decrement:word; var Logarithmic:boolean); procedure SetErrorCode(ec:tErrorCode); function ErrorMessage(en:tErrorCode):string; virtual; procedure SetNoError; virtual; { установка параметров тонкой настройки контроллера. В обычных условиях менять их не следует. } procedure RepeatWaitDelay(x:word); procedure DelayAfterStartRoll(x:word); function OverloadLimitTime:word; procedure OverloadLimitTimeSet(x:word); { Сохранение/восстановление состояния контроллера } function DataSize:word; // procedure Save(var DataPtr:pointer); // procedure exRestore(var DataPtr:pointer); function Restore(var DataPtr:pointer):boolean; function Save(var DataPtr:pointer):boolean; { Инициализация оборудования ( прокручивает магнит от минимума до максимума и определяет рабочий диапазон счетчика числа импульсов) } procedure exInit; virtual; // procedure exReInit; virtual; procedure exDone; virtual; { Прокручивает магнит на x импульсов с учетом знака } function exScroll(x:tMagnetCounter):tMagnetCounter; function exJumpTo(x:tMagnetCounter):tMagnetCounter; { Прокручивает магнит на до нижней АППАРАТНОЙ границы и устанавливает TotalCounter=0, после чего выводит на значение счетчика CurLoBound } function exScrollToLowLimit:tMagnetCounter; function exScrollToAbsoluteLowLimit:tMagnetCounter; { возвращает аппаратные флаги состояния контроллера } procedure exCurFlags(x:tCtrlFlags); { Cостояние автостабилизации магнитного поля в момент отсутствия выдачи импульсов } procedure exCurAutoTuning; procedure exAutoTuning(x:boolean); { Установка магнита с затуханием амплитуды. Медленная процедура (из-за задержки реверса). } procedure exFineTune; procedure exDetectCtrl(var x:tCtrlAlive); virtual; private prData:tData; { данные подлежащие сохранению } prTmpData:tTmpData; { данные НЕподлежащие сохранению } { Установка глобального счетчика импульсов } procedure CounterSet(x:tMagnetCounter); { procedure CheckLimitInWait; procedure LimitControl;} // procedure Delay(x:word); // procedure DelayBeforeReverse; { Битовые флаги состояния контроллера } function exFlags:byte; { Информация о достижении предела } function exLimit:boolean; {=TRUE, если стоит аппаратная блокировка предела } function exLoLimit:boolean; {=TRUE, если стоит аппаратная блокировка предела } function exUpLimit:boolean; {=TRUE, если стоит аппаратная блокировка предела } function exIsReady:boolean; { ожидание сигнала "ГОТОВ" без проверки стабильности и БЕЗ возбуждения ошибки ecTimeOut в контроллере. Ошибка ecTimeOut возбуждается только в контроллере шины при неудачном ожидании } function exWaitOk(Time:word):boolean; function exLazyWaitOk(Time:word):boolean; { ожидание сигнала "ГОТОВ" без проверки стабильности } function exWaitReady:boolean; function exLazyWaitReady:boolean; { Информация о негодном состоянии контроллера } function exBadState:boolean; { аппаратный сброс контроллера с повтором при неудачах (см. ResetRetry)} procedure exResetCtrl; { ожидание готовности с проверкой перегрузки после выдачи импульсов развертки } function exCheckOverloadF:integer; { изменение магн. поля на величину не более cMaxSingleStepCount импульсов} function exDSSOutByte(Port:word; b:byte):boolean; function exDoSmallStepF(x:tStepCounter; p:tPolarity):integer; { уст. состояния автостабилизации магнитного поля в момент отсутствия выдачи импульсов (0-выкл; 1-вкл.)} procedure exSetAutoTuning(x:tAutoTuning); {Процедуры сохранения значений в портах} procedure exReadPortsData(var PD:tPortsArray); procedure exSavePortsData; function exIsNotChangedPortsData:boolean; procedure ClearPortsData; { время [мкс] ожидания на выдачу импульсов } function ImpulsesTime_mkS(x:word):longint; function ImpulsesTime_mS(x:tMagnetCounter):longint; { время [мс] ожидания после выдачи импульсов (RollDelayTime_mS >=1) } function RollDelayTime_mS(ImpulsesNumber:word):word; function RollDelayTime_mkS(ImpulsesNumber:word):longint; function ImpulsesFrequency_Hz:longint; // procedure DelayRoll(ImpulsesNumber:byte); { Вспомогательные функции определния наличия питания, см. exIsPowerON} function PortsNumber:word; virtual; function exReadSafePorts(var PortsValues:tPortValuesArray; Count:word):boolean; virtual; end; IMPLEMENTATION USES {$IfNDef Seg16}Windows,{$EndIf} xStrings, DataSave, MiscFunc; const cCtrlAlive=3; cpScrollUp=1; cpScrollDown=2; cMaskStart=1+2+4+8; cPattStart=1+2+4+8; cBitStart=1; cMaskReady=1+2+4+8; cPattReady= 2+4+8; cMaskReadyX=0+1; cPattReadyX=0+0; cDefaultPorts:tPorts=( owCounter: $B1; rwReset_Polarity: $B2; rwFlags_AutoTuning:$B3 ); const cMaxMagnetCounter=High(tMagnetCounter)-100; function Polarity(x:tMagnetCounter):tPolarity; begin if x<0 then Polarity:=cpScrollDown else Polarity:=cpScrollUp; end; {------------------------------------------------------------------------} { Инициализация (без ввода/вывода в порты)} constructor tCtrl.Init(var Bus:c_Bus.tCtrl; Ports:tPorts); begin Inherited Init; prTmpData.BusPtr:=@Bus; prTmpData.SingleStepCount:=cInitialSingleStepCount; prTmpData.Flags:=[]; prData.Ports:=Ports; prData.Flags:=[]; TimeOut(cDefaultTimeOut); CounterSet(0); FineTune(5000, 100, False); ResetRetry(cDefaultResetRetryCount, cDefaultResetRetryDelay); ReverseDelay(cDefaultReverseDelay); RepeatWaitDelay(cRepeatWaitDelay); OverloadLimitTimeSet(cOverloadLimitTime); {4 мкс - длительность импульса, 64000 Гц - частота выдачи импульсов } DelayAfterStartRoll((ImpulsesTime_mks(cMaxSingleStepCount) div 1000)); If (Bus.ErrorCode<>0) and (ErrorCode=0) then begin SetErrorCode(tErrorCode(ecBadBus)); end; end; constructor tCtrl.InitDefault(var Bus:c_Bus.tCtrl); begin Init(Bus, cDefaultPorts); end; destructor tCtrl.Done; begin if NotInitialized then Exit; Inherited Done end; function tCtrl.Name; begin Name:='Roll'; end; (*procedure tCtrl.exRestore; begin Inherited exRestore(DataPtr); RestoreData(DataPtr, prData, SizeOf(prData)); end; *) (*procedure tCtrl.Save; begin exSavePortsData; Inherited Save(DataPtr); StoreData(DataPtr, prData, SizeOf(prData)); end;*) function tCtrl.Restore(var DataPtr:pointer):boolean; begin if Inherited Restore(DataPtr) then Restore:=RestoreDataEx(DataPtr, prData, SizeOf(prData)) else Restore:=FALSE; end; function tCtrl.Save(var DataPtr:pointer):boolean; begin if Inherited Save(DataPtr) then Save:=StoreDataEx(DataPtr, prData, SizeOf(prData)) else Save:=FALSE; end; (*procedure tCtrl.exRestoreX; var c:tMagnetCounter; begin { CheckExInitDone;} c:=Counter; exRestore(DataPtr); CounterSet(prTmpData.CounterValue); exJumpTo(c); end; *) function tCtrl.DataSize:word; begin DataSize:=Inherited DataSize + DataSave.SizeOfData(SizeOf(prData)); end; {------------------------------------------------------------------------} { Установка параметров (без ввода/вывода в порты)} procedure tCtrl.FineTune(Amplitude, Decrement:word; Logarithmic:boolean); begin prData.Amplitude:=Amplitude; prData.Decrement:=Decrement; if Logarithmic then Include(prData.Flags, fLogarithmicFineTune) else Exclude(prData.Flags, fLogarithmicFineTune); end; procedure tCtrl.CounterSet(x:tMagnetCounter); begin prData.Counter.Value:=x; prTmpData.CounterValue:=x; end; procedure tCtrl.ResetRetry(Count, DelayTime:word); begin prData.ResetRetryCount:=Count; prData.ResetRetryDelay:=DelayTime; end; procedure tCtrl.ReverseDelay(x:word); begin prData.ReverseDelay:=x; end; procedure tCtrl.FastExInitSet(x:boolean); begin if x then Include(prData.Flags, fFast_exInit) else Exclude(prData.Flags, fFast_exInit); end; function tCtrl.FastExInit:boolean; begin FastExInit:=(fFast_exInit in prData.Flags); end; procedure tCtrl.SimpleExInitSet(x:boolean); begin if x then Include(prData.Flags, fSimplified_exInit) else Exclude(prData.Flags, fSimplified_exInit); end; function tCtrl.SimpleExInit:boolean; begin SimpleExInit:=(fSimplified_exInit in prData.Flags); end; procedure tCtrl.RepeatWaitDelay(x:word); begin prData.RepeatWaitDelay:=x; end; procedure tCtrl.DelayAfterStartRoll(x:word); begin prData.DelayAfterStartRoll:=x; end; {------------------------------------------------------------------------} { Чтение текущих значений параметров (без ввода/вывода в порты)} procedure tCtrl.CurResetRetry(var Count, DelayTime:word); begin Count:=prData.ResetRetryCount; DelayTime:=prData.ResetRetryDelay; end; function tCtrl.CurReverseDelay:word; begin CurReverseDelay:=prData.ReverseDelay; end; procedure tCtrl.CurFineTune(var Amplitude, Decrement:word; var Logarithmic:boolean); begin Amplitude:=prData.Amplitude; Decrement:=prData.Decrement; Logarithmic:=fLogarithmicFineTune in prData.Flags; end; function tCtrl.AutoTuning:boolean; begin AutoTuning:=(fAutoTuning in prData.Flags); end; function tCtrl.Counter:tMagnetCounter; begin Counter:=prData.Counter.Value; end; procedure tCtrl.CounterRefine(x:tMagnetCounter); begin CounterSet(x); end; function tCtrl.LimitReached:boolean; begin LimitReached:=(fLimitReached in prTmpData.Flags); end; function tCtrl.LowLimit:boolean; begin LowLimit:=LimitReached and not (fLastScrollUP in prTmpData.Flags); end; function tCtrl.UpLimit:boolean; begin UpLimit:=LimitReached and (fLastScrollUP in prTmpData.Flags); end; function tCtrl.ImpulsesFrequency_Hz; begin ImpulsesFrequency_Hz:=cDefaultFrequency; end; function tCtrl.ImpulsesTime_mkS; var fi:longint; begin fi:=ImpulsesFrequency_Hz; ImpulsesTime_mkS:=(LongInt(x)*1000000 + (fi div 2)) div fi; end; function tCtrl.ImpulsesTime_mS; begin x:=Abs(x); if x>cCounterRange then x:=cCounterRange; ImpulsesTime_mS:=((x shr 6)*RollDelayTime_mS(255)); end; function tCtrl.RollDelayTime_mS; var i:longint; begin i:=ImpulsesTime_mkS(ImpulsesNumber) div 1000; if i<=0 then RollDelayTime_mS:=1 else RollDelayTime_mS:=i; end; function tCtrl.RollDelayTime_mkS; var i:longint; begin i:=ImpulsesTime_mkS(ImpulsesNumber); if i<=0 then RollDelayTime_mkS:=1 else RollDelayTime_mkS:=i; end; procedure tCtrl.SetErrorCode(ec:tErrorCode); begin if ec<>0 then Exclude(prTmpData.Flags, fResetDone); Inherited SetErrorCode(ec); end; procedure tCtrl.SetNoError; begin if prTmpData.BusPtr<>NIL then prTmpData.BusPtr^.SetNoError; Inherited SetNoError; end; function tCtrl.ErrorMessage(en:tErrorCode):string; begin case tErrorCodes(en) of ecTimeOut: ErrorMessage:='Не удалось дождаться конца выдачи импульсов'; ecFailExInit: ErrorMessage:='Ошибка инициализации оборудования'; ecFailReadFlags: ErrorMessage:='Ошибка чтения флагов состояния'; ecFailResetCtrl: ErrorMessage:='Ошибка инициализации контроллера'; ecFailAutoTuning: ErrorMessage:='Ошибка переключения автостабилизации магн. поля'; ecDoSmallStepInOutError: ErrorMessage:='Ошибка ввода/вывода в DoSmallStep'; exDoSmallStepFTimeOutBefore: ErrorMessage:='Нет готовности контр-ра в DoSmallStep при входе'; exDoSmallStepFTimeOutAfter: ErrorMessage:='Нет готовности контр-ра в DoSmallStep после выдачи импульсов'; exDoSmallStepFTimeOutAfterUpLimit: ErrorMessage:='Нет готовности контр-ра в DoSmallStep после выдачи импульсов на верх. пределе'; ecBadControllerState: ErrorMessage:='Ошибочное состояние контроллера'; else ErrorMessage:=Inherited ErrorMessage(en)+' (контр. эл.магнита)'; end; end; {------------------------------------------------------------------------} { Исполняемые функции (ввод/вывод в порты)} procedure tCtrl.exInit; begin Inherited exInit; if IsExInitDone then begin ClearPortsData; if exBadState then begin SetErrorCode(tErrorCode(ecBadControllerState)); end; prTmpData.SingleStepCount:=1; end; SetExInitDone(NoError); end; (*procedure tCtrl.exReInit; var OldFlags:tFlags; c:tMagnetCounter; begin Inherited exReInit; if IsExInitDone then begin if exBadState then begin SetErrorCode(tErrorCode(ecBadControllerState)); end else if SimpleExInit then begin SetNoError; exCurAutoTuning; end else begin OldFlags:=prData.Flags*[fIgnoreAutoTuning]; prData.Flags:=prData.Flags + [fIgnoreAutoTuning]; SetNoError; c:=Counter; CounterSet(prTmpData.CounterValue); exJumpTo(c); prData.Flags:=prData.Flags-[fIgnoreAutoTuning]+OldFlags; exCurAutoTuning; end; SetExInitDone(NoError); end; end; *) procedure tCtrl.exDone; begin if IsExDoneDone then Exit; if not CheckEXInitDone then Exit; SetNoError; exResetCtrl; Inherited exDone; exSavePortsData; end; function tCtrl.exScrollToLowLimit:tMagnetCounter; begin exScrollToLowLimit:=exScroll(-High(tMagnetCounter)); end; function tCtrl.exScrollToAbsoluteLowLimit:tMagnetCounter; begin Include(prTmpData.Flags, fIgnoreHardwareLimits); exScrollToAbsoluteLowLimit:=exScrollToLowLimit; Exclude(prTmpData.Flags, fIgnoreHardwareLimits); if (ErrorCode=Byte(Ord(exDoSmallStepFTimeOutAfter))) or (ErrorCode=Byte(Ord(exDoSmallStepFTimeOutBefore))) then SetNoError; end; procedure tCtrl.exResetCtrl; var cnt:word; ResetDone:boolean; begin CheckExInitDone; Exclude(prTmpData.Flags, fResetDone); if NoError then with prTmpData.BusPtr^ do begin if exIsReady then begin ResetDone:=True; end else begin ResetDone:=False; cnt:=prData.ResetRetryCount; if cnt=0 then Inc(cnt); repeat exOutByte(prData.Ports.owCounter, 0); { сброс счетчика } exOutByte(prData.Ports.rwReset_Polarity, 0); { сброс полярности } exInByte(prData.Ports.rwReset_Polarity); { сброс контроллера } if prTmpData.BusPtr^.Error then begin cnt:=0; end else if exWaitOk(prData.ResetRetryDelay) then begin cnt:=0; ResetDone:=True; end else begin prTmpData.BusPtr^.SetNoError; if not exBadState then begin Dec(cnt); end else begin cnt:=0; end; end; until (cnt=0); end; If not ResetDone then SetErrorCode(tErrorCode(ecFailResetCtrl)) else Include(prTmpData.Flags, fResetDone); end; end; procedure tCtrl.exCurAutoTuning; begin exAutoTuning(AutoTuning); end; procedure tCtrl.exAutoTuning(x:boolean); begin CheckExInitDone; if exWaitReady then begin if x then begin exSetAutoTuning(1); if NoError then Include(prData.Flags, fAutoTuning); end else begin exSetAutoTuning(0); if NoError then Exclude(prData.Flags, fAutoTuning); end; end; end; procedure tCtrl.exCurFlags(x:tCtrlFlags); begin CheckExInitDone; if NoError then begin Byte(x):=exFlags; if prTmpData.BusPtr^.Error then begin SetErrorCode(tErrorCode(ecFailReadFlags)); end; end; end; procedure tCtrl.exFineTune; var a, a1, d:tMagnetCounter; p:shortint; l:boolean; begin CheckExInitDone; a:=prData.Amplitude; d:=prData.Decrement; l:=(fLogarithmicFineTune in prData.Flags); if (fLastScrollUp in prTmpData.Flags) then p:=1 else p:=-1; while NoError and (a>0) do begin exScroll(p*a); if l then a1:=(a div d) else a1:=(a-d); if a1>0 then exScroll(-p*(a+a1)) else exScroll(-p*a); a:=a1; end; end; {------------------------------------------------------------------------} { * PRIVATE секция } (*procedure tCtrl.DelayBeforeReverse; begin Delay(IntelliTimeOut(prData.ReverseDelay,0)); end; *) procedure tCtrl.exSetAutoTuning(x:tAutoTuning); begin if ErrorCode=0 then begin prTmpData.BusPtr^.exOutByte(prData.Ports.rwFlags_AutoTuning, x); { выключение автонастройки } if prTmpData.BusPtr^.Error then begin SetErrorCode(tErrorCode(ecFailAutoTuning)); end; end; end; function tCtrl.exWaitOk(Time:word):boolean; begin if prTmpData.BusPtr^.NoError then begin exWaitOk:=(0= prTmpData.BusPtr^.exWait(prData.Ports.rwFlags_AutoTuning, 1,0, Time)); if prTmpData.BusPtr^.ErrorCode=Word(Ord(ecTimeOut)) then prTmpData.BusPtr^.SetNoError; end else begin exWaitOk:=FALSE; end; end; function tCtrl.exLazyWaitOk; begin if prTmpData.BusPtr^.NoError then begin exLazyWaitOk:=(0= prTmpData.BusPtr^.exLazyWait(prData.Ports.rwFlags_AutoTuning, 1,0, Time, 1)); if prTmpData.BusPtr^.ErrorCode=Word(Ord(ecTimeOut)) then prTmpData.BusPtr^.SetNoError; end else begin exLazyWaitOk:=FALSE; end; end; function tCtrl.exBadState:boolean; begin exBadState:=(prTmpData.BusPtr^.exInByte(prData.Ports.rwFlags_AutoTuning)=$FF); end; function tCtrl.exLimit:boolean; {=TRUE, если стоит аппаратная блокировка предела } begin exLimit:=exLoLimit or exUpLimit; end; function tCtrl.exLoLimit:boolean; {=TRUE, если нижний аппаратный предел } begin exLoLimit:=(( exFlags and (2+4) )=4); end; function tCtrl.exUpLimit:boolean; {=TRUE, если верхний аппаратный предел } begin exUpLimit:=(( exFlags and (2+4))=2); end; function tCtrl.exFlags:byte; begin exFlags:=prTmpData.BusPtr^.exInByte(prData.Ports.rwFlags_AutoTuning); end; procedure tCtrl.exDetectCtrl(var x:tCtrlAlive); var c:word; begin c:=prTmpData.BusPtr^.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; (*procedure tCtrl.Delay(x:word); begin prTmpData.BusPtr^.Delay(x); end;*) procedure ProcessStepResult(StepResult:integer; var Step:tStepCounter); var SepDecr:word; const cNoOvrl=30; begin if StepResult<0 then begin Step:=1; end else if StepResult<(cNoOvrl div 2) then begin {НЕТ перегрузки} if Step<(cMaxSingleStepCount div 2) then Step:=Step shl 1 else Step:=255; end else if StepResult1 then Dec(Step) else Step:=1; end else if StepResult<(cNoOvrl+15) then begin {весьма малая перегрузка} if Step>2 then Dec(Step,2) else Step:=1; end else if StepResult<(cNoOvrl+30) then begin { малая перегрузка} if StepResult>40 then SepDecr:=Step else SepDecr:=StepResult*StepResult*StepResult; if Step>SepDecr then Dec(Step,SepDecr) else Step:=1; end else if StepResult<(cNoOvrl+100) then begin {средняя перегрузка} if Step<=1 then Step:=1 else Step:=Step shr 1; { asm shr Step,1 end;} end else begin {большая перегрузка} Step:=1; end; {$IfOpt R+} if Step<=0 then RunError(201); {$EndIf} end; function tCtrl.exScroll(x:tMagnetCounter):tMagnetCounter; var InCounter,c:tMagnetCounter; p:tPolarity; Step:tStepCounter; sr:Integer; begin CheckExInitDone; If NoError and (x<>0) then begin OperationTimeSet(ImpulsesTime_mS(x)+CurTimeOut); if not (fResetDone in prTmpData.Flags) then exResetCtrl; if (fAutoTuning in prData.Flags) then begin exSetAutoTuning(0); { выключение автонастройки } end; { Вычисление модуля числа импульсов и полярности } c:=Abs(x); p:=Polarity(x); { установка текущего шага развертки } Step:=prTmpData.SingleStepCount; { Задержка реверса - ВРОДЕ БЫ НЕНУЖНА } { if ((p=cpScrollUp) <> (fLastScrollUp in prTmpData.Flags)) or ( not (fScrollOccured in prTmpData.Flags)) then DelayBeforeReverse;} { исходное значение счетчика } InCounter:=Counter; { выдача импульсов по Step штук, если c>Step } while NoError and (c>=Step) do begin Dec(c, Step); sr:=exDoSmallStepF(Step, p); ProcessStepResult(sr, Step); if LimitReached then Break; end; { выдача остатка импульсов (=0) {and (t<=OverloadLimitTime)} then begin exCheckOverloadF:=t; end else begin if (tErrorCodes(prTmpData.BusPtr^.ErrorCode)=ecTimeOut) then prTmpData.BusPtr^.SetNoError; exCheckOverloadF:=-1; end; end; function tCtrl.exDSSOutByte(Port:word; b:byte):boolean; begin prTmpData.BusPtr^.exOutByte(Port, b); if (prTmpData.BusPtr^.Error) then begin SetErrorCode(tErrorCode(ecDoSmallStepInOutError)); end; exDSSOutByte:=NoError; end; function tCtrl.exDoSmallStepF; var b:tCtrlFlags; ScrollUp:boolean; begin exDoSmallStepF:=0; //{!} Byte(b):=exFlags; if x=0 then {ничего делать не надо} Exit else if exWaitReady then begin ScrollUp:=(p=cpScrollUp); { проверка предела } if ScrollUp then begin if UpLimit then begin exDoSmallStepF:=-Ord(srError); Exit; end; end else begin if LowLimit then begin exDoSmallStepF:=-Ord(srError); Exit; end; end; { команда установки счетчика импульсов } if exDSSOutByte(prData.Ports.owCounter, x) then begin { этот сигнал определяет направление и запускает развертку } if exDSSOutByte(prData.Ports.rwReset_Polarity, p) then begin { изменение глобального счетчика импульсов } if ScrollUp then begin CounterSet(Counter+x); Include(prTmpData.Flags, fLastScrollUp); end else begin CounterSet(Counter-x); Exclude(prTmpData.Flags, fLastScrollUp); end; Include(prTmpData.Flags, fScrollOccured); { задержка на выдачу импульсов } // DelayRoll(x); { состояние контроллера эл. магнита} Byte(b):=exFlags; { ожидание окончания выдачи импульсов } { проверка перегрузки (состояния контроллера) } Result:=exCheckOverloadF; //{!} Byte(b):=exFlags; if Result<0 then begin { аппаратный предел - контроллер эл. магнита остановился } SetErrorCode(tErrorCode(exDoSmallStepFTimeOutAfter)); end else if (fIgnoreHardwareLimits in prTmpData.Flags) then begin { Игнорировать все, пока не уткнемся в аппаратный предел } if (p=cpScrollUp) and (Result>OverloadLimitTime) and (x<2) then begin { с верхним пределом стоит обращаться осторожнее } SetErrorCode(tErrorCode(exDoSmallStepFTimeOutAfterUpLimit)); end; { end else if (Result>=0) and (Result0 then SetErrorCode(Ord(ecFailReadPortsData)); end; end; procedure tCtrl.exSavePortsData; begin exReadPortsData(prData.PortsData); end; procedure tCtrl.ClearPortsData; begin ClearPortsDataX(prData.PortsData); end; function tCtrl.exIsNotChangedPortsData:boolean; var PD:tPortsArray; begin exReadPortsData(pd); exIsNotChangedPortsData:=Equal(PD,prData.PortsData,SizeOf(PD)); end; function tCtrl.OverloadLimitTime:word; begin OverloadLimitTime:=prData.OverloadLimitTime; end; procedure tCtrl.OverloadLimitTimeSet(x:word); begin prData.OverloadLimitTime:=x; end; function tCtrl.PortsNumber:word; begin PortsNumber:=1; end; function tCtrl.exReadSafePorts(var PortsValues:tPortValuesArray; Count:word):boolean; begin exReadSafePorts:=FALSE; if NoError and (Count=PortsNumber) then begin PortsValues[0]:=prTmpData.BusPtr^.exInByte(prData.Ports.Ports[prwFlags_AutoTuning]); if prTmpData.BusPtr^.Error then SetErrorCode(Ord(ecFailReadPortsData)) else exReadSafePorts:=TRUE; end; end; END.