大家救命,在用MSCOMM控件在一个按钮中实现发送和接收数据的问题。

legendhui 2004-12-17 03:03:53
我想在一个按钮响应函数中,发送一个数据包,然后等待一段时间后,再对接收的数据进行判断。我想用MSCOMM控件来实现,请问可不可以?我在发送数据后,用Sleep函数让线程等待一段时间,可是仍然不会产生CommEvent,要等到执行完这个按钮中所有的语句才会响应。请高手指点,谢谢!
...全文
448 点赞 收藏 27
写回复
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
chinablood 2004-12-21
程序并没有错, ComEvReceive也可能发生了(如果通信连接正确的话.),怀疑测试过程中发送的数据太少,当你点击void CAutoMedView::OnOnCommMscomm() 所对应的工具或菜单时发送已经完成,此时收到的是ComEvEOF事件.建议1:把m_Comm.SetPortOpen(TRUE);放到OnOnCommMscomm()函数中;建议2:对m_Comm.GetCommEvent()==2返回的事件进行逐一判断,这应该是好习惯.
回复
wy311216 2004-12-20
肯定好用啊,不管它有多少单片机,毕竟它是要通过串口传送的,所以同时你只能传送一组数据
我上面的程序代码,就可以控制很多个单片机
回复
legendhui 2004-12-20
pAutoMedView->OnComm();
这个我也知道,不过是想检验一下在按钮执行的过程中是否能响应OnComm事件处理,我也说过了它根本不会去执行if(m_Comm.GetCommEvent()==2) 里面的东东。
回复
legendhui 2004-12-20
定时器我也想过,不过我最终至少要控制12个单片机连续工作,并且应该实现发一个接一个,接收的数据判断后,再发下一个。所以定时器我想应该不好用。
回复
wy311216 2004-12-20
pAutoMedView->OnComm();
虽然你触发了串口事件,但是和接收到外部数据触发的串口事件是两个不同的线程.所以你在OnButton10里面接收数据是不可能收到的.你得在OnComm事件处理里面接收
回复
wy311216 2004-12-20
你可以使用定时器
回复
wy311216 2004-12-20
BOOL CComTestDlg::ComInitialize(int i)
{
if(m_com.GetPortOpen())
{
//若有开启的COM口则关闭
m_com.SetPortOpen(FALSE);
}
m_com.SetCommPort(i);
if (!m_com.GetPortOpen())
{
//打开串口
m_com.SetPortOpen(TRUE);
}
//波特率9600,无校验,8个数据位,1个停止位
m_com.SetSettings("19200,n,8,1");
// 以二进制方式检取数据,参数取0数据以文字形式取回
m_com.SetInputMode(1);
//参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
m_com.SetRThreshold(1);
//先预读缓冲区以清除残留数据
m_com.GetInput();
return TRUE;
}

void CComTestDlg::OnButtonopencom()
{
UpdateData(TRUE);
if(!(m_comValue == "1" || m_comValue == "2") )

{
MessageBox("请选择需要打开的COM口");
return;
}
ComInitialize(atoi(m_comValue));
m_openBtn.EnableWindow(FALSE);
m_sendBtn.EnableWindow(TRUE);
m_importBtn.EnableWindow(TRUE);
}

void CComTestDlg::OnClose()
{
if(m_com.GetPortOpen())
{
//若有开启的COM口则关闭
m_com.SetPortOpen(FALSE);
}
DestroyWindow();

}

