Plancia configurabile su Modbus RTU
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>
This commit is contained in:
commit
4a01a2ec88
69 files changed
+11658
No files matched your search
@@ -0,0 +1,141 @@
|
||||
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.
|
||||
Reference in new issue
Block a user