API串口一问一答式通信

xiaocongzhi 2009-06-17 10:31:02
各位老大:
我在做上位机与下位机用COM2通信的程序 上位机(PC)与下位机(控制单元)采用一问一答式即PC给控制单元发一条命令(程序中命令为SendStr=110300000001869A),当控制单元收到这条命令时 会给PC回发送数据。我在Button2的OnClick事件中建立一个通信监视线程 并给控制单元发送了命令,(控制单元接收数据指示灯指示控制单元收到了PC发的命令,并回发送数据指示灯指示控制单元有向PC发出数据),PC如果收到数据会显示在RichEdit1中,但RichEdit1中什么也不显示。
请哪位高手指点小弟,程序哪里有不妥!
const
WM_COMMNOTIFY=WM_USER+1; //通讯消息
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
OpenDialog1: TOpenDialog;
Label1: TLabel;
BitBtn1: TBitBtn;
RichEdit1: TRichEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
procedure WMCOMMNOTIFY(var Message:TMessage);message WM_COMMNOTIFY;//消息处理过程
public
{ Public declarations }
end;

var
hNewCommFile,Post_Event:THandle;
Read_os:TOverlapped;
Receive:Boolean;
ReceiveData:Dword;

procedure AddToMemo(Str:PChar;Len:DWORD);//接收的数据送入显示区
begin
Str[Len]:=#0; //#0为NULL
Form1.RichEdit1.Text:=Form1.RichEdit1.Text+StrPas(Str);
end;

procedure CommWatch(Ptr:Pointer);stdcall; //通讯监视线程
var
dwEvtMask,dwTranser:DWORD;
Ok:Boolean;
Os:TOverlapped;
begin
Receive:=True;
FillChar(Os,SizeOf(Os),0);//将OS填充为0
Os.hEvent:=CreateEvent(nil,True,False,nil);//创建重叠读事件对象
if Os.hEvent=null then
begin
MessageBox(0,'Os.Event Create Error!','Notice',MB_OK);
Exit;
end;
if (not SetCommMask(hNewCommFile,EV_RXCHAR)) then
begin
MessageBox(0,'SetCommMask Create Error!','Notice',MB_OK);
Exit;
end;
while(Receive) do
begin
dwEvtMask:=0; //等待事件发生
if not WaitCommEvent(hNewCommFile,dwEvtMask,@Os) then
begin
if ERROR_IO_PENDING=GetLastError then //如果出错状态为ERROR_IO_PENDING
GetOverlappedResult(hNewCommFile,Os,dwTranser,True)//就用GetOverlappedResult函数来获取状态,第4个参数为True表示一直等到操作完成
end;
if ((dwEvtMask and EV_RXCHAR)=EV_RXCHAR)then
begin
//等待允许传递WM_COMMNOTIFY通讯消息
WaitForSingleObject(Post_Event,INFINITE);
//处理WM_COMMNOTIFY消息时不再发送WM_COMMNOTIFY消息
ResetEvent(Post_Event); //置Post_Event对象为无信号状态,类似于DelHighDesignP37底左"不发信号状态"
//传递WM_COMMNOTIFY通讯消息
Ok:=PostMessage(Form1.Handle,WM_COMMNOTIFY,hNewCommFile,0);
if (not Ok)then
begin
MessageBox(0,'PostMessage Error!','Notice',MB_OK);
Exit;
end;
end;
end;
CloseHandle(Os.hEvent);//关闭重叠事件对象
end;


{ TForm1 }

