C#_serialPort_串口的应用

C#_serialPort_串口的应用

前言:一个上位机与下位机通讯最常用的就是串口了,是上位机与外界数据交互的通道。
1、获取串口号部分
2、串口必要参数设置
3、串口数据的接收
4、串口数据的发送

获取串口号部分

说明:一般串口号只能获取是COM3这样的,并不能真实的获取像设备管理器里面这样的串口名字,所以我们要引入一个能够获取电脑硬件信息的类。在项目名上右键添加类,命名为SystemHardware.cs,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace JD_MINI_TOOL
{
    class SystemHardware
    {
        //获取CPU序列号
        public static string GetCPUSerialNumber()
        {
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * From Win32_Processor");
                string sCPUSerialNumber = "";
                foreach (ManagementObject mo in searcher.Get())
                {
                    sCPUSerialNumber = mo["ProcessorId"].ToString().Trim();
                    break;
                }
                return sCPUSerialNumber;
            }
            catch
            {
                return "";
            }
        }


        //获取主板序列号
        public static string GetBIOSSerialNumber()
        {
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * From Win32_BIOS");
                string sBIOSSerialNumber = "";
                foreach (ManagementObject mo in searcher.Get())
                {
                    sBIOSSerialNumber = mo.GetPropertyValue("SerialNumber").ToString().Trim();
                    break;
                }
                return sBIOSSerialNumber;
            }
            catch
            {
                return "";
            }
        }

        //获取硬盘序列号
        public static string GetHardDiskSerialNumber()
        {
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
                string sHardDiskSerialNumber = "";
                foreach (ManagementObject mo in searcher.Get())
                {
                    sHardDiskSerialNumber = mo["SerialNumber"].ToString().Trim();
                    break;
                }
                return sHardDiskSerialNumber;
            }
            catch
            {
                return "";
            }
        }



        /// <summary>
        /// Get system serail port
        /// </summary>
        /// <returns></returns>
        public static string[] GetSerialPort()
        {
            List<string> spList = new List<string>();
            Regex reg = new Regex(@"COM\d+");
            string[] strArr = GetHarewareInfo(HardwareEnum.Win32_PnPEntity, "Name");
            foreach (string s in strArr)
            {
                if (reg.IsMatch(s))
                {
                    spList.Add(s);
                }
            }

            return spList.ToArray();


            //List<string> strs = new List<string>();
            //try
            //{
            //    using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + HardwareEnum.Win32_PnPEntity))
            //    {
            //        var hardInfos = searcher.Get();
            //        foreach (var hardInfo in hardInfos)
            //        {

            //            string str = hardInfo.Properties["Name"].Value.ToString();
            //            //Regex reg = new Regex(@"COM\d+");

            //            //if (reg.IsMatch(str))
            //            //{
            //                strs.Add(str);
            //            //}

            //        }
            //        searcher.Dispose();
            //    }

            //}
            //catch (Exception ex)
            //{
            //    Console.WriteLine(ex.ToString());
            //}
            //return strs.ToArray();





        }

        /// <summary>
        /// Get the system devices information with windows api.
        /// </summary>
        /// <param name="hardType">Device type.</param>
        /// <param name="propKey">the property of the device.</param>
        /// <returns></returns>
        public static string[] GetHarewareInfo(HardwareEnum hardType, string propKey)
        {

            List<string> strs = new List<string>();
            try
            {
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
                {
                    var hardInfos = searcher.Get();
                    foreach (var hardInfo in hardInfos)
                    {
                        if (hardInfo.Properties[propKey].Value != null)
                        {
                            String str = hardInfo.Properties[propKey].Value.ToString();
                            strs.Add(str);
                        }

                    }
                }
                return strs.ToArray();
            }
            catch
            {
                return null;
            }
            finally
            {
                strs = null;
            }
        }//end of func GetHarewareInfo().

        /// <summary>
        /// 枚举win32 api
        /// </summary>
        public enum HardwareEnum
        {
            // 硬件
            Win32_Processor, // CPU 处理器
            Win32_PhysicalMemory, // 物理内存条
            Win32_Keyboard, // 键盘
            Win32_PointingDevice, // 点输入设备,包括鼠标。
            Win32_FloppyDrive, // 软盘驱动器
            Win32_DiskDrive, // 硬盘驱动器
            Win32_CDROMDrive, // 光盘驱动器
            Win32_BaseBoard, // 主板
            Win32_BIOS, // BIOS 芯片
            Win32_ParallelPort, // 并口
            Win32_SerialPort, // 串口
            Win32_SerialPortConfiguration, // 串口配置
            Win32_SoundDevice, // 多媒体设置,一般指声卡。
            Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)
            Win32_USBController, // USB 控制器
            Win32_NetworkAdapter, // 网络适配器
            Win32_NetworkAdapterConfiguration, // 网络适配器设置
            Win32_Printer, // 打印机
            Win32_PrinterConfiguration, // 打印机设置
            Win32_PrintJob, // 打印机任务
            Win32_TCPIPPrinterPort, // 打印机端口
            Win32_POTSModem, // MODEM
            Win32_POTSModemToSerialPort, // MODEM 端口
            Win32_DesktopMonitor, // 显示器
            Win32_DisplayConfiguration, // 显卡
            Win32_DisplayControllerConfiguration, // 显卡设置
            Win32_VideoController, // 显卡细节。
            Win32_VideoSettings, // 显卡支持的显示模式。

            // 操作系统
            Win32_TimeZone, // 时区
            Win32_SystemDriver, // 驱动程序
            Win32_DiskPartition, // 磁盘分区
            Win32_LogicalDisk, // 逻辑磁盘
            Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。
            Win32_LogicalMemoryConfiguration, // 逻辑内存配置
            Win32_PageFile, // 系统页文件信息
            Win32_PageFileSetting, // 页文件设置
            Win32_BootConfiguration, // 系统启动配置
            Win32_ComputerSystem, // 计算机信息简要
            Win32_OperatingSystem, // 操作系统信息
            Win32_StartupCommand, // 系统自动启动程序
            Win32_Service, // 系统安装的服务
            Win32_Group, // 系统管理组
            Win32_GroupUser, // 系统组帐号
            Win32_UserAccount, // 用户帐号
            Win32_Process, // 系统进程
            Win32_Thread, // 系统线程
            Win32_Share, // 共享
            Win32_NetworkClient, // 已安装的网络客户端
            Win32_NetworkProtocol, // 已安装的网络协议
            Win32_PnPEntity,//all device
        }
    }
}

