c#串口读写威盟士五插针

WinForm页面

对应Combox按钮里面要书写对应数据

搭建完页面代码后要搭建后端代码,编写完成之后即进行威盟士五插针传感器的数据读取。

后端代码书写

默认窗口配置

cs 复制代码
 private void Form1_Load(object sender, EventArgs e)

 {

     cbbPortName.DataSource=SerialPort.GetPortNames();

     cbbBaudRate.SelectedIndex=1;

     cbbDataBit.SelectedIndex=0;

     cbbStopBit.SelectedIndex=1;

     cbbParity.SelectedIndex=0;

 }

编写连接按钮

cs 复制代码
 private void btnConn_Click(object sender, EventArgs e)

 {

     try

     {

         if (btnConn.Text=="连接")

         {

                   

             //设置属性

             serialPort1.PortName=cbbPortName.SelectedItem.ToString();

             serialPort1.BaudRate = Convert.ToInt32(cbbBaudRate.SelectedItem.ToString());

             serialPort1.DataBits = Convert.ToInt32(cbbDataBit.SelectedItem.ToString());

             serialPort1.StopBits=(StopBits)Enum.Parse(typeof(StopBits),cbbStopBit.SelectedItem.ToString());

             serialPort1.Parity= (Parity)Enum.Parse(typeof(Parity), cbbParity.SelectedItem.ToString());

             //判断是否打开 如果没有打开 就调用open()打开

             if (!serialPort1.IsOpen)  serialPort1.Open();

             btnConn.Text = "关闭";



             //禁用按钮

             cbbPortName.Enabled=false;

             cbbBaudRate.Enabled=false;

             cbbDataBit.Enabled=false;

             cbbStopBit.Enabled=false;

             cbbParity.Enabled=false;

         }



         else

         {

             btnConn.Text = "连接";



             if (serialPort1.IsOpen) serialPort1.Close();

             cbbPortName.Enabled= true;

             cbbBaudRate.Enabled= true;

             cbbDataBit.Enabled= true;

             cbbStopBit.Enabled= true;

             cbbParity.Enabled= true;



         }



     }

     catch(Exception ex)

     {

         MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);



     }

 }

编写读取按钮

这里要创建一个自动函数:SendData()

自定义类:CRCHelper

cs 复制代码
/// <summary>

/// CRC校验帮助类,提供CRC16校验算法实现

/// </summary>

internal class CRCHelper

{

    /// <summary>

    /// 计算CRC16校验值

    /// </summary>

    /// <param name="data">需要计算校验值的字节数组</param>

    /// <returns>CRC16校验结果,长度为2的字节数组,索引0是低八位,索引1是高八位</returns>

    public static byte[] CRC16(byte[] data)

    {

        // 初始化CRC寄存器为0xFFFF

        int crc = 0xffff;



        // 遍历数据字节(排除最后两个字节,通常是预留的校验位位置)

        for (int i = 0; i < data.Length - 2; i++)

        {

            // 将当前数据字节与CRC寄存器进行异或运算

            crc = crc ^ data[i];



            // 对每个数据位进行处理

            for (int j = 0; j < 8; j++)

            {

                // 保存CRC寄存器的最低位

                int temp = 0;

                temp = crc & 1;



                // CRC寄存器右移一位

                crc = crc >> 1;



                // 确保高位置零,保持16位范围

                crc = crc & 0x7fff;



                // 如果最低位为1,则与多项式0xA001进行异或

                if (temp == 1)

                {

                    crc = crc ^ 0xa001;

                }



                // 确保结果保持在16位范围内

                crc = crc & 0xffff;

            }

        }



        // 准备CRC结果数组,高低位分离

        byte[] crc16 = new byte[2];

        crc16[0] = (byte)(crc & 0xff);      // 取低8位

        crc16[1] = (byte)((crc >> 8) & 0xff); // 取高8位



        return crc16;

    }

}



 private void SendData()

 {

     // *****



     //1.buffer 字节数组的前6个字节专门用来生成CRC校验码

     byte[] buffer = new byte[8];

     buffer[0] = 0X01; //从站地址 0x01 0X01   ===> 1

     buffer[1] = 0X03; // 功能码  0x03/0x04 表示读取  0x06/0x10 表示写入



     buffer[2] = 0x00; //起始地址的高位

     buffer[3] = 0x00; //起始地址的底位



     buffer[4] = 0x00;//数据长度的高位

     buffer[5] = 0x04;//数据长度的低位



     //2.用前面6个字节生成两个自己的crc校验码

     byte[] crc= CRCHelper.CRC16(buffer);





     //3.设置校验码

     buffer[6] = crc[0];//校验码低位

     buffer[7]= crc[1];//校验码高位



     //buffer 就是咱们准备好的请求报文 也叫做问询帧



     //4.发送问询帧



     serialPort1.Write(buffer, 0, buffer.Length);



 }