procedure TForm1.WMCOMMNOTIFY(var Message: TMessage); //消息处理函数
var
CommState:COMSTAT;
dwNumberOfBytesRead:DWORD;
ErrorFlag:DWORD;
InputBuffer:array[0..1024]of Char;
begin
if not ClearCommError(hNewCommFile,ErrorFlag,@CommState)then
begin
MessageBox(0,'ClearCommError!','Notice',MB_OK);
PurgeComm(hNewCommFile,PURGE_RXABORT or PURGE_RXCLEAR);
Exit;
end;
if (CommState.cbInQue>0)then
begin
fillChar(InputBuffer,CommState.cbInQue,#0);
//接收通讯数据
if (not ReadFile(hNewCommFile,InputBuffer,CommState.cbInQue,dwNumberOfBytesRead,@read_os))then
begin
ErrorFlag:=GetLastError();
if (ErrorFlag<>0)and(ErrorFlag<>ERROR_IO_PENDING)then
begin
MessageBox(0,'ReadFile Error!','Notice',MB_OK);
Receive:=False;
CloseHandle(Read_os.hEvent);
CloseHandle(Post_Event);
CloseHandle(hNewCommFile);
Exit;
end
else
begin
WaitForSingleObject(hNewCommFile,INFINITE);//等待操作完成
GetOverlappedResult(hNewCommFile,Read_os,dwNumberOfBytesRead,False);
end;
end;
if dwNumberOfBytesRead>0 then //dwNumberOfBytesRead表示已经读取的字节数,其>0表示已经有读取的数据
begin
Read_os.Offset:=Read_os.Offset+dwNumberOfBytesRead;
ReceiveData:=Read_os.Offset;
//处理接收的数据
AddToMemo(InputBuffer,dwNumberOfBytesRead);
end;
end;
//允许发送下一个WM_COMMNOTIFY消息
SetEvent(Post_Event);
end;

procedure TForm1.Button2Click(Sender: TObject); //建立通信监视线程并发送读取数据命令
var
dcb:TDCB;
Error:Boolean;
dwNumberOfBytesWritten,dwNumberOfBytesToWrite,
ErrorFlag,dwWhereToStartWriting:DWORD;

SendStr:string;
Write_os:TOverlapped;
s2:string;
buf1:array[0..50000] of char;
i:integer;
Ok:Boolean;
com_thread:THandle;
ThreadID:DWORD;
begin

Form1.Caption:='';
//打开通讯端口COM2
hNewCommFile:=CreateFile('COM2',GENERIC_WRITE or GENERIC_READ,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
if hNewCommFile=INVALID_HANDLE_VALUE then
MessageBox(0,'Error Opening Com Port!','Notice',MB_OK);
SetupComm(hNewCommFile,1024,1024);//设置缓冲区大小及主要通讯参数
GetCommState(hNewCommFile,dcb); //用hNewCommFile(COM2)的当前控制设置填充dcb
dcb.BaudRate:=19200;
dcb.ByteSize:=8;
dcb.Parity:=NOPARITY;
dcb.StopBits:=ONESTOPBIT;
Error:=SetCommState(hNewCommFile,dcb); //用dcb配置hNewCommFile(COM2)
if (not Error)then MessageBox(0,'SetCommState Error','Notice',MB_OK);
SetCommMask(hNewCommFile,EV_TXEMPTY or EV_RXCHAR);//设置监视事件EV_TXEMPTY EV_RXCHAR
{------------------------------------------------
------------建立监视线程-----------------------}
ReceiveData:=0;
RichEdit1.Clear;
FillChar(Read_os,SizeOf(Read_os),0);
Read_os.Offset:=0;
Read_os.OffsetHigh:=0;
//Create Event for Overlapped Read
Read_os.hEvent:=CreateEvent(nil,True,False,nil); //创建事件对象
if Read_os.hEvent=null then
begin
CloseHandle(hNewCommFile); //关闭串口COM2
MessageBox(0,'CreateEvent Error!','Notice',MB_OK);
Exit;
end;
//Create Event for PostMessage
Post_Event:=CreateEvent(nil,True,True,nil); //创建事件对象
if Post_Event=null then
begin
CloseHandle(hNewCommFile); //关闭串口COM2
MessageBox(0,'CreateEvent Error!','Notice',MB_OK);
Exit;
end;
//建立通讯监视线程
com_thread:=CreateThread(nil,0,@CommWatch,nil,0,ThreadID);
if (com_thread=0)then
MessageBox(Handle,'No CreateThread!',nil,MB_OK);
EscapeCommFunction(hNewCommFile,SETDTR);
Label1.Font.Color:=clRed;
Label1.Caption:='正在接收数据...!';

SendStr:='110300000001869A'; //SendStr为发送的命令
for i:=1 to length(SendStr) do
begin
if ((copy(SendStr,i,1)>='0') and (copy(SendStr,i,1)<='9'))or((copy(SendStr,i,1)>='a') and (copy(SendStr,i,1)<='f'))
or((copy(SendStr,i,1)>='A') and (copy(SendStr,i,1)<='F')) then
begin
s2:=s2+copy(SendStr,i,1);
end;
end;
for i:=0 to (length(s2) div 2-1) do
buf1[i]:=char(strtoint('$'+copy(s2,i*2+1,2)));

dwWhereToStartWriting:=0;
dwNumberOfBytesWritten:=0;
dwNumberOfBytesToWrite:=length(s2) div 2; //需要发送的长度
begin
try
Label1.Font.Color:=clRed;
FillChar(Write_os,SizeOf(Write_os),0);//将Write_os填充为0
//为重叠写创建事件对象
Write_os.hEvent:=CreateEvent(nil,True,False,nil);//创建事件对象
Label1.Caption:='正在发送数据...!';
repeat
Label1.Repaint;
//发送通讯数据
if not WriteFile(hNewCommFile,buf1,
dwNumberOfBytesToWrite,dwNumberOfBytesWritten,@write_os)then
begin
ErrorFlag:=GetLastError; //错误标志
if ErrorFlag<>0 then
begin
if ErrorFlag=Error_IO_PENDING then
begin
WaitForSingleObject(Write_os.hEvent,INFINITE);
GetOverlappedResult(hNewCommFile,Write_os,dwNumberOfBytesWritten,False);
end
else
begin
MessageBox(0,'WriteFile Error!','Notice',MB_OK);
Receive:=False;
CloseHandle(Read_os.hEvent);
CloseHandle(Post_Event);
CloseHandle(hNewCommFile);
Exit;
end;
end;
end;
Dec(dwNumberOfBytesToWrite,dwNumberOfBytesWritten);
Inc(dwWhereToStartWriting,dwNumberOfBytesWritten);
until (dwNumberOfBytesToWrite<=0);//Write the Whole thing!
Form1.Caption:=IntToStr(dwWhereToStartWriting);
finally

end;
CloseHandle(hNewCommFile);//关闭串口
end;
...全文
189 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
李_军 2009-06-24
  • 打赏
  • 举报
回复
你可以先用串口调试助手测试一下,如果正确,再检查你的代码
huboy 2009-06-24
  • 打赏
  • 举报
回复
spcomm是开放源码的。
xiaowei_001 2009-06-24
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 xiaocongzhi 的回复:]
我用SPCOMM已经实现了,但老板说要用API写的稳定一些 控件不太稳定...所以没办法呀
[/Quote]
能实现就可以了嘛,串口控件都是开放源码的,跟你自己写API没区别吧,如果那里不爽可以自动修改下!
xiaocongzhi 2009-06-22
  • 打赏
  • 举报
回复
我用SPCOMM已经实现了,但老板说要用API写的稳定一些 控件不太稳定...所以没办法呀
贝隆 2009-06-19
  • 打赏
  • 举报
回复
楼主看的懂VB的代码不?看的懂的话这儿有一个API串口通信的例子:
http://download.csdn.net/source/1339593
nbzip 2009-06-19
  • 打赏
  • 举报
回复
有些东东在程序里面不一定能看出来,一定要实际的调试.

你用端口软件,看一下,返回的数据是否正确.

串口的设置,是按硬件工程师提供的设置,你用端口软件看一下,按他说的,是不是能得返回到机器的正确值,还要连续的测试多下.

如果多是正确无误的,那么你可以修改程序了.不然哪里错都不知道,就不太好找程序了.

(如果是新开发的东西,你可不用太相信硬件工程师,一定要多测试.)

ly_liuyang 2009-06-19
  • 打赏
  • 举报
回复
用SPCOMM就方便多了
yanshibo 2009-06-19
  • 打赏
  • 举报
回复
友情UP
xiaocongzhi 2009-06-18
  • 打赏
  • 举报
回复
我的下位机的指示灯显示已经成功收到PC发的命令,并且也给PC回复了数据,而程序就是不能接收到下位机发的数据!请您帮我看看是不是串口的设置哪里有冲突或者是监视事件设置有问题! (hNewCommFile:=CreateFile('COM2',GENERIC_WRITE or GENERIC_READ,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);//打开串口2)
(SetCommMask(hNewCommFile,EV_TXEMPTY or EV_RXCHAR);//设置监视事件EV_TXEMPTY EV_RXCHAR ) (通信监视里设置串口事件:if (not SetCommMask(hNewCommFile,EV_RXCHAR)) then )

nbzip 2009-06-18
  • 打赏
  • 举报
回复
看你那么写的那么多.呵呵.

做COM口通讯,先做一个小软件,或找个端口软件,你打个命令,然后看一下连接通没有,是否给了返回值.返回值是否正确.
(验证返回值就用转码,转成你需要的码,一般都是十六进制转ASCII码)

噢,要对COM的设置进行确定,如数据位8位,奇偶检验等等.确定通信的参数,再进行通讯的测试.(先写一些基本的函数)

然后,再写正试的测试程序或软件.(把函数做成一个文件,直接挂着用.)

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