应用程序配置的保存
1 右键应用设置 → 属性 → 添加键值对和用户范围,应用程序和用户范围
2 获取配置参数:Properties.Settings.Default.参数名
3 修改修改参数 roperties.Settings.Default["A"] = 10 最后调用 save进行保存
1.什么是modbus? 包含的内容包含的三种协议: modbus-RTU: modbus-ASCII: modbus-TCP:
大部分的硬件都支持modbus-RTU(远程终端设备)协议,对数据在传输过程和接收过程格式的规定
2.modbus作用?
用来通信; 如果没有协议:发送数据,接收方不知道这些数据的作用
协议方就是指定数据的准则的
3 modbus-RTU: 协议是一种开放的串行协议,广泛应用于当今的工业监控设备中。该协议使用 RS-232 或 RS-485 串行接口进行通信,并得到市场上几乎所有商业 SCADA、HMI、OPC 服务器和数据采集软件程序的支持。因此,很容易将 Modbus 兼容设备集成到新的或现有的监控应用程序中,并具有即时的软件支持。
4 modbus 的主从技术()?
Modbus RTU 协议使用主/从技术在设备之间进行通信。这意味着,任何使用 Modbus RTU 协议的应用程序都将有一个 Modbus 主站和至少一个 Modbus 从站。Modbus Master 通常是一台运行软件的主机监控计算机,它将与一个或多个 Modbus Slave 设备进行通信。Modbus 从设备是执行系统参数测量和控制系统中的开/关设备的设备。为了执行这些任务,主站向 Modbus 从站发送消息,请求执行特定任务。
modbus中的帧结构?帧就是系统 Master和Slave 设备之间发送的信息,master发送的叫做命令帧,Slave返回的叫做应答帧
帧的结构 = 地址位 + 功能码 + 数据 + CRC校验
地址: 占用一个字节,范围0-255,其中有效范围是1-247,其他有特殊用途
功能码:占用一个字节,功能码的意义就是,知道这个指令是干啥的,比如你可以查询从机的数据,也可以修改数据,
所以不同功能码对应不同功能。
数据:根据功能码不同,有不同结构,在下面的实例中有说明。
校验:为了保证数据不错误,增加这个,然后再把前面的数据进行计算看数据是否一致,如果一致,就说明这帧数据是正确的,我再回复;
如果不一样,说明你这个数据在传输的时候出了问题,数据不对的,所以就抛弃了
Modbus-RTU协议一般我们用的最多功能码就是`03`和`06`,大部分都是用modbus来查询传感器上的信息用`03`查询功能码(读寄存器),
如果需要修改传感器寄存器的值就用`06`修改功能码(写寄存器),其他的不需要过多关注
6 上位机需要选择合适的 Modbus 协议栈、配置 Modbus 通信参数、建立 Modbus 通信连接、发送 Modbus 命令帧、接收 Modbus 响应帧和关闭 Modbus 通信连接等步骤。
应用程序配置的读取,保存
cs
#region ① 读取,修改
// 读取setting配置的参数
// Properties.Settings.Default.参数名
this.Text = Properties.Settings.Default.A; // 修改窗体标题
this.BackColor = Properties.Settings.Default.B;// 修改窗体背景
// 修改参数 应用程序范围参数 不能在运行的时候修改:用户范围的参数可以在运行时候修改
Properties.Settings.Default["A"] = "31马赫的威慑力,奥特之王都追不上";
Properties.Settings.Default["B"] = Color.PaleGreen;
Properties.Settings.Default.Save(); // 保存修改
#endregion
Modbus协议
cs
// 初始化串口参数配置
serialPort1.PortName = "COM5"; // 串口名字
serialPort1.BaudRate = 4800; // 波特率
serialPort1.Parity = System.IO.Ports.Parity.None;// 无奇偶校检
serialPort1.DataBits = 8; // 数据位置
serialPort1.StopBits = System.IO.Ports.StopBits.One; // 停止位
serialPort1.Open(); // 开放
serialPort1.DataReceived += serialPort1_DataReceived;
}
// 接收到数据的方法
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] body = new byte[20];
serialPort1.Read(body, 0, body.Length);// 读取应答帧
// 01 03 02 06 C3 FB B5
// 01 地址码
// 03 功能码
// 02 长度
// 06 C3 数据位
// FB B5 校检码
// 将数据位解析为10进制
Console.WriteLine(body[3] * 256 + body[4]);
// 06C3 真正的值
// 06 C3, C#是小端模式,这个数组被传递进去之后会被认为06为低位,C3为高位,按照C306进行计算
// 先获取中间的两个字节, 再反转,使低位在前,高位在后
byte[] value = body.Skip(3).Take(2).Reverse().ToArray();
Console.WriteLine(BitConverter.ToUInt16(value, 0));
BeginInvoke(new Action(() =>
{
label1.Text = BitConverter.ToUInt16(value, 0).ToString();
}));
}
public static byte[] CRCCalc(byte[] data)
{
//crc计算赋初始值
int crc = 0xffff;
for (int i = 0; i < data.Length; i++)
{
crc = crc ^ data[i];
for (int j = 0; j < 8; j++)
{
int temp;
temp = crc & 1;
crc = crc >> 1;
crc = crc & 0x7fff;
if (temp == 1)
{
crc = crc ^ 0xa001;
}
crc = crc & 0xffff;
}
}
//CRC寄存器的高低位进行互换
byte[] crc16 = new byte[2];
//CRC寄存器的高8位变成低8位,
crc16[1] = (byte)((crc >> 8) & 0xff);
//CRC寄存器的低8位变成高8位
crc16[0] = (byte)(crc & 0xff);
return crc16;
}
private void button1_Click(object sender, EventArgs e)
{
// 组织回答帧CO2
byte[] bs = new byte[]
{
0x01,// 地址码 占1个字节
0x03,// 功能码 读取 查询功能 占1个字节
0x00,0x08, // 起始地址,占2个字节
0x00,0x01,// 数据长度 1个长度 占2个字节
// 校检码 2个字节
};
// 2 通过crc进行计算校检码
byte[] abc = CRCCalc(bs); // 0x05,0xc8
bs = bs.Concat(abc).ToArray();// 把bs和校检码进行合并
//3 发送
serialPort1.Write(bs, 0, bs.Length);
}
}
}