void CComTestDlg::OnOnCommMscomm()
{
CListCtrl *preturnListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST2);
CListCtrl *pdataListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST1);
//定义VARIANT型变量 
VARIANT m_input1;
//定义COleSafeArray型变量
COleSafeArray m_input2;
int length;
LONG i;
//定义字节数组 
BYTE data[128],datahead;
CString str,str1;
//接收缓冲区内字符
if(m_com.GetCommEvent()== 2)
{
m_com.SetInputLen(1);
//从缓冲区读数据
m_input1=m_com.GetInput();
//将VARIANT型变量转换为ColeSafeArray型变量
m_input2=m_input1;
//将数据转换为BYTE型数组
for(i=0;i< 1;i++)
m_input2.GetElement(&i,data+i);
datahead=data[0];
//传送出的数据得到正确响应,终止定时器,删除第一个数据
if(datahead==0xA5)
{
KillTimer(1);
pdataListCtrl->DeleteItem(0);
Send();
}
//重发第一个数据
else if(datahead==0xA6)//发送出去的数据错误,重新发送.
{
Send();
}
else if(datahead==0x5A)//发送过来的命令
{
m_com.SetInputLen(1);
m_input1=m_com.GetInput();
m_input2=m_input1;
for(i=0;i< 1;i++)
m_input2.GetElement(&i,data+i);
length=data[0];
m_com.SetInputLen(length);
//从缓冲区读数据
//Sleep(50);
m_input1=m_com.GetInput();
//将VARIANT型变量转换为ColeSafeArray型变量
m_input2=m_input1;
//将数据转换为BYTE型数组
for(i=0;i< length;i++)
m_input2.GetElement(&i,data+i);
//m_data1=data[1];//sno
//m_data2=data[2]+1;//bno
BYTE CHKRESULT = 0;
for(i=0;i<length;i++)//校验数据的正确与否。CHK+SNO+BNO+BARCODE[1]+。。。。。。BARCODE[N]
{
CHKRESULT+=data[i];
}
if(CHKRESULT==0)
{
//preturnListCtrl添加数据
CString strBoxNo,strReaderNo,strData;
strBoxNo.Format("%d",data[1]);
strReaderNo.Format("%d",data[2]+1);
strData.Format("0x%02X",data[3]);
int i = preturnListCtrl->GetItemCount();
pdataListCtrl->InsertItem(LVIF_TEXT|LVIF_STATE,i,strBoxNo,0,LVIS_SELECTED,0,0);
pdataListCtrl->SetItemText(i,1,strReaderNo);
pdataListCtrl->SetItemText(i,2,strData);
}
}
else if(datahead==0xA7)
{

}
}
}

//将CString转为CByteArray
void CComTestDlg::String2Hex(CString str, CByteArray &senddata)
{
int hexdata,lowhexdata;
int hexdatalen=0;
int len=str.GetLength();
senddata.SetSize(len/2);
for(int i=0;i<len;)
{
char lstr,hstr=str[i];
if(hstr==' ')
{
i++;
continue;
}
i++;
if(i>=len)
break;
lstr=str[i];
hexdata=ConvertHexChar(hstr);
lowhexdata=ConvertHexChar(lstr);
if((hexdata==16)||(lowhexdata==16))
break;
else
hexdata=hexdata*16+lowhexdata;
i++;
senddata[hexdatalen]=(char)hexdata;
hexdatalen++;
}
}

//这是一个将字符转换为相应的十六进制值的函数
//功能:若是在0-F之间的字符,则转换为相应的十六进制字符,否则返回-1
char CComTestDlg::ConvertHexChar(char ch)
{
if((ch>='0')&&(ch<='9'))
return ch-0x30;
else if((ch>='A')&&(ch<='F'))
return ch-'A'+10;
else if((ch>='a')&&(ch<='f'))
return ch-'a'+10;
else return (-1);
}

void CComTestDlg::SendData(CString str,int sno,int bno)//向串接器发送命令
{
CByteArray hexdata;
CString str1 = "";
CString str2 = "";
CString str3 = "";
int CMD[5];
int result = 0;
int check = 0;
int header = 0x5A;
int len = str.GetLength();
BYTE data[128];

for (int i=0; i<len; i++)
{
data[i] = str.GetAt(i);
result = result + data[i];
str1.Format("%02X", data[i]); //$
str2 += str1;
}

str3 = str2;
//计算校验码
check = 256-(sno + bno + result - 1)%256;
CMD[0] = 0x5A;
CMD[1] = len + 3;
CMD[2] = check;
CMD[3] = sno;
CMD[4] = bno - 1;

str1 = "";
str2 = "";
for(i=0;i<5;i++)
{
str1.Format("%02X",CMD[i]); //$
str2 += str1;
}
//向串口发送数据
str = str2 + str3;
String2Hex(str,hexdata);
m_com.SetOutput(COleVariant(hexdata)); //发送数据
}

