RS232 problem z odbiorem danych (odczyt z bufora).

0

witam
mam taki problem. Mam uklad do pomiaru temp na atmega polaczony z kompem przez rs232. mikrokontroler wysyla mi dane (2 temp) do komputera i ja to odbieram przez rs232 w delphi w polu RichEdit. Problem w tym ze jesli nacisne przycisk jakiś na ukladzie to uklad wysyla mi jakis znak np. "a" do kompa (tak chciałem) i jesli w buforze znajdzie sie litera "a" to program rozpoczyna animacje.
Wiem jak zrobić animacje ale nie wiem w jaki sposób moge odczytać dane z bufora kompa. Nie wiem jak to rozdzielić aby znaleźć to "a". Prosze o pomoc, załączam swoj program.

unit temprs;

interface

uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ExtCtrls, OleCtrls, ShockwaveFlashObjects_TLB;

type
TForm1 = class(TForm)
CloseComm: TButton;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
OpenComm: TButton;
TimerON: TButton;
TimerOFF: TButton;
RichEdit1: TRichEdit;
Timer1: TTimer;
TrackBar1: TTrackBar;
Edit1: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
StatusBar1: TStatusBar;
Flashcichy: TShockwaveFlash;
procedure CloseCommClick(Sender: TObject);
procedure OpenCommClick(Sender: TObject);
procedure TimerONClick(Sender: TObject);
procedure TimerOFFClick(Sender: TObject);
procedure TimerOnTimer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
procedure FormClose(Sender: TObject;
var Action: TCloseAction);

private
{ Private declarations }
function Write_Comm(hCommDev: THANDLE;
nNumberOfBytesToWrite: DWORD): BOOL;
function Read_Comm(hCommDev: THANDLE; Buf_Size: DWORD): BOOL;

public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}
const
// -- wartości flag sterujących portu szeregowego --
dcb_fBinary = $0001;
dcb_fParity = $0002;
dcb_fOutxCtsFlow = $0004;
dcb_fOutxDsrFlow = $0008;

// -- fDtrControl --
DTR_CONTROL_ENABLE = $0010;
DTR_CONTROL_HANDSHAKE = $0020;

dcb_fDsrSensitivity = $0040;
dcb_fTXContinueOnXoff = $0080;
dcb_fOutX = $0100;
dcb_fInX = $0200;
dcb_fErrorChar = $0400;
dcb_fNull = $0800;

// -- fRtsControl --
RTS_CONTROL_ENABLE = $1000;
RTS_CONTROL_HANDSHAKE = $2000;
RTS_CONTROL_TOGGLE = $3000;

dcb_fAbortOnError = $4000;

cbInQueue = 16;
cbOutQueue = 16;

var
query : PChar = 'CDAT?'+#13+#10;// przykładowe zapytanie
// zakończone parą znaków CR LF
Buffer_O : ARRAY[0..cbOutQueue] of Char; // bufor wyjściowy
Buffer_I : ARRAY[0..cbInQueue] of Char; // bufor wejściowy
Number_Bytes_Read : DWORD;
hCommDev : THANDLE;
lpFileName : PChar;
fdwEvtMask : DWORD;
Stat : TCOMSTAT;
Errors : DWORD;
dcb : TDCB;

resourcestring
s1 = 'Niewłaściwa nazwa portu lub jest on aktywny ';
s2 = 'Uwaga !';
s3 = 'Blad';

//---------------------------------------------------------
procedure TForm1.CloseCommClick(Sender: TObject);
begin
Timer1.Enabled := FALSE;
CloseHandle(hCommDev);
Application.Terminate();
end;
//---------------------------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
begin

Timer1.Enabled := FALSE;
Timer1.Interval := 2000;
TrackBar1.Max := 2000;
TrackBar1.Min := 100;
TrackBar1.Frequency := 50;

end;
//---------------------------------------------------------
function TForm1.Write_Comm(hCommDev: THANDLE;
nNumberOfBytesToWrite: DWORD): BOOL;
var
NumberOfBytesWritten : DWORD;

