Flow control of stepper motors via parallel port in Delphi

154 views Asked by At

I created 4 threads for each of the 4 stepper motors separately, where an infinite loop will spin with the given Dir and Step and with delays depending on the current speed for each motor. Each call to Out32 will be in a critical section.

In procedure TLPTEngine.ApplyHardware, RotDir[i], RotateStep[i] and speed (delay) TimeOut[i] will be set for each engine. The code below should start spinning the motors when the program starts, but it doesn't. When calling the OutToLptThread[i].Execute procedure in the TLPTEngine.InitializeHardware procedure, an error occurs:

"Exception EAccessViolation in module MyProgram.exe at 001CE279. Access violation at address 005CE279 in module MyProgram.exe'. Read of address 00000000."

and the program is terminated.

uses
SysUtils, Math, TraceLog, MDriveEngines, SyncObjs;

const
  numOfEngines = 4;

type
  // Class of threads that control motors
  TOutToLptThread = class(TThread)
  private
  { Private declarations }
  protected
    procedure Execute; override;
  public
    LPTEngineNum: integer; // Number of engine and thread
  end;

// Class of stepper motors
TLPTEngine = class(TEngine)
public
  procedure InitializeHardware; override;
  procedure FinalizeHardware; override;
  procedure ApplyHardware; override;
end;

var
  RotateStep: array [1 .. numOfEngines] of Integer; // Stepper motor rotation pulse via LPT-port
  RotDir: array [1 .. numOfEngines] of Integer; // Direction of rotation of stepper motor via LPT-port
  Time_out: array [1 .. numOfEngines] of Integer; // Delays in the supply of pulses to the stepper motor through the LPT-port - for different motor speeds

FSynchronizer: TCriticalSection;
OutToLptThread: array[1..numOfEngines] of TOutToLptThread; // Array of threads that control numOfEngines engines
OutToLPTData: Byte; // Common byte with all Dir and Step for tumOfEngines engines, issued to the LPT port

procedure TOutToLptThread.Execute;

procedure Delay_mcs(time_out: double); // Delay in microseconds
var
  iCounterPerSec: TLargeInteger;
  T1, T2: TLargeInteger; // Values of counter before and after operation
begin
  QueryPerformanceFrequency(iCounterPerSec);
  // We defines a frequency of counter
  QueryPerformanceCounter(T1); // Recorded the start time of the operation
  T2 := T1;

  while (T2 - T1) * 1000000 / iCounterPerSec < time_out do
    QueryPerformanceCounter(T2); // Recorded the end time of the operation
  end;

var
  PortAdr: word;
begin
  PortAdr := $EEFC; // Address of LPT-port

  while true do
  begin
    OutToLPTData := RotDir[1] * 2 + RotDir[2] * 8 + RotDir[3] * 32 + RotDir[4] * 128; // Data that output to LPT-port
    FSynchronizer.Enter; // = Acquire;
    try
      Out32(PortAdr, OutToLPTData);
    finally
      FSynchronizer.Leave; // = Release
    end;
    Delay_mcs(Time_out[LPTEngineNum]);
    OutToLPTData := RotateStep[1] + RotateStep[2] * 4 + RotateStep[3] * 16 +
    RotateStep[4] * 64 +
    RotDir[1] * 2 + RotDir[2] * 8 + RotDir[3] * 32 +
    RotDir[4] * 128; // Data that output to LPT-port
    FSynchronizer.Enter; // = Acquire;
    try
      Out32(PortAdr, OutToLPTData);
    finally
      FSynchronizer.Leave; // = Release
    end;
    Delay_mcs(Time_out[LPTEngineNum]);
  end;
end;

procedure TLPTEngine.InitializeHardware; // Called at the start of program execution
var
  i: integer;
begin
  IsSoftwareControlEngine := true;

  for i := 1 to numOfEngines do
  begin
    RotateStep[i] := 1; // Initial pulses of rotation of the stepper motor
    RotDir[i] := 0; // Initial direction of rotation of motors
    Time_out[i] := 500; // Delay in microseconds for each stepper motor
    OutToLptThread[i] := TOutToLptThread.Create(False);
    OutToLptThread[i].LPTEngineNum := i; // The thread number corresponds to the engine number, used in the assignment Time_out[LPTEngineNum]
    OutToLptThread[i].Priority := tpNormal;
//  OutToLptThread[i].Execute; // This command causes a message "Exception EAccessViolation in module MyProgram.exe at 001CE279. Access violation at address 005CE279 in module MyProgram.exe'. Read of address 00000000."
  end;

  inherited;
end;

procedure TLPTEngine.ApplyHardware; // Called when the value of Velocity changes.
var
  i: Integer;
begin
  i := AxisNum; // Number of engine
  if Velocity > 0 then // Direction of Rotation
  begin
    RotDir[i] := 0;
    RotateStep[i] := 1
  end
  else if Velocity < 0 then // Another direction of Rotation
  begin
    RotDir[i] := 1;
    RotateStep[i] := 1
  end
  else
  begin
    RotDir[i] := 0;
    RotateStep[i] := 0
  end;
end;
0

There are 0 answers