关于多机通讯,单片机,上位机,地址帧,数据帧
我现在在干一个项目,其中一块是实现多机通讯,数据中分为地址帧(RB8=1),数据帧(RB8=0);首先发送地址帧,选择需要通讯的单片机,然后得到单片机应答后,发送数据帧。主机计划选择为PC机,但是我发现我无法控制通过pc上的上位机区分出第九位,没法得到第九位数据就没法知道是地址帧,还是数据帧。请问,是否有牛人做过?
[解决办法]
WORD ss;
ss=513;
if (ss&(1<<8))
TRUE; //第9为为1
else
FALSE; //第9为为0
[解决办法]
你用什么通信啊?RS232?
[解决办法]
串口一般7或8个数据位,你的单片机如何发送9位?
[解决办法]
什么通讯?我记得主机上的串口不好处理第9位,这类问题,找一个成熟的协议就行了。
[解决办法]
这个如果你坚持主机用PC,基本上无解。
变通的办法,下面的51从机不要使用多机通信模式,直接采用串口与PC通信。
或者,PC先串口连接一个51主机,由它转发至下面的51从机。
[解决办法]
给你个我写的例子,可以看下
BOOL GetData(unsigned char command,int date,DWORD ms,HAND *temphand) { CString strtemp; DWORD dwactlen; DWORD dwLength=0; unsigned int i=0,sum=0; //变量使用前必须初始化,建议在定义时即初始化 unsigned char checkdata=0; int len; len=1; unsigned char *psendbuf=new unsigned char[len]; unsigned char *recvBuf=new unsigned char[1024]; psendbuf[0]=command; PurgeComm((*temphand).hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除收/发缓冲区 WriteFile((*temphand).hComm,psendbuf,len,&dwactlen,NULL); Sleep(ms);//等待应答 ReadFile((*temphand).hComm,recvBuf,1024,&dwLength,NULL); //其实我们接收到的命令应答只是一个字节 if(dwLength==0) { } if(dwLength==18) { if(recvBuf[0]==0x02&&recvBuf[17]==0x05) //判断起始、结束字符 { for(i=0;i<14;i++) { (*temphand).RecvADCData[i]=recvBuf[i+2]; //读取下位机ADC数据,12字节,位于数据包第3~14字节 sum +=(*temphand).RecvADCData[i]; //计算下位机ADC数据和,用于计算校验字 } checkdata=sum&0xff; //取sum低八位为校验字 (*temphand).CheckByte=recvBuf[16]; //读取下位机校验字节,数据包第15个字节 if((*temphand).CheckByte==checkdata) { for(i=0;i<7;i++) //高2位与低八位合并,还原ADC数据 { Rvc_Values[i] = (*temphand).RecvADCData[i*2]*256+(*temphand).RecvADCData[i*2+1]; //AD数据滤波,新数据与老数据相差不超过1丢弃 if(abs(Rvc_Values[i] - (*temphand).ADCData[i]) <=4) { Rvc_Values[i] = (*temphand).ADCData[i]; } else { (*temphand).ADCData[i] = Rvc_Values[i]; } strtemp.Format(_T("%d"),(*temphand).ADCData[i]); //转换为字符型,用于显示 (*temphand).display += strtemp+"\r\n"; } IFConnect = "已连接"; delete psendbuf; delete recvBuf; return TRUE; //ADC数据正确,返回真值 } else { errcount1++; delete psendbuf; delete recvBuf; if(errcount1 > 10) { return false; //ADC数据正确,返回真值 } else { return true; } } } else { errcount2++; delete psendbuf; delete recvBuf; if(errcount2 > 10) { return false; } return true; //ADC数据正确,返回真值 } } else { errcount3++; delete psendbuf; delete recvBuf; if(errcount3 > 200) { return false; } return true; } }
[解决办法]
...8250/16550的寄存器就是8位的...
[解决办法]
估计得自己写驱动了。
[解决办法]
// PC机串口的校验位,用windows系统本身的串口驱动,对用户来说是不存在的。
[解决办法]
楼主上位机编写经验太少了,这一个简答的协议,你都没自己接收完,肯定不知道第九位怎么读取了。首先要解决的问题是,你必须每次都能接收到下位机传回来的11个字节(你的描述可能有误解,你协议里的位是一个字节,我说的没错吧)的完整协议,再进行你的协议解析处理。要不然你一条协议都还没能完整接收谈任何的处理都没有用,一个很大的问题就是如果有校验,你都不处理,很可能要出大事,或者循环没法玩下去了的。
还有我不知道你用的是那个vc里的通信控件还是第三方通信类实现对串口数据接收的。如果是控件的话(并且你的协议长度都一样的话)就设定串口接收事件的触发条件设定为每接收到你协议长度的时候触发一次接收函数,很简单就搞定一条完整的协议了。如果你用第三方通信类如CSerialPort,那你就每次接收一次就记录一次,并存放起来,接收完后(指的是一条完整的协议接收完),再做你的解析工作,然后处理尾巴,为下次接收做好初始化准备。这样的程序才稳定可靠。