begin
WriteFile(hCommDev, Buffer_O, nNumberOfBytesToWrite,
NumberOfBytesWritten, NIL);
Result := WaitCommEvent(hCommDev, fdwEvtMask, NIL);
end;
//---------------------------------------------------------
function TForm1.Read_Comm(hCommDev: THANDLE;
Buf_Size: DWORD): BOOL;
var
nNumberOfBytesToRead: DWORD;
begin
Result := FALSE;
ClearCommError(hCommDev, Errors, @Stat);
if (Stat.cbInQue > 0) then
begin
if (Stat.cbInQue > Buf_Size) then
nNumberOfBytesToRead := Buf_Size
else
nNumberOfBytesToRead := Stat.cbInQue;
Result := ReadFile(hCommDev, Buffer_I,
nNumberOfBytesToRead,
Number_Bytes_Read, NIL);
end;
end;
//---------------------------------------------------------
procedure TForm1.OpenCommClick(Sender: TObject);
begin

if (CheckBox1.Checked = TRUE) then
lpFileName := 'COM1';

 hCommDev := CreateFile(lpFileName, GENERIC_READ or
                        GENERIC_WRITE,0, NIL,
                        OPEN_EXISTING, 0, 0);

if (hCommDev <> INVALID_HANDLE_VALUE) then
begin
SetupComm(hCommDev, cbInQueue, cbOutQueue);
dcb.DCBlength := sizeof(dcb);
GetCommState(hCommDev, dcb);
if (CheckBox2.Checked = TRUE) then
dcb.BaudRate := CBR_9600;

   //-- przykładowe ustawienia flag sterujących DCB --
   dcb.Flags := dcb.Flags or dcb_fParity;

     dcb.Parity := ODDPARITY;
     dcb.StopBits :=ONESTOPBIT;
     dcb.ByteSize :=7;

     SetCommState(hCommDev, dcb);
     GetCommMask(hCommDev, fdwEvtMask);
     SetCommMask(hCommDev, EV_TXEMPTY);

     StatusBar1.Panels[0].Text := 'Port '+lpFileName+ ' jest otwarty';

end
  else
     case hCommDev of
       IE_BADID:
       Application.MessageBox(PChar(s1),PChar(s2),MB_OK);
     end;

end;
//---------------------------------------------------------
procedure TForm1.TimerONClick(Sender: TObject); //rozpocznij pomiar
begin

if (hCommDev <> INVALID_HANDLE_VALUE)
and (hCommDev > 0) then
begin
StrCopy(Buffer_O, query);
Timer1.Enabled := TRUE;

    StatusBar1.Panels[1].Text := 'Trwa odbiór danych z portu '+lpFileName;

    Flashcichy.Movie := ExtractFilePath(Application.ExeName) + 'napis.swf';
     Flashcichy.Play;
 end
  else
     Application.MessageBox(PChar(s1),PChar(s2),MB_OK);

end;
//---------------------------------------------------------
procedure TForm1.TimerOFFClick(Sender: TObject); //zakończ pomiar
begin
StatusBar1.Panels[1].Text := 'Transmisja z portu '+lpFileName+' zakończona';

Flashcichy.Movie := ExtractFilePath(Application.ExeName) + 'koniec.swf';

Flashcichy.Play; //animacje zakańczająca pomiary

Timer1.Enabled := FALSE;
end;
//---------------------------------------------------------
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
Timer1.Interval := TrackBar1.Position;
Edit1.Text := IntToStr(TrackBar1.Position);
end;
//---------------------------------------------------------
procedure TForm1.TimerOnTimer(Sender: TObject);
begin
Repeat
// wysłanie zapytania
FlushFileBuffers(hCommDev);
Until (Write_Comm(hCommDev, StrLen(Buffer_O)) <> FALSE);

if (Read_Comm(hCommDev, SizeOf(Buffer_I)) = TRUE) then
// odbiór danych
begin

  if (Buffer_I = 'a')   then
     begin
  Flashcichy.Movie := ExtractFilePath(Application.ExeName) + 'koniec.swf';

Flashcichy.Play;
end

   else if  (Buffer_I <> 'a')   then
  RichEdit1.Text := Buffer_I;
        end
  else
   RichEdit1.Text := s3;