然后就可以获取串口号了

public static bool com_update_arrange_flog = false;  //用来标志该电脑是否存在COM1
private void Form1_Load(object sender, EventArgs e)  //主窗口打开后
{
    serialPort.ReadTimeout = -1;    //设置超时读取时间
    serialPort.RtsEnable = true; //定义DataReceived事件,当串口收到数据后触发事件
    serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
 
    string[] ArryPort = SystemHardware.GetSerialPort();
    if (ArryPort.Length > 0) cbComName.Text = ArryPort[0];  //如果读到串口默认填入一个串口号
    foreach (string arryport in ArryPort)
    {
        if (string.Equals(arryport, "通信端口 (COM1)"))
        {
            com_update_arrange_flog = true;
            break;
        }
    }
}

然后就是动态更新串口了

public void timer2_Tick(object sender, EventArgs e)  //刷新串口
{
    if (com_update_arrange_flog == true)
    {
        update_com_1();
    }
    else
    {
        update_com();
    }
}

void update_com_1()  //识别到有串口COM1
{
    string[] ArryPort = SystemHardware.GetSerialPort();
    if (com_num != ArryPort.Length - 1)
    {
        cbComName.Items.Clear();
        create_com_list.Clear();
        foreach (string arryport in ArryPort)
        {
            if (string.Equals(arryport, "通信端口 (COM1)") == false)
            {
                Console.WriteLine(arryport);
                create_com_list.Add(arryport);
                cbComName.Items.Add(arryport);

            }
        }
        com_num = create_com_list.Count();
    }
}

void update_com()  //没有识别到有串口COM1
{
    string[] ArryPort = SystemHardware.GetSerialPort();
    if (com_num != ArryPort.Length)
    {
        cbComName.Items.Clear();
        create_com_list.Clear();
        foreach (string arryport in ArryPort)
        {
            if (string.Equals(arryport, "通信端口 (COM1)") == false)
            {
                Console.WriteLine(arryport);
                create_com_list.Add(arryport);
                cbComName.Items.Add(arryport);

            }
        }
        com_num = create_com_list.Count();
    }
}

串口必要参数设置