private void btnRead_Click(object sender, EventArgs e)

{



    //发送请求帧

    SendData();



}

编写串口数据接收事件

选择对应创建串口点击属性

编写代码

cs 复制代码
 //DataReceived 事件用来接收从站相应的报文(应答帧)

// DataReceived 是在内部开辟一个分线程接收数据的

//弹窗是主线程的控件,不建议使用弹框

 private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)

 {

     SerialPort sp=(SerialPort) sender;



     //buffer 用来存储接收到的数据

     byte[] buffer = new byte[sp.BytesToRead];

     sp.Read(buffer, 0, buffer.Length);



     //校验一下数据是否符合预期

     //13怎么来的 ?

     //读取了4个地址,每个地址的数据占用2个字节, ===8

     //地址码  ===1

     //功能码 ===1

     //有效字节数 ==1

     //校验码   ===2

     //8+1+1+1+2=13

     if (buffer.Length != 13) return;



     //字节数组  存放的是十六进制的数据

     //一个字节是8位    1Byte===8bit     1B=8b

     //两个字节是16位   如: 0x02  0x09   0x02 就是高8位   0x09就是低8位





     //应答帧

     //Tx: 000007 - 01 03 08  00 64    00 C8  00 0A   00 07 30 01

     //固定格式

     //公式: 10进制 === 16进制高8位 * 256 + 16进制的低8位

     int hsl = buffer[3] * 256 + buffer[4];

     int wdz = buffer[5] * 256 + buffer[6];

     int ddl = buffer[7] * 256 + buffer[8];

     int ph = buffer[9] * 256 + buffer[10];



     Invoke(new Action(() =>

     {

         txtHSL.Text=hsl.ToString();

         txtWDZ.Text= wdz.ToString();

         txtDDL.Text= ddl.ToString();

         txtPH.Text= ph.ToString();

     



     }));



 }

编写对应按钮

cs 复制代码
 private void cbRealTimeRead_CheckedChanged(object sender, EventArgs e)

 {



     if (cbRealTimeRead.Checked)

     {

         if (!serialPort1.IsOpen)

         {

             MessageBox.Show("请先连接,再实时显示数据", "错误",MessageBoxButtons.OK,MessageBoxIcon.Error);

             cbRealTimeRead.Checked = false;

             return;

         }



         timer1.Interval = 1000;

         timer1.Start();

                

     }

     else

     {

         timer1.Stop();

              

     }



 }



 private void timer1_Tick(object sender, EventArgs e)

 {

     SendData();

 }

编写对应代码

cs 复制代码
 private void btnWrite_Click(object sender, EventArgs e)

 {

     //先准备请求帧

     byte[] buffer = new byte[8];

     buffer[0]= Convert.ToByte(txtSlaveID.Text.Trim()); //从站地址



     //功能码

     buffer[1] = 0x06;



     //寄存地址

     int address = Convert.ToInt32(txtStartAddress.Text.Trim());//十进制

     //(byte)(address >> 8) 把地址转成高8位

     buffer[2] = (byte)(address >> 8);//写入起始地址的高位

     //(byte)(address & 0xFF) 把地址转成低8位

     buffer[3] = (byte)(address & 0xFF);//写入起始地址的低位





     int data = Convert.ToInt32(txtData.Text.Trim());//数据值

     //10

     //buffer[4] = (byte)(data / 256); //写入的数据的高位

     //buffer[5] = (byte)(data % 256);//写入的数据的低位



     Console.WriteLine("-------");



     Console.WriteLine((byte)(data / 256));//0x00

     Console.WriteLine((byte)(data % 256));//0x01



     Console.WriteLine("-------");

     // >> 位运算符

     // &   按位与

     buffer[4]= (byte)(data >> 8); //写入的数据的高位

     buffer[5]= (byte)(data & 0xFF); //写入的数据的低位





     byte[] crc = CRCHelper.CRC16(buffer);

     buffer[6] = crc[0];//校验码低位

     buffer[7] = crc[1];//校验码高位



     //buffer 就是咱们准备好的请求报文 也叫做问询帧



     //4.发送问询帧



     serialPort1.Write(buffer, 0, buffer.Length);



 }