//发送数据到串口
void CComTestDlg::OnSend()
{
Send();
}

//发送数据到串口
void CComTestDlg::Send()
{
//从datalist中得到要发送的数据发送出去
CString strBoxNo;
CString strReaderNo;
CString strData;
int BoxNo;
int ReaderNo;
CListCtrl *pdataListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST1);

if (pdataListCtrl->GetItemCount() <= 0)
{
//MessageBox("没有数据");
return;
}

strBoxNo = pdataListCtrl->GetItemText(0,0);
strReaderNo = pdataListCtrl->GetItemText(0,1);
strData = pdataListCtrl->GetItemText(0,2);
BoxNo = atoi(strBoxNo.GetBuffer(0));
ReaderNo = atoi(strReaderNo.GetBuffer(0));
SendData(strData, BoxNo, ReaderNo);
//启动定时器
SetTimer(1,20000,NULL);
}

void CComTestDlg::OnTimer(UINT nIDEvent)
{
switch(nIDEvent)
{
case 1:
Send();
break;
case 2:
;
}
//CDialog::OnTimer(nIDEvent);
}

void CComTestDlg::OnClear()
{
//CListCtrl *preturnListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST2);
//preturnListCtrl->DeleteAllItems();
MessageBox("hello");
}


void CComTestDlg::OnImport()
{
CListCtrl *pdataListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST1);
pdataListCtrl->DeleteAllItems();

CString szLine = "";
CString strBoxNo = "";
CString strReaderNo = "";
CString strData = "";
CFileFind find;
if(!find.FindFile(".//data.txt"))
{
MessageBox("没有可导入的数据文件");
return;
}
CStdioFile file;
file.Open("data.txt",CFile::modeRead);

while(file.ReadString(szLine))
{
if(szLine != "")
{
CString str = "";
szLine.TrimLeft();
szLine.TrimRight();
for(int i=0; i<szLine.GetLength(); i++)
{
str = szLine.Mid(i,1);
if(str == " ")
{
strBoxNo = szLine.Left(i);
szLine = szLine.Mid(i);
szLine.TrimLeft();
szLine.TrimRight();
break;
}
}

if(szLine != "")
{
CString str1 = "";
for(int k=0; k<szLine.GetLength(); k++)
{
str1 = szLine.Mid(k,1);
if(str1 == " ")
{
strReaderNo = szLine.Left(k);
szLine = szLine.Mid(k);
szLine.TrimLeft();
szLine.TrimRight();
break;
}
}
if(szLine != "")
{
strData = szLine;
}
}
if(strBoxNo=="" || strReaderNo=="" || strData == "")
{
continue;
}
int j = pdataListCtrl->GetItemCount();

pdataListCtrl->InsertItem(LVIF_TEXT|LVIF_STATE,j,strBoxNo,0,LVIS_SELECTED,0,0);
pdataListCtrl->SetItemText(j,1,strReaderNo);
pdataListCtrl->SetItemText(j,2,strData);
strBoxNo = "";
strReaderNo = "";
strData = "";
}
}
}

