modbus_rtu 代码示例
1.目前编写modbus_rtu控制钧舵的产品,控制夹爪的开关,modbus_rtu主要掌握如下几点:
1>串口打开
2>串口读写
3>串口报文组包
4>串口报文校验
5>串口关闭
下列为vs2015 mfc工程编写代码示例:
串口打开代码:
xxx.cpp
#include "stdafx.h"
#include "Serial.h"
#include "afxmt.h"
#include <time.h>
#include <process.h>
CSerial::CSerial()
{
m_hCom = NULL;
}
CSerial::~CSerial()
{
//500ms
Sleep(500);
CloseSerial();
}
bool CSerial::OpenSerial(int com,int baud,int parity,int bytesize,int stopbit)
{
char msg[100];
BOOL result;
DCB dcb;
CString comName;
char buf[256];
memset(buf, 0, 256);
m_sCom = com, m_baud = baud, m_parity = parity, m_bytesize = bytesize, m_stopbit = stopbit;
sprintf_s(buf, "serial=%d,baud=%d,parity=%d,bytesize=%d,stopbit=%d", m_sCom, m_baud, m_parity, m_bytesize, m_stopbit);
_cprintf("%s\n", buf);
//_T会根据项目选择的无编码和多编码来决定一个字符占的位数
comName.Format(_T("\\\\.\\COM%d"), m_sCom);
//1.获取串口句柄
CloseSerial();
m_hCom = CreateFile(comName, GENERIC_READ | GENERIC_WRITE,
0,//独占方式
NULL, OPEN_EXISTING,
NULL,
NULL);
if (m_hCom == INVALID_HANDLE_VALUE)
{
CString str;
str.Format(_T("串口%s不存在或已坏!"), comName);
USES_CONVERSION;
_cprintf("%s\n", W2A(str));
CloseSerial();
return false;
}
//2.初始化输入/输出缓冲区大小
result = SetupComm(m_hCom, 512, 512);
if (!result)
{
return false;
}
//3.获得设备句柄的当前参数
result = GetCommState(m_hCom, &dcb);
if (!result)
{
return false;
}
//4.设置串口波特率
dcb.BaudRate = m_baud;
//5.设置串口为奇/偶校验为NONE
dcb.Parity = m_parity;
//6.设置串口数据位
dcb.ByteSize = m_bytesize;
//7.设置串口停止位
int sbit;
if (m_stopbit == 1)
{
sbit = ONESTOPBIT;
}
else if (m_stopbit == 2)
{
sbit = TWOSTOPBITS;
}
else
{
sbit = ONE5STOPBITS;
}
dcb.StopBits = sbit;
//8.
dcb.fOutX = 0;
dcb.fInX = 1;
dcb.fRtsControl = RTS_CONTROL_DISABLE;//RTS_CONTROL_HANDSHAKE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
//9.更新设备句柄的参数
result = SetCommState(m_hCom, &dcb);
if (!result)
{
int dwLastError = GetLastError();
sprintf(msg, "串口:SetComState error(%d)", dwLastError);
_cprintf("%s\n", msg);
return false;
}
//10.设置串口读入/写出等候超时时间
COMMTIMEOUTS timeout;
result = GetCommTimeouts(m_hCom, &timeout);
if (!result)
{
int dwLastError = GetLastError();
sprintf(msg, "串口:GetComTimeouts error(%d)", dwLastError);
_cprintf("%s\n", msg);
return false;
}
timeout.ReadIntervalTimeout = MAXDWORD;
timeout.ReadTotalTimeoutMultiplier = 0;
timeout.ReadTotalTimeoutConstant = 0;
timeout.WriteTotalTimeoutMultiplier = 0;
timeout.WriteTotalTimeoutConstant = 0;
result = SetCommTimeouts(m_hCom, &timeout);
if (!result)
{
int dwLastError = GetLastError();
sprintf(msg, "串口:SetComTimeouts error(%d)", dwLastError);
_cprintf("%s\n", msg);
return false;
}
//11.清除输入/输出缓冲区内的数据
result = PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
if (!result)
{
int dwLastError = GetLastError();
sprintf(msg, "串口:PurgeCom error(%d)", dwLastError);
_cprintf("%s\n", msg);
return false;
}
//mfc的工作线程,必须为全局函数或静态函数
//AfxBeginThread(OnRead, LPVOID(this), THREAD_PRIORITY_LOWEST);
sprintf(msg, "打开串口%d成功", m_sCom);
_cprintf("%s\n", msg);
return true;
}
bool CSerial::CloseSerial()
{
if (m_hCom != NULL)
{
CloseHandle(m_hCom);
m_hCom = NULL;
_cprintf("%s\n", "串口通道关闭");
}
return true;
}
//bool CSerial::GetState()
//{
// if (m_hCom)
// {
// return true;
// }
// else
// {
// return false;
// }
//}
int CSerial::Read(BYTE * lpBuf)
{
BOOL result = FALSE;
BYTE buff[1024] = {
0 };
DWORD nRead = 0;
result = ReadFile(m_hCom, buff, 1024, &nRead, NULL);
if (!result)
{
if (GetLastError() == ERROR_HANDLE_EOF)
{
char msg[256] = {
0 };
sprintf(msg, "OnRead关闭通道,错误码%d\n", ERROR_HANDLE_EOF);
CloseSerial();
return -1;
}
}
else
{
memcpy(lpBuf, buff, nRead);
_cprintf("Rx: ");
for (int i = 0;i < nRead;i++)
{
char buf[4096] = {
0 };
sprintf(buf, "%02X ", lpBuf[i]);
_cprintf("%s", buf);
}
_cprintf("\n");
}
return nRead;
}
int CSerial::Write(BYTE * lpBuf, int len)
{
DWORD nWrite = 0;
BOOL result = WriteFile(m_hCom, lpBuf, (DWORD)len, &nWrite, NULL);
if ((!result) || (len != nWrite))
{
_cprintf("%s\n", "发送数据失败");
if ((GetLastError() == ERROR_INVALID_HANDLE) || (GetLastError() == ERROR_ACCESS_DENIED))
{
CloseSerial();
return -1;
}
}
else
{
//解析报文:
}
return nWrite;
}
xxx.h
#pragma once
#ifndef _SERIAL_H__
#define _SERIAL_H__
#include<conio.h>
#include <iostream>
#include <map>
#include <locale.h>// setlocale函数的头文件
using namespace std;
#pragma warning(disable:4996)
typedef map<string, string> PARA;//存放串口配置文件参数
//#include "common.h"
//串口通信主要四步:
//1.设置初始化并打开串口
//2.配置串口
//3.串口上传输数据,传输过程中并校验
//4.不需要此串口,关闭串口
class CSerial
{
public:
CSerial();
~CSerial();
//打开串口
bool OpenSerial(int com, int baud, int parity, int bytesize, int stopbit);
//关闭串口
bool CloseSerial();
//普通模式读
int Read(BYTE * lpBuf);
//普通模式写
int Write(BYTE * lpBuf, int len);
public:
int m_sCom; //串口号
int m_baud; //波特率
int m_parity; //校验
int m_bytesize; //数据位
int m_stopbit; //停止位
HANDLE m_hCom;//串口句柄
};
#endif
代码下载地址:
链接:https://pan.baidu.com/s/1n001s1RIBhPbf5Hbt2bs0w
提取码:pw8z