代码功能分析:

串口读写威盟士五插针程序代码综述

该代码是一个基于 C# WinForms 框架开发的串口通信应用程序,专门用于与威盟士五插针设备进行数据交互,实现了设备数据的读取、写入和实时监控功能。

核心功能模块

1. 串口配置与连接模块

  • 程序启动时自动获取并显示可用串口列表
  • 支持配置串口通信参数:波特率、数据位、停止位和校验位
  • 提供连接 / 关闭按钮,实现串口的连接状态切换
  • 连接状态变化时自动启用 / 禁用参数配置控件,防止误操作

2. 数据读取模块

  • 支持手动读取和定时自动读取两种模式
  • 采用标准 Modbus 协议格式发送读取请求帧:
    • 包含从站地址 (0x01)、功能码 (0x03)
    • 起始地址和数据长度设置
    • CRC16 校验码计算与添加
  • 对接收到的应答帧进行解析,提取 HSL、WDZ、DDL、PH 四项数据
  • 使用 Invoke 方法确保跨线程安全更新 UI 显示

3. 数据写入模块

  • 支持向指定从站地址和寄存器地址写入数据
  • 采用 Modbus 协议的 0x06 功能码进行单寄存器写入
  • 同样包含完整的 CRC16 校验机制
  • 支持用户输入从站 ID、起始地址和写入数据值

4. 实时监控模块

  • 通过复选框控制是否启用实时数据读取
  • 使用定时器实现固定间隔 (1 秒) 自动发送读取请求
  • 实时数据变化时自动更新界面显示

技术实现特点

Modbus 协议实现 :遵循 Modbus RTU 通信协议,正确处理功能码、地址、数据长度和校验机制

CRC 校验 :使用 CRCHelper 工具类进行 CRC16 校验码的计算,确保数据传输的准确性​​​​​​​

线程安全处理 :在 DataReceived 事件中使用 Invoke 方法,安全地跨线程更新 UI 控件​​​​​​​

错误处理 :包含基本的异常捕获机制,当操作出错时显示错误信息​​​​​​​

数据转换 :正确处理十六进制与十进制数据的转换,特别是多字节数据的高低位拼接

潜在扩展点

  1. 可以增加更完善的错误处理机制,特别是针对 Modbus 协议错误码的解析
  2. 可以添加数据记录和导出功能,方便数据分析
  3. 可以增加通信日志显示,便于调试和问题排查
  4. 可以扩展支持更多的 Modbus 功能码,实现更丰富的设备控制
  5. 可以添加数据报警功能,当监测值超出设定范围时发出提示

该程序整体结构清晰,功能明确,专注于与威盟士五插针设备的串口通信,适合作为工业控制场景中设备监控的基础应用。

相关推荐
路长冬4 小时前
matlab与数字信号处理的不定期更新
开发语言·matlab·信号处理
卡卡酷卡BUG4 小时前
Java 后端面试干货:四大核心模块高频考点深度解析
java·开发语言·面试
Yolo566Q4 小时前
OpenLCA生命周期评估模型构建与分析
java·开发语言·人工智能
安娜的信息安全说5 小时前
深入浅出 MQTT:轻量级消息协议在物联网中的应用与实践
开发语言·物联网·mqtt
睡前要喝豆奶粉5 小时前
在.NET Core Web Api中使用redis
redis·c#·.netcore
在坚持一下我可没意见5 小时前
HTTP 协议基本格式与 Fiddler 抓包工具实战指南
java·开发语言·网络协议·tcp/ip·http·java-ee·fiddler
樱花开了几轉5 小时前
element ui下拉框踩坑
开发语言·javascript·ui
报错小能手5 小时前
C++笔记(面向对象)RTTI操作符
开发语言·c++·笔记
草明5 小时前
Go 的 IO 多路复用
开发语言·后端·golang