回复
legendhui 2004-12-20
wy311216
我的OnButton3()里实际也是发送数据的,我跟踪了,实际实际是执行的,及时把他换成,OnButton3()里的语句也没有意义,我现在主要想解决的是,在一个按钮里,同时发送然后等下微机处理完数据后,在接收数据,对其判断,然后再发数据。
回复
wy311216 2004-12-20
void CMovequipDlg::OnButton10()
{
OnButton3();
Sleep(2000);
}
你在事件处理函数中调用事件处理函数.OnButtton3是不会执行的.你可以跟踪一下
回复
legendhui 2004-12-20
我的代码是这样写的:
void CAutoMedView::OnInitialUpdate()
{
m_Comm.SetCommPort(1);
m_Comm.SetInBufferSize(1024);
m_Comm.SetOutBufferSize(512);
if(!m_Comm.GetPortOpen())
m_Comm.SetPortOpen(TRUE);
m_Comm.SetInputMode(1);
m_Comm.SetRThreshold(1);
m_Comm.SetSettings("9600,n,8,1");
m_Comm.SetInputLen(0);
m_Comm.GetInput();
m_Comm.SetEOFEnable(true);

}
////////////////////
void CAutoMedView::OnOnCommMscomm()
{
// TODO: Add your control notification handler code here
Sleep(3000);
VARIANT m_Input1;
COleSafeArray m_Input2;
long length,i;
BYTE data[1024];
CString str;
if(m_Comm.GetCommEvent()==2)
{
m_Input1=m_Comm.GetInput();
m_Input2=m_Input1;
length=m_Input2.GetOneDimSize();
for(i=0;i<length;i++)
m_Input2.GetElement(&i,data+i);
for(i=0;i<length;i++)
{
BYTE a=*(char*)(data+i);
str.Format("%02X ",a);
m_strReceiveData+=str;
}
}
UpdateData(false);
}
////////////////////////////
void CMovequipDlg::OnButton3()
{
// TODO: Add your control notification handler code here
CMainFrame * pMainFrame = (CMainFrame*)AfxGetMainWnd();
CAutoMedView * pAutoMedView = (CAutoMedView*)pMainFrame->GetActiveView();
byte.RemoveAll();
UpdateData(TRUE);
switch(m_nHprobe)
{
case 0:
packet = "a5c5a040000000f5";
break;
case 1:
packet = "a5c5a140000000f5";
break;
case 2:
packet = "a5c5a240000000f5";
break;
case 3:
packet = "a5c5a340000000f5";
break;
case 4:
packet = "a5c5a440000000f5";
break;
default:
AfxMessageBox("请输入0--4之间的数");
return;
}
pAutoMedView->String2Hex(packet,byte);
pAutoMedView->m_Comm.SetOutput(COleVariant(byte));

}
//////////////////////////////////////////////////
void CMovequipDlg::OnButton4()
{
// TODO: Add your control notification handler code here
CMainFrame * pMainFrame = (CMainFrame*)AfxGetMainWnd();
CAutoMedView * pAutoMedView = (CAutoMedView*)pMainFrame->GetActiveView();
byte.RemoveAll();
UpdateData(TRUE);
CString str;
switch(m_nHsamplingpin)
{
case 0:
packet = "a5c7a140000000f5";
break;
case 1:
packet = "a5c7a240000000f5";
break;
default:
AfxMessageBox("请输入0--1之间的数");
return;
}
pAutoMedView->String2Hex(packet,byte);
pAutoMedView->m_Comm.SetOutput(COleVariant(byte));

}
void CMovequipDlg::OnButton10()
{
// TODO: Add your control notification handler code here
CMainFrame * pMainFrame = (CMainFrame*)AfxGetMainWnd();
CAutoMedView * pAutoMedView = (CAutoMedView*)pMainFrame->GetActiveView();
OnButton3();
Sleep(2000);
pAutoMedView->OnComm();
//在这里对收到的数据进行判断,然后再进行其它数据的发送。可是进入 OnOnCommMscomm()函数它并不执行if(m_Comm.GetCommEvent()==2)这个判断里的内容,不管Sleep多久。
OnButton4();
UpdateData(false);
}
回复
danielzhu 2004-12-20
UP
回复
legendhui 2004-12-20
大哥,这样也忒麻烦了吧,要一两个单片机还好说,我以后要有12个单片机,这样恐怕不如用别的省事
回复
5iDream 2004-12-19
gz
回复
如果是VC程序,建议不要用MSCOMM控件,自己用API实现,也没几句代码兼容性还好,不过我在网吧,没法给例子。
回复
yintongshun 2004-12-18
示例:
初始化:
bool CYourClass::OpenPort()
{
if(m_Comm.GetPortOpen())
m_Comm.SetPortOpen(FALSE);
m_Comm.SetCommPort(m_iPort); //选择com1
if( !m_Comm.GetPortOpen())
m_Comm.SetPortOpen(TRUE); //打开串口
else
AfxMessageBox("cannot open serial port");

m_Comm.SetSettings(_T("1200,E,8,1")); //波特率1200,无校验,8个数据位,1个停止位
m_Comm.SetSThreshold(0);
m_Comm.SetRThreshold(1); //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
m_Comm.SetInputMode(1);
m_Comm.SetInputLen(0); //设置当前接收区数据长度为0
return true;
}
发送:
CByteArray bArryFrame;
bArryFrame.Add(0x68);
bArryFrame.Add(0x23);
m_Comm.SetOutput(COleVariant(bArryFrame));