//打开和关闭串口的按钮
private void btnPortOpt_Click(object sender, EventArgs e)  //打开串口
{
    if (cbComName.Text == "")
    {
        MessageBox.Show("串口选择不能为空", "提示");
        return;
    }
    try
    {
        if (btnPortOpt.Text == "打开串口")
        {
            serialPort.PortName = sp_com_name(cbComName.Text);
            serialPort.BaudRate = Convert.ToInt32(cbxBaudRate.Text.Trim());
            serialPort.Parity = System.IO.Ports.Parity.None;     //奇偶校验
            serialPort.DataBits = 8;                             //数据位
            serialPort.StopBits = System.IO.Ports.StopBits.One;  //停止位
            serialPort.ReadBufferSize = 2 * 1024 * 1024;         //缓冲区 2M
            serialPort.Open();
        }
        if (btnPortOpt.Text == "关闭串口")
        {
            serialPort.Close();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        if (serialPort.IsOpen)
        {
            btnPortOpt.Text = "关闭串口";
            UpdatalabText();//信息提示框
        }
        else
        {
            btnPortOpt.Text = "打开串口";
            UpdatalabText();
        }
    }
}

//输入串口名字字符串将串口号转变为串口可以识别的COM
public string sp_com_name(string str)
{
    string sp_com_name;
    if (str != null)
    {
        string S1 = str.ToString().ToLower();
        if (S1.Contains("com"))
        {
            int i = S1.IndexOf("(");
            int j = S1.IndexOf(")");
            if ((j - i) == 5)
            {
                sp_com_name = "COM" + S1[i + 4];//设置串口号
                return sp_com_name;
            }
            if ((j - i) == 6)
            {
                sp_com_name = "COM" + S1[i + 4] + S1[i + 5];//设置串口号
                return sp_com_name;
            }
            if ((j - i) == 7)
            {
                sp_com_name = "COM" + S1[i + 4] + S1[i + 5] + S1[i + 6];//设置串口号
                return sp_com_name;
            }
        }
    }
    return "";
}

//重新设定串口波特率后要及时更新
private void cbxBaudRate_TextChanged(object sender, EventArgs e)
{
    int baudrate = 9600;  //默认9600
    if (int.TryParse(cbxBaudRate.Text, out baudrate))
    {
        serialPort.BaudRate = Convert.ToInt32(cbxBaudRate.Text.Trim());
    }
    else MessageBox.Show("波特率异常!", "错误提示");
}

串口数据的接收

下面这个函数就是项目中实际用到的,接收16进制数据后进行处理的过程,解析数据帧

private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)  //CRCPing-X:宽度16 多项式1021 初始值FFFF 结果异或值0000
{
    bool isHex = true;
    if (rdio_show_hax.Checked)
    {
        isHex = true;
    }
    else
    {
        isHex = false;
    }
    System.Threading.Thread.Sleep(100);    //延时100ms等待接收完数据
    //this.Invoke就是跨线程访问ui的方法,也是文本的范例
    this.Invoke((EventHandler)delegate
    {
        serport_richTextBox.Text += "收--《《";
        if (isHex == false)
        {
            System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();
            Byte[] readBytes = new Byte[serialPort.BytesToRead];
            serialPort.Read(readBytes, 0, readBytes.Length);
            string decodString = utf8.GetString(readBytes);
            serport_richTextBox.Text += decodString;// sp.ReadLine();
        }
        else
        {
            Byte[] ReceivedData = new Byte[serialPort.BytesToRead];//创建接收字节数组
            serialPort.Read(ReceivedData, 0, ReceivedData.Length);//读取所接收到的数据
            String RecvDataText = null;
            for (int i = 0; i < ReceivedData.Length; i++)
            {
                RecvDataText = (ReceivedData[i].ToString("X2") + " ");
                serport_richTextBox.Text += RecvDataText;
            }
            serport_richTextBox.Text += "\r\n";

            ushort data_length = (ushort)(ReceivedData[5] + (ReceivedData[6] * 256));  //获取Payload的数据长度
            byte[] data1 = new byte[data_length+5];  //根据上述获取的长度动态创建适合长度的数组,不然0x00这个的数据会影响crc校验值
            byte[] data2 = new byte[2];

            for (int j = 0; j < ReceivedData.Length - 4; j++)
            {
                data1[j] = ReceivedData[j+2];
            }
            data2[0] = ReceivedData[ReceivedData.Length - 1];
            data2[1] = ReceivedData[ReceivedData.Length - 2];

            if (CRC16(data1,ref data2))  //crc校验
            {
                if (ReceivedData[0] == Sync_h)  //检验头部数据
                {
                    if (ReceivedData[1] == Sync_l)  //检验头部数据
                    {
                        if (ReceivedData[2] == Version)  //校验协议版本
                        {
                            byte Seq = ReceivedData[4];  //mcu->wifi上报数据
                            switch (ReceivedData[3])
                            {
                                case Query_mcu:  //数据类型一
                                    Console.WriteLine("查询设备状态");
                                    break;
                                case Control_mcu:  //数据类型二  
                                    Console.WriteLine("控制设备");
                                    break;
                                case Upload_wifi:  //数据类型三
                                    Console.WriteLine("123");
                                    break;
                            }
                        }
                    }
                }
            }
        }
        serialPort.DiscardInBuffer();
    });
}

串口数据的发送

byte[] send_data = new byte[10];
send_data[0] = 0x5a;
send_data[1] = 0x5a;
send_data[2] = data[0];
send_data[3] = data[1];
send_data[4] = data[2];
send_data[5] = data[3];
send_data[6] = data[4];
send_data[7] = data[5];
send_data[8] = crc_data[1];
send_data[9] = crc_data[0];
serialPort.Write(send_data, 0, send_data.Length);
//下面是显示在日志框中
String SendDataText = null;
serport_richTextBox.Text += "发--》》";
for (int i = 0; i < send_data.Length; i++)
{
    SendDataText = (send_data[i].ToString("X2") + " ");
    serport_richTextBox.Text += SendDataText;
}
serport_richTextBox.Text += "\r\n";
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值