Due programmi che condividono uModbusRTU e uGauge: - Console/PlanciaConsole: plancia nautica descritta da file XML, con modalita' plancia e modalita' configurazione. Comandi, spie, selettori, strumenti e allarmi sonori; il bus gira in un thread suo perche' la finestra non si fermi mai. - ProjectPlancia: il programma di prova piu' vecchio, usato per collaudare i canali. Le plance sono in Console/*.xml, la documentazione in Console/LEGGIMI.md. Esclusi dal versionamento i compilati (.exe, .dcu), i file dell'IDE e un audio da 17 MB. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
142 lines
3.8 KiB
ObjectPascal
142 lines
3.8 KiB
ObjectPascal
program scanbus;
|
|
|
|
{
|
|
Scanner del bus Modbus RTU.
|
|
|
|
Interroga gli indirizzi slave uno per uno e riporta chi risponde, con quali
|
|
funzioni e che dati restituisce. Serve a scoprire l'indirizzo di un modulo
|
|
appena inserito e a capire da che canale partono i suoi ingressi.
|
|
|
|
Uso: scanbus [porta] [baud] [ultimoIndirizzo]
|
|
Es.: scanbus COM7 9600 16
|
|
}
|
|
|
|
{$APPTYPE CONSOLE}
|
|
|
|
uses
|
|
System.SysUtils,
|
|
uModbusRTU in '..\..\uModbusRTU.pas';
|
|
|
|
const
|
|
PROBE_TIMEOUT_MS = 200; // basso: un indirizzo morto non deve costare mezzo secondo
|
|
PROBE_COUNT = 8; // 8 canali: la taglia tipica di questi moduli
|
|
|
|
/// Rende leggibili gli 8 bit come "1 0 0 1 ...", con i numeri di canale sopra.
|
|
function BitsToStr(const ABits: TArray<Boolean>): string;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := '';
|
|
for I := 0 to High(ABits) do
|
|
if ABits[I] then Result := Result + '1 ' else Result := Result + '0 ';
|
|
end;
|
|
|
|
function RegsToStr(const ARegs: TArray<Word>): string;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := '';
|
|
for I := 0 to High(ARegs) do
|
|
Result := Result + IntToStr(ARegs[I]) + ' ';
|
|
end;
|
|
|
|
var
|
|
Port: string;
|
|
Baud: Cardinal;
|
|
LastAddr: Integer;
|
|
Bus: TModbusRTU;
|
|
Addr: Integer;
|
|
Alive: Boolean;
|
|
Found: Integer;
|
|
Bits: TArray<Boolean>;
|
|
Regs: TArray<Word>;
|
|
|
|
begin
|
|
try
|
|
Port := 'COM7';
|
|
Baud := 9600;
|
|
LastAddr := 16;
|
|
if ParamCount >= 1 then Port := ParamStr(1);
|
|
if ParamCount >= 2 then Baud := StrToUIntDef(ParamStr(2), 9600);
|
|
if ParamCount >= 3 then LastAddr := StrToIntDef(ParamStr(3), 16);
|
|
|
|
Writeln(Format('Scansione %s a %d baud, indirizzi da 1 a %d.', [Port, Baud, LastAddr]));
|
|
Writeln('Chiudi PlanciaConsole prima di lanciarlo: la porta si apre una volta sola.');
|
|
Writeln;
|
|
|
|
Bus := TModbusRTU.Create(Port, Baud, PROBE_TIMEOUT_MS);
|
|
try
|
|
Bus.Connect;
|
|
Found := 0;
|
|
|
|
for Addr := 1 to LastAddr do
|
|
begin
|
|
Write(Format(#13' provo indirizzo %d... ', [Addr]));
|
|
Alive := False;
|
|
|
|
// FC 02 - ingressi digitali: e' cio' che interessa a un modulo IO
|
|
try
|
|
Bits := Bus.ReadDiscreteInputs(Addr, 0, PROBE_COUNT);
|
|
if not Alive then Writeln(#13 + Format('SLAVE %d trovato', [Addr]) + StringOfChar(' ', 20));
|
|
Alive := True;
|
|
Writeln(' FC02 ingressi (canali 0..7): ' + BitsToStr(Bits));
|
|
except
|
|
on E: Exception do ;
|
|
end;
|
|
|
|
// FC 01 - bobine: le uscite rele'
|
|
try
|
|
Bits := Bus.ReadCoils(Addr, 0, PROBE_COUNT);
|
|
if not Alive then Writeln(#13 + Format('SLAVE %d trovato', [Addr]) + StringOfChar(' ', 20));
|
|
Alive := True;
|
|
Writeln(' FC01 bobine (canali 0..7): ' + BitsToStr(Bits));
|
|
except
|
|
on E: Exception do ;
|
|
end;
|
|
|
|
if not Alive then
|
|
Continue; // indirizzo morto: inutile insistere con i registri
|
|
|
|
// Solo per chi ha gia' risposto: vale la pena chiedere anche i registri
|
|
try
|
|
Regs := Bus.ReadHoldingRegisters(Addr, 0, 4);
|
|
Writeln(' FC03 holding (reg 0..3): ' + RegsToStr(Regs));
|
|
except
|
|
on E: Exception do ;
|
|
end;
|
|
|
|
try
|
|
Regs := Bus.ReadInputRegisters(Addr, 0, 4);
|
|
Writeln(' FC04 input reg (reg 0..3): ' + RegsToStr(Regs));
|
|
except
|
|
on E: Exception do ;
|
|
end;
|
|
|
|
Writeln;
|
|
Inc(Found);
|
|
end;
|
|
|
|
Writeln(#13 + StringOfChar(' ', 40));
|
|
if Found = 0 then
|
|
begin
|
|
Writeln('Nessuno slave ha risposto.');
|
|
Writeln('Controlla: baud del modulo, scambio A/B del RS485, alimentazione,');
|
|
Writeln('e che PlanciaConsole non tenga gia'' aperta la porta.');
|
|
end
|
|
else
|
|
Writeln(Format('Trovati %d slave.', [Found]));
|
|
|
|
finally
|
|
Bus.Free;
|
|
end;
|
|
|
|
except
|
|
on E: Exception do
|
|
Writeln('ERRORE: ' + E.Message);
|
|
end;
|
|
|
|
Writeln;
|
|
Write('Premi INVIO per chiudere.');
|
|
Readln;
|
|
end.
|