接收:
CByteArray m_RecFrameArray_All;(类中定义即可)
void CYourClass::OnCommMscommCtrl()
{
// TODO: Add your control notification handler code here
Sleep(300);

VARIANT variant_inp;
COleSafeArray safearray_inp;
CString csDispString;
LONG len;
BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed.
short ENO;
CString strtemp;
ENO=1;BYTE bt;CString csByte,csResult;
if(1)//bReceive)
{
ENO=m_Comm.GetCommEvent();

if(ENO==2) //事件值为2表示接收缓冲区内有字符
{
variant_inp = m_Comm.GetInput(); //读缓冲区
safearray_inp = variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
len=safearray_inp.GetOneDimSize(); //得到有效数据长度
for(LONG iter=0;iter<len;iter++)
{
safearray_inp.GetElement(&iter,rxdata+iter); //转换为BYTE型数组

bt=*(char*)(rxdata+iter);m_RecFrameArray_All.Add(bt);
strtemp.Format("%02X ",m_RecFrameArray_All.ElementAt(iter));
csResult+=strtemp;
}
}
回复
kugou123 2004-12-18
你的代码是怎么写的?
回复
legendhui 2004-12-18
谁能比较详细的给我解决这个问题啊?最好在原来控件的基础上,实在不行别的方法也可以。我另开一贴,用我的一半分相送(大约100多分)!愁死我了!!!发了这么久了
回复
UDX协议 2004-12-18
http://www.vczx.com/article/show.php?id=790
换个控件试试
回复
zyp2kyear 2004-12-18
http://cs.nju.edu.cn/yangxc/dcc2003.files/jszc-sub/comif-30.htm
回复
legendhui 2004-12-18
请问
CreateMutex
WaitForSingleObject
在哪里创建,用的时候怎么用,能不能给出详细的代码。本人实在太菜了
我的程序中的一部分如下:

void CMovequipDlg::OnButton10()
{
// TODO: Add your control notification handler code here
CMainFrame * pMainFrame = (CMainFrame*)AfxGetMainWnd();
CAutoMedView * pAutoMedView = (CAutoMedView*)pMainFrame->GetActiveView();
OnButton1();//对机器发送一条指令,然后它作出相应的动作后返回一条指令。
Sleep(1000);
pAutoMedView->OnComm();
pAutoMedView->m_strReceiveData;//等待接收缓冲区里的数据,然后判断做下一步。这里主要是要接收到数据,然后才能最下一步。
OnButton2();
Sleep(2000);
}
回复
发动态
发帖子
进程/线程/DLL
创建于2007-09-28

1.5w+

社区成员

VC/MFC 进程/线程/DLL
申请成为版主
社区公告
暂无公告