模拟 ModBus 协议发送数据——从机和主机程序(c#)
2011-08-27 17:23 230 人阅读 评论(0) 收藏 举报
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
//为一个库,包含 thread
namespace modbus_2
{
public partial class Form1 : Form
{
public Form1()
{
}
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
//跨线程调用界面资源
private byte[] byRecBuff = new Byte[1024];
//为从串口接收到的数据预留空间
private byte[] array = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
//进行测试发送的
十个数据,主机和从机都可以使用
private byte[] byBcakFrame = new byte[15];
//在 GetFrame()函数得到的数据发在这个数组中来,然后对这个数组
中的数据来进行一定的处理
///
/// 进行串口初始化
///
///
///
private void Form1_Load(object sender, EventArgs e)
{
//byte[] array_1 = new byte[] { 0x01,0x03,0x0A,0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09 };
//将所要发送的数据进行 CRC 校验,作为测试只用而已
serialPort1.BaudRate = 9600;
//波特率
serialPort1.PortName = "COM1";
//端口号
serialPort1.Parity = System.IO.Ports.Parity.None;
//校验位
serialPort1.DataBits = 8;
//数据位
serialPort1.StopBits = System.IO.Ports.StopBits.One;
//停止位
serialPort1.Open();
//打开端口
}
///
/// 从机程序
/// 从串口获取数据并且在 text1 窗口中显示
///
///
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
Thread.Sleep(1000);
//具有休眠作用,使数据得到缓存,缓存一秒
int iCount = serialPort1.BytesToRead;
//读取有多少个数据
/**
**显示获取的数据长度
**/
string len = Convert.ToString(iCount);
//将 int 型的 icount 转换成 string 类型
MessageBox.Show(len);
//测试获取数据的长度
/**
**从串口获取数据
**/
serialPort1.Read(byRecBuff, 0, iCount);
//将数据存在数组 byRecBuff 中
/**
**返还数据
**/
ushort iCRC = CRC16(byRecBuff, iCount - 2);
if (((byte)(iCRC >> 8) == byRecBuff[iCount - 2]) && ((byte)(iCRC) == byRecBuff[iCount - 1]))
//判断奇偶校
验码是否正确
{
if (byRecBuff[0] == 0x01)
//第一个是不是 01
{
if (byRecBuff[1] == 0x03)
//第二个是不是 03
{
for (int i = 0; i < iCount; i++)
{
textBox1.Text += byRecBuff[i].ToString("X2");
//tostring 为将 byte 型数组转换成 string 的形式,
X2 为一种格式,用来格式化数据
}
int How_Many_To_Send = (byRecBuff[5]) * 2;
byBcakFrame = new byte[How_Many_To_Send + 5];
//设定数组的存储空间大小
GetFrame(0x01, 0x03, (byte)How_Many_To_Send, array);
//得到的数据存于 byBcakFrame 数组
serialPort1.Write(byBcakFrame, 0, How_Many_To_Send + 5);
//将 byBcakFrame 数组中的数据
MessageBox.Show("数据返还成功");
中去
发送出去
}
}
}
}
///
/// 主机程序
/// 在 text_box2 窗口中输入要显示的字符,点击按键从串口中发送出去
///
///
private void button1_Click(object sender, EventArgs e)
{
byte[] senddata = System.Text.Encoding.Default.GetBytes(textBox2.Text);
//将 textbox 中的 string 类型数据放到
byte 型数组中去
//int datacount = Encoding.Default.;
int datacount = senddata.Length;
//获取动态数组长度
serialPort1.Write(senddata,0,datacount);
//任意程度的数据发送
MessageBox.Show("数据发送成功");
}
///
/// 点击按键,结束程序
///
///
///
private void button2_Click(object sender, EventArgs e)
{
}
this.Dispose();
//程序结束执行
///
/// 进行奇偶校验
///
///
测试的数据
///
需要测试数据的长度
///
CRCResult 数据结果
public static ushort CRC16(byte[] data, int Len)
{
const ushort polinomio = 0xA001;
ushort result = 0xFFFF;
for (int i = 0; i < Len; i++)
{
byte tmp = data[i];
result = (ushort)(tmp ^ result);
for (int j = 0; j < 8; j++)
{
if ((result & 0x0001) == 1)
{
}
result = (ushort)((result >> 1) ^ polinomio);
else
result = (ushort)(result >> 1);
{
}
}
}
ushort CRCResult = (ushort)((result << 8) + (result >> 8));
return CRCResult;
}
///
/// 将测试过后的数据打包发到新数组中去,并且返回新数组
///
///
地址码(第一位)
///
通信判断码(第二位)
///
数据位数(第三位)
///
返回的数组
private void GetFrame(byte byAddr, byte byFun, byte byByteNum, byte[] byData)
{
}
int iCounts = 0;
byBcakFrame[iCounts++] = byAddr;
byBcakFrame[iCounts++] = byFun;
byBcakFrame[iCounts++] = byByteNum;
for (int i = 0; i < byByteNum; i++)
//通过判断数据位数,来从数组中取出数据放到新数组中
{
}
byBcakFrame[iCounts++] = byData[i];
ushort iCRC = CRC16(byBcakFrame, iCounts);
//得出新数组的奇偶校验之前的奇偶校验码
byBcakFrame[iCounts++] = (byte)(iCRC >> 8);
//将奇偶校验码的前两位放入新数组中去
byBcakFrame[iCounts] = (byte)(iCRC);
//将奇偶校验码的后两位放入新数组中去
}
}