串口通讯 自定义协议

along2427295 2010-09-12 11:14:24
刚开始接触VC编程,现在用MFC想做个串口通讯的程序,自定义协议,想知道总体的程序架构是怎么样的,

比如说:界面,接收数据,发送数据,主要是发送和接收数据,他们放在什么地方比较合适,需不需要创建独立的线程,还有就是收到重发消息,在哪里做重发的工作,如果在接收线程做,那么重发的数据从哪里获得。

谢谢!
...全文
518 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
现在还是人类 2010-09-16
  • 打赏
  • 举报
回复
我提供的类就是多线程处理的,CPU占用率也很低,用起来也很简单,你可以看看的
along2427295 2010-09-16
  • 打赏
  • 举报
回复
现在做法:只有一个工作线程,这个线程如果接受到界面的消息(全局标志)就调用串口发送函数,感觉比在按钮响应函数里面直接调用发送要慢很多(看串口调试工具,接受显示明显变慢),为什么?

还有就是界面与工作线程的最好通信方法是什么?如果数据量比较大
alexmayer 2010-09-14
  • 打赏
  • 举报
回复
在哪里发送就在哪里重发,我是这么做的。

其实,如果是一问一答,完全可以用一个独立线程,发送完后超时等待。

cnComm有个Demo中有WantReturn函数(好像就是这个名字,我记不清了),就可以起这个作用。

好好分析一下cnComm和他的例子吧,绝对值得花费时间。
alexmayer 2010-09-14
  • 打赏
  • 举报
回复
你这种完全是个简单的停等协议,一问一答,起一个独立线程完成完全可以的。

至于重发不重发,就是你控制逻辑的事情了。
zwhate 2010-09-14
  • 打赏
  • 举报
回复
最好还是使用独立的接收线程,然后自己用API函数来写吧

我们平时都是这样做的,串口控件在接收数据会导致界面卡住...
along2427295 2010-09-14
  • 打赏
  • 举报
回复
谢谢 小豹

阅读了下cnComm ,第一感觉就是这个串口类居然可以封装得这么庞大,还需要慢慢琢磨啊,确实可以从中学到东西。

我开始想做成这样:UI线程、串口发送线程、读串口线程。发送线程应该有个消息队列,等到得到正确答复后,才将一个消息从队列中剔除,否则重发这个消息,现在难题是这个消息队列的建立和管理。

按照楼上(小豹)的说法:是不是发送和接收都在一个线程处理,消息发出去后就等待答复,如果答复要求重发或者超时,就重发上一消息,否则等待发送下一消息,如果超时重发多次则认为链路出故障
along2427295 2010-09-13
  • 打赏
  • 举报
回复
谢谢大家的答复,第一次在这里发帖就得到这么多的响应,太激动了!
正在看llbird兄的cnComm类,有所收获,谢谢小豹、smalltigerli

楼上:我现在是接收到数据就解包,然后投递到相应对话框进行更新,但是如果要重发的数据在哪里处理呢?
要不要独立的线程来处理发送和重发数据?
pshchao 2010-09-13
  • 打赏
  • 举报
回复
不建议使用mscomm控件,建议使用系统自带的API函数。

一般都是在串口初始化成功后,开启读取串口数据的线程,检测到串口有数据后,投递自定义消息,进行解包。或相应的处理。

iCan.club 2010-09-13
  • 打赏
  • 举报
回复
开源的类库也不错,CommonCPP,里面有很多基础类库,比如串口,线程等不错的哦
yanchenyu 2010-09-13
  • 打赏
  • 举报
回复
记号。
NIKE霸天虎 2010-09-13
  • 打赏
  • 举报
回复
1、龚建伟的网站:www.gjwtech.com
2、codeproject中CSerialPort类
3、llbird兄的cnComm类
PCCOM
ReadFile
以上基本都可以实现,前四个基本有都实现了打开读写等操作,直接调用即可
alexmayer 2010-09-13
  • 打赏
  • 举报
回复
对于串口问题,我的回答只有这个

1、龚建伟的网站:www.gjwtech.com
2、codeproject中CSerialPort类
3、llbird兄的cnComm类

网站有很多基础知识介绍。自己分析这两个类,会学到串口操作的基本理论、多线程、消息通信等,这两个类分析透彻了,串口也就入门了。

时间紧迫的话,cnComm的1.51demo里有多个例子,可以先修改应付任务。
chenjelly 2010-09-13
  • 打赏
  • 举报
回复
mfc里面有个MSComm控件,你可以直接用控件,对于你的数据帧格式,你可以用结构体来暂存你解析了数据包,然后添加到链表……等等处理
现在还是人类 2010-09-13
  • 打赏
  • 举报
回复
这是我自己写的串口类中的一个过程

