各位大虾:
最近在写一份上位机程序,和下位机进行通信,采用的是modbus协议,数据一ASCII代码发送。上位机开发环境是VC++6.0,用MFC做的界面,首先是设置串口参数,串口COM1,波特率是9600,无校验,一个停止位,数据位7位。
不知到该怎样设置发送的数据。
void CModbusDlg::OnModbussend()
{
// TODO: Add your control notification handler code here
if (!m_Com->PortOpened())
{
AfxMessageBox("通讯串口没有打开!");
return;
}
char* ucharReadFrame;
CString str;
m_edtSendView.GetWindowText(str);
int num=str.GetLength();
ucharReadFrame =new char[num];
memcpy(ucharReadFrame,(LPCTSTR)str,num);
m_Com->Send(ucharReadFrame, num);
}
bool CComControl::Send(char* pBuff, DWORD dwBytesSend)
{
if(!PortOpened()) return false;
BOOL wRes;
DWORD dwBytesW;
wRes = WriteFile( m_hCom,
pBuff,
dwBytesSend,
&dwBytesW,
&m_ovWrite
);
if(!wRes) //there are some data not send
{
if(GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_ovWrite.hEvent, 20*1000); //阻塞呼叫线程,如果出现错误或是超时则返回
wRes = GetOverlappedResult( m_hCom, // 串口设备句柄
&m_ovWrite, // 指向重叠结构
&dwBytesW, // 指向实际字节计数
false // 等待标记
);
if(!wRes || dwBytesW != dwBytesSend)
{
ClearInOut();
return false;
}
}
else // an error occured
{
ClearInOut();
return false;
}
}
return true;
}
a: 起始字符 [①:1位/STX(02H)或“@”(40H)]
?
?
?
选择 STX ( 02H ) - - - ETX (03H)
选择 “@” ( 40H ) - - - “:” (3AH)
b: 机器地址 [②,③:2位]
?
?
?
?
c: 附属地址[④:1位]
?
(3) 基本格式第II部分详解
h: 文本结束字符[?:1位/ETX(03H)]或[“:”(3AH)]
? 表示完成指令接收,可立即开始执行。
I : BCC数据(块校验字符)[?, ?:2位]
?
?
?
?
?
a b c d e g h i
? ? ? ? ?
STX 0 1 1 R 0 0 ---- ETX 3 E CR
STX 0 2 1 W 0 0 ,**** ETX 4 F CR
基本格式第1部分 文本部分基本格式第II部分
起始字符
调节器地址
附属地址
指令类型
数据
文本结束字符
BCC 数据
结束字符
(分界符)
应答代码
声明通讯字符串的起始字符。
收到此字符可作为另一条通讯指令开始的判据。
起始字符与文本结束字符是一一对应的关系。
指定传送指令调节器的地址。
地址可在1-255(十进制)范围内指定。
二进制8位数据(1:0000 0001 - 255:1111 1111)分为前4位与后4位转成ASCII码数据。
②:前4位数据转为ASCII码
③:后4位数据转为ASCII码
机器地址=0(30H,30H)用于广播指令。
SRS10系列支持广播指令。
对广播指令,无论正确与否,都不做应答。
要以ASCII代码发送一串数据,应该怎样编码呢?
比如@011W018C0:00
a b c d e f g h i j
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
STX 0 1 1 R 0 1 0 0 0 … ETX D A CR …
STX 0 2 1 W 0 1 8 c 0 … ETX 0 B CR …
1. 通讯发送格式的解释:
a 通讯的起始符: 第 1 位。STX:(02H)或”@”(40H) 。
b 通讯下位机地址:第2、3 位由8 位二进制组成。地址范围1~98,这8 位二进制被分成
高4 位和低4 位,其中高4 位被送入2 中,低4 位放入3 中,并转换成ASCII 码。
c 通讯下位机地址的子地址:第4 位。当只有一个回路时为1;当有两个回路时通道一为1,
通道二为2。
d 通讯命令类型:第5 位。“R”(52H),表明在上位机发送或仪表应答中的读命令。“W”
(57H),表明在上位机发送或仪表应答的写命令。“B”表明在上位机以广播方式发送命令。
e 通讯命令代码:第6、7、8、9 位。是16 位二进制代码(0~65535),这16 位被分成四
组,并转换成相应的ASCII 码。命令代码祥见命令代码表。
f 通讯命令连续读代码:第10 位。表明上位机要连续读取多少个参数。这位取值范围(0~9)
(30H~39H),十个数。实际的连续读参数的个数=表明的数值+1。
g 通讯数据:第11 位。这位的数据量决定于这位的数据,既这位的数据长度不定。数据总
是以“,”(2CH),数据项与数据项之间不需要任何分割符。数据的长度主要取决于第10 位
的方式。每一个数据项由16 位二进制代码组成(1 个字),每4 位被分成一个数据单元,同
时每个数据单元又被转换成ASCII 数据,当第5 位为“R”读命令时,此位不写。
第一数据项 第二数据项 第 N 数据项
高位低位高位低位高位低位,” 第一单元第二单元第三单元第四单元第一单元第二单元
第三 单元第四单元第一单元第二单元第三单元第四单元2CH
h 数据发送结束符:第12 位。ETX(03H)或“:”(3AH)。所有的数据和命令在此位之
前都以发送完成,遇到此字符表名结束。
i BCC 块校验:第13、14 位。三种BCC 块校验和无校验。上位机的BCC 校验应通过软件
处理。仪表的BCC 校验可在仪表1-34 窗口设置。当BCC 校验结果有错误时,将没有应答。
BCC 校验数据被分成高4 位和低4 位,并被转换成ASCII 码。
13 位为高4 位的ASCII 码。14 位为低4 位的ASCII 码。
modbus ASC模式是固定以冒号为帧起始,回车换行为帧结尾的,便于在终端打印出数据。
至于中间的用户协议是由你们自己定义。
还有一点,ASC模式一字节数据只用7位的,所以对于通信来说,字节最高位无意义。
PC端只要把所有要发送的数据与0x80按位或。
下位机串口通信模式设为7个数据位的模式。
你上面提的要求还没时间仔细看,回去再看看。
不知道我说的能不能帮到你,很久之前做过modbus的程序,差不多全还给老师了。
讲错了,PC端数据应该是与0x7F按位与。
呵呵,记错了。
下位机还是上面说的那样,7个数据位,2个起始位。
谢谢,比如我想打开下位机的COM端口,首先我应该写@011W018C1:00结束时以CR结束。用ASCII发送的 时候,怎么发送呢?
打开下位机的COM端口是什么意思?
没有打开就无通信了啊,你的命令就没有用了。
下位机是一只处于通信状态的,读里面的信息,但是如果要想往下位机写东西,首先要发送一串指令,让其打开COM端口
你用个正常的应用程序和PLC通信,拦截下数据流,自己照着写不就成了,它发什么你就发什么呗。
你可以用这个工具调试你的串口程序。
下载地址:
http://download.cnet.com/ComTrace/3000-2218_4-75156892.html?tag=mncol
感觉好别忘了给个review(评论),谢谢!
你上面用什么写串口?
我觉得直接用WriteFile写字符串下去就可以了。
我以前是用CSerialPort这个类,不过其实这个类里面也是用的WriteFile。
不用想的太复杂的。