0

This code, when the variable Vel is set to more than zero, starts clockwise rotation, when the variable Vel is set to less than zero, it starts counterclockwise rotation, setting the variable Vel to zero stops the motor.

In total, 4 stepper motors are connected to the board, which rotate at the same speed.

But here, the problem is that it may be necessary to rotate different step motors at different speeds. The Out32() procedure outputs a whole byte (all 8 bits at the same time) to bits 2-9 of the LPT port.

Therefore, to programmatically change the rotation speed of individual SMs, it may be necessary to organize additional separate cycles in separate threads, setting different numbers of RotateStep[i] change rates for each engine. Then the delays for each individual SD will be a multiple of the time_out value.

Is there a procedure like Out32() that changes only certain bits at the input of the LPT port? Then it will be possible to record the signals RotDir[i] and RotateStep[i] in each separate for each SD stream with its own delay time_out = K / Vel[i], where K is the multiplication factor.

function Out32(PortAdr: word; Data: byte): byte; stdcall; external 'inpout32.dll';

procedure ChangeRotateSD; // Вызывается при изменении величины SetVel
var
  i: Integer;
begin
  i := AxisNum;
  if Vel > 0 then // Направление вращения
  begin
    RotDir[i] := 0;
    RotateStep[i] := 1
  end
  else if Vel < 0 then // Другое направление вращения
  begin
    RotDir[i] := 1;
    RotateStep[i] := 1
  end
  else // Остановка
  begin
    RotDir[i] := 0;
    RotateStep[i] := 0
  end;
end;

function RotateThread(Parameter: pointer): Integer;

  procedure Delay_mcs(time_out: double); // Задержка в микросекундах
  var
    iCounterPerSec: TLargeInteger;
    T1, T2: TLargeInteger; // значение счётчика ДО и ПОСЛЕ операции
  begin
    QueryPerformanceFrequency(iCounterPerSec);
    // определили частоту счётчика
    QueryPerformanceCounter(T1); // засекли время начала операции
    T2 := T1;

    while (T2 - T1) * 1000000 / iCounterPerSec < time_out do
      QueryPerformanceCounter(T2); // засекли время окончания
  end;

var
  PortAdr: word;
  Data: byte; // То, что выдается в LPT-порт
  time_out: double;
begin
  PortAdr := $EEFC; // Адрес LPT-порта
  time_out := 500; // Задержка в микросекундах
  // Установка 0 возвращаемому значению
  Result := 0;

  while true do
  begin
    Data := RotDir[1] * 2 + RotDir[2] * 8 + RotDir[3] * 32 + RotDir[4] * 128; 
    Out32(PortAdr, Data);
    Delay_mcs(time_out);
    Data := RotateStep[1] + RotateStep[2] * 4 + RotateStep[3] * 16 +
      RotateStep[4] * 64 +
      RotDir[1] * 2 + RotDir[2] * 8 + RotDir[3] * 32 + RotDir[4] * 128;
    Out32(PortAdr, Data);
    Delay_mcs(time_out);
  end;

  // Конец потока
  EndThread(0);
end;

procedure InitializeHardware;
var
  id1: LongWord;
  thread1: Integer;
  msg1: TMsgRecord;
begin
  IsSoftwareControlEngine := true;

  RotateStep[1] := 0; // Начальная скорость вращения ШД = 0
  RotateStep[2] := 0; // Начальная скорость вращения ШД = 0
  RotateStep[3] := 0; // Начальная скорость вращения ШД = 0
  RotateStep[4] := 0; // Начальная скорость вращения ШД = 0
  RotDir[1] := 0;
  RotDir[2] := 0;
  RotDir[3] := 0;
  RotDir[4] := 0;
  thread1 := BeginThread(nil, 0, Addr(RotateThread), Addr(msg1), 0, id1);

  CloseHandle(thread1);
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770

1 Answers1

0

This is easy to implement.You have to implement pair of functions called SetBit() and ClearBit(). Those function will set or clear a single bit (or a bit mask depending on how you want to implement it) in a global variable and then call Out32 to copy that variable's value to the LPT port.

Since your program is multithreaded, you MUST use a critical section in SetBit and ClearBit so that only one of them do his job at a given time.

fpiette
  • 11,983
  • 1
  • 24
  • 46