void CDemoDlg::OnOK()
{
BOOL OpenState;
DWORD NowTickCount;
DWORD SaveTickCount;
char * SendText;
// 这里很关键,因为 Send 是通过 GlobalSize 来取得指针大小的,所以需要这样分配控件大小
SendText = (char *)GlobalAlloc(GMEM_ZEROINIT, 4);

ReturnValue = 0; //设置默认返回为失败
Approach = 0; //设置接收步骤参数

COMM1.EventRead = OnComm; //设置处理函数
COMM1.ObjClassAddress = (DWORD)this; //设置类地址,确保在OnComm过程中可以调用本类中的一些过程或变量
COMM1.Port = 1; //设置端口
COMM1.BaudRate = CBR_57600; //设置波特率
COMM1.ByteSize = 8; //设置数据位
COMM1.Parity = 0; //设置校检
COMM1.StopBits = 1; //设置停止位
OpenState = COMM1.Open(); //打开串口,这时候便开始了 OnComm 事件的侦听
if(OpenState==TRUE){
sprintf(SendText,"AT\r\n"); //设置要发送的文本内容(当然也可以发送字节流)
COMM1.Send((BYTE*)SendText); //发送文本到串口

//=========== 以下做超时处理 ===========
//超时处理总共有两个全局变量控制
//ExecOver 和 ReturnValue
ExecOver = FALSE;
SaveTickCount = GetTickCount();
while(ExecOver==FALSE){
Sleep(5);
NowTickCount = GetTickCount();
if(NowTickCount-SaveTickCount>=1000){
//超过1秒钟还未正常返回结果就自动退出循环
ReturnValue = 0;
ExecOver=TRUE;
}
}
COMM1.Close();
}
if(ReturnValue==1){
MessageBox("串口1接入的设备支持AT命令。","执行结果",64);
}else{
MessageBox("没有检测到串口1接入支持AT命令的设备。","执行结果",64);
}
}

void CDemoDlg::OnComm(DWORD pClassAddress, BYTE *ReadBuffers, DWORD ReadCount)
{
// pClassAddress 类地址,由用户自行设置 ObjClassAddress 而来
// ReadBuffers 从串口缓冲区读到的数据指针
// ReadCount 从川口缓冲区读到的数据大小
//=============== 还原类的方法,以下是范例 ===============
//CDemoDlg * DlgObj;
//DlgObj = (CDemoDlg *)pClassAddress;
//DlgObj->COMM1.Send((BYTE *)"AAA");
//========================================================
// 下面做个简单的信息识别处理

// 还原类事例对象,因为要用到类中的变量
CDemoDlg * DlgObj;
DlgObj = (CDemoDlg *)pClassAddress;

DWORD i;
if(ReadCount>0){
for(i=0;i<ReadCount;i++){
switch(DlgObj->Approach){
case 0:
if((BYTE)ReadBuffers[i]==0x0D||(BYTE)ReadBuffers[i]==0x0A){ //有可能先发换行符号
DlgObj->Approach = 1;
}else if((BYTE)ReadBuffers[i]==0x4F||(BYTE)ReadBuffers[i]==0x62){ //有可能直接发 OK 信息
DlgObj->Approach = 2;
}
break;
case 1:
if((BYTE)ReadBuffers[i]==0x4F||(BYTE)ReadBuffers[i]==0x6F){
DlgObj->Approach = 2;
}else if((BYTE)ReadBuffers[i]==0x0D||(BYTE)ReadBuffers[i]==0x0A){
DlgObj->Approach = 1;
}else{
DlgObj->Approach = 0;
}
break;
case 2:
if((BYTE)ReadBuffers[i]==0x4B||(BYTE)ReadBuffers[i]==0x6B){
DlgObj->Approach = 3;
}else{
DlgObj->Approach = 0;
}
break;
case 3:
if((BYTE)ReadBuffers[i]==0x0D||(BYTE)ReadBuffers[i]==0x0A){
DlgObj->ReturnValue = 1;
DlgObj->ExecOver = TRUE;
}
DlgObj->Approach = 0;
break;
}

}
}
}


你可以下载我的这个范例看一下,里面有完整的范例和静态库
http://download.csdn.net/source/2690778
along2427295 2010-09-12
  • 打赏
  • 举报
回复
不太明白楼上的意思,我现在是没有一个整体的架构,以前做过单片机程序,用的是C语言,比较简单,一下进入MFC真的有点不知从何下手的感觉,所以想以串口的通讯入手,做个与单片机通讯的简单协议。

我现在做了几个简单对话框,每个对话框都要发数据给单片机,都是在相应按钮消息里面发送,另外有个线程在等待单片机发来的消息,当收到消息后继续下发别的消息,这个下发别的消息应该在哪里做呢?

vnking 2010-09-12
  • 打赏
  • 举报
回复
很简单的,有个控件可以使用,收到信息时会发出中断通知你。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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