end;
//---------------------------------------------------------
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=CaFree;
end;
//---------------------------------------------------------
end.

0

ja bym sie nie zajmowal winApi tylko uzyl darmowego TComPort, tu wywolanie urzadzenia uruchamia zadarzenie komponentu ktore sobie mozna latwo obrabiac bo parametrem jest string,
ComPortReceiveCallBack(Data: string);
soft oczywiscie darmowy

0

oki tylko nie wiem jak sie do tego zabrac, zaistalowalem cport i mam uklad ktory wysyla mi temp na kompa. Jak mam to odczytac teraz? nie wiem kompletnie jakie elementy uzyc i co dalej w delphi

0

oki jakos udalo mi sie cos uruchomic tylko mam problem niby bardzo prosty, jak rozpoznać w przesylanych danych jakiś znak lub cyfre?. Wiem ze odbieram to jako string poprzez polecenie ComPort.ReadStr(String, Count); ale teraz chcialbybm coś zrobić (np wlaczyć animacje) jesli w tym wystąpi np 'a' ???

0

Zdaje się, że mam podobny problem. Również używam Win Api. Próbuje się skomunikować ze sterownikiem po MODBUSie. Mój kod wygląda następująco:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
RichEdit1: TRichEdit;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure CRC16(len:integer);
procedure Write_Comm(hCommDev: THANDLE;
nNumberOfBytesToWrite: DWORD);
procedure Read_Comm(hCommDev: THANDLE; Buf_Size: DWORD);
function int2bin(int:int64):string;
function int2hex(int:integer):string;
function bin2int(binary:string) :int64;
function poteN(liczba:int64;do_potegi:integer=2):int64;
procedure Button2Click(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

const
// -- wartości znaczników sterujących portu szeregowego --
dcb_fBinary = True;
dcb_fParity = False;

dcb_fOutxCtsFlow = True;
dcb_fOutxDsrFlow = True;

dcb_fDSRSensitive =False;
dcb_fDtrCOntrol =True;
dcb_fTXContinueOnXoff = False;

// DTR_CONTROL_ENABLE = True;
// RTS_CONTROL_ENABLE = True;

// DTR_CONTROL_HANDSHAKE = True;
// RTS_CONTROL_HANDSHAKE = True;

dcb_fOutX = False;//ok
dcb_fInX = False;//ok

dcb_fErrorChar = False;
dcb_fNull = False;

dcb_AbortOnError = False;

cbInQueue = 16;
cbOutQueue = 16;

var

ramka:String='050330000001';
ramka_ost:String;

Buffer_O : array[1..cbOutQueue] of Char; // bufor wyjściowy
Buffer_I : ARRAY[1..cbInQueue] of Char; // bufor wejściowy
Data: array[1..8] of Integer;

hCommDev : THANDLE;
lpFileName : PChar;
fdwEvtMask : DWORD;
Number_Bytes_Read : DWORD;

Stat : TCOMSTAT;
Errors : DWORD;
dcb: TDCB;

procedure TForm1.Write_Comm(hCommDev: THANDLE;
nNumberOfBytesToWrite: DWORD);
var
NumberOfBytesWritten : DWORD;

begin
WriteFile(hCommDev, Buffer_O, nNumberOfBytesToWrite,
NumberOfBytesWritten, NIL);
WaitCommEvent(hCommDev, fdwEvtMask, NIL);
end;

procedure TForm1.Read_Comm(hCommDev: THANDLE; Buf_Size: DWORD);
var
nNumberOfBytesToRead: DWORD;
begin
ClearCommError(hCommDev, Errors, @Stat);
if (Stat.cbInQue > 0) then
begin
if (Stat.cbInQue > Buf_Size) then
nNumberOfBytesToRead := Buf_Size
else
nNumberOfBytesToRead := Stat.cbInQue;
ReadFile(hCommDev, Buffer_I, nNumberOfBytesToRead,
Number_Bytes_Read, NIL);
end
else
Number_Bytes_Read := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
s:String;
begin

Data[1]:=5;//00000101;
Data[2]:=3;//00000011;
Data[3]:=48;//00110000;
Data[4]:=0;//00000000;
Data[5]:=0;//00000000;
Data[6]:=32;//00100000;

CRC16(6);

ramka:='';
ramka_ost:='';

// wypelnienie ramki
for i:=1 to 8 do
begin
// wypelnienie ramki po osiem bitów 2 znakami 05 03 30 00 00 20 (4A 96)<-CRC16
ramka:=ramka+int2bin(DATA[i]);
end;

//zamiana na znaki 16 znaków szestastkowych po jednym na 4 bity
for i:=1 to 16 do
begin
s:=Copy(ramka, (8*i-7), 8);
ramka_ost:=ramka_ost+int2hex(bin2int(s));
end;

// konwersja string na char
for i:=1 to length(ramka_ost) do
Buffer_O[i]:= ramka_ost[i];

lpFileName:='Com1';

hCommDev:=CreateFile(lpFileName, GENERIC_READ or GENERIC_WRITE,0,NIL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);

if (hCommDev=Invalid_Handle_Value) then
begin
MessageDlg('Niewłaściwa nazwa portu '+lpFileName+
' lub jest on aktywny' , mtInformation, [mbOk], 0);
end;

GetCommState(hCommDev,dcb);

// parametry transmisji
dcb.BaudRate:= CBR_9600;
dcb.Parity:= NOPARITY;
dcb.StopBits:=1; ///ONESTOPBIT;
dcb.ByteSize:=4;

SetCommState(hCommDev,dcb);

RichEdit1.Text := Buffer_O;
Write_Comm(hCommDev,16); // szesnascie znaków po 2 na 8 bitach danych..
FlushFileBuffers(hCommDev);
end;

procedure TForm1.CRC16(len:integer);
var crc: word;
n,i: integer;
b:byte;
begin
crc := $FFFF;
for i:=1 to len do begin
b:=Data[i];
crc := crc xor b;
for n:=1 to 8 do begin
if (crc and 1)<>0
then crc:=(crc shr 1) xor $A001
else crc:=crc shr 1;
end;
end;
Data[len+1]:=crc and $ff;
Data [len+2]:=crc shr 8;
end;

function TForm1.int2bin(int:int64):string;
var strtemp:string;
s:string;
begin
while int>0 do
begin
insert(inttostr(int mod 2),strtemp,1);
int:= int div 2;
end;
s:='0';

if Length(strtemp)<8 then
repeat
strtemp:=Concat(s,strtemp);
until Length(strtemp)=8 ;

result:=(strtemp);
end;

function TForm1.int2hex(int:integer):string;
begin
result:=inttohex(int,2);
end;

function TForm1.poteN(liczba:int64;do_potegi:integer=2):int64;
begin

 case do_potegi of
   0:result:=1;
   1:result:=liczba;
  else
    PoteN:=liczba*PoteN(liczba,do_potegi-1);
end;

end;

function TForm1.bin2int(binary:string) :int64;
var I,j:integer;wynik:Int64;
begin
wynik:=0;
j:=0;
for i:=length(binary) downto 1 do
begin
wynik:=wynik+((strtoint((binary)[i])*( poten(2,j))));
inc(j);
end;
result:=wynik;
end;

function int2hex(int:integer):string;
begin
result:=inttohex(int,2);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Read_Comm(hCommDev, SizeOf(Buffer_I));
RichEdit1.Text := Buffer_I;
end;

end.

Sterownik milczy. Wiem, że dane w ramce są poprawne ->modbus tester wysyła takie same znaki.

Mój sterownik na 4 bitach zapisuje jeden znak. Będę próbował przystosować powyższy kod do transmisji RTU, ale według mnie pojedyncza ramka i pojedyncza odpowiedź powinny chodzić. Gdzie popełniłem błąd?

Jak mierzyć czas wysyłania pojedynczego znaku i ustawiać początek ramki jako czas 3,5 krotność tego czasu?

0

Witam,
tobiasz0606 napisz do mnie na PW to posle Ci pare przykladow modbus-a.
Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0