C#上位机(串口工具添加相应的汉字编码转换)

在之前写的串口工具上位机中添加汉字编码转换功能,还是针对gb2312.把上次写的博客融汇贯通一下。

1.设置编码格式,在窗体函数中设置,相当于初始化串口的编码方式。

public Form1()
{
    InitializeComponent();
    System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

    //设置串口的编码格式
    serialPort1.Encoding = Encoding.GetEncoding("gb2312");
}

在这里插入图片描述
2.对于串口函数的修改


//串口数据信息接收
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)//SerialDataReceived 
{
   //接收方式为字符模式,字符方式读
   //Checked:获取或设置一个值,该值指示是否已选中控件。
   if (!radioButton3.Checked)
   {
       //串口类会自动处理汉字。

       //字符串方式读缓冲区中的数据
       string str = serialPort1.ReadExisting();
       //把读取的数据添加至接收区。AppendText():向文本框的当前文本追加文本。
       textBox2.AppendText(str);
   }
   //接收方式为数值模式,数值方式读
   else
   {
       //定义一个缓冲器数组,读取串口的数据的字节数
       byte[] buffer = new byte[serialPort1.BytesToRead];
       //将缓冲器的数据存入数组中。操作系统的串口是非实时性的,所以一次串口可能是多个字节,串口事件触发时会响应。
       serialPort1.Read(buffer, 0, buffer.Length);
       //遍历数组
       foreach (byte Member in buffer)
       {
           //转换为大写十六进制字符串
           string str = Convert.ToString(Member, 16).ToUpper();
           //对单个值,进行补0
           textBox2.AppendText("0x" + ((str.Length == 1) ? "0" + str : str)+" ");
       }   
   }
}

在这里插入图片描述

串口会自动处理汉字。
在这里插入图片描述
防止中断引发错误。读取缓存器中的长度。

3.验证
3.1 发送字符,接收字符
在这里插入图片描述
3.2 发送字符,接收数值
在这里插入图片描述

存在一个问题:为啥接收的值后面多了一个0x0A,我调试了一下,缓存器的长度为5.实在不知道哪错了。之后解决了写博客告诉大家。

3.3 发送数值,接收数值
在这里插入图片描述
3.4 发送数值,接收字符
在这里插入图片描述
4.存在的问题
4.1 发送数值时,不能写0x,也不能有空格**
在这里插入图片描述
在这里插入图片描述
4.2 接收数据时,后面会多一个0x0A
在这里插入图片描述
5.源代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;

namespace CommTool
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

            //设置串口的编码格式
            serialPort1.Encoding = Encoding.GetEncoding("gb2312");
        }
        

        //窗体事件
        private void Form1_Load(object sender, EventArgs e)
        {
            Updata_Serialport_Name(comboBox1);  //调用更新可用串口函数,comboBox1为 端口 组合框名字
            
            /*//对端口进行设置
            for (int i = 1; i < 20; i++)
            {
                comboBox1.Items.Add("COM"+ i.ToString());
            }*/
            //对串口号、波特率进行默认值设置
            comboBox1.Text = "COM1";
            comboBox2.Text = "4800";
            radioButton1.Checked = true;   //函数中选择发送模式 为“数值”发送模式。 radioButton1为单选按钮属性(name)名字
            radioButton3.Checked = true;   //函数中选择接收模式 为“数值”接收模式。 radioButton3为单选按钮属性(name)名字
            button1.Text = "打开串口";     //确保 “打开串口”按键文本属性为 “打开串口”
            button2.Text = "关闭串口";     //确保 “关闭串口”按键文本属性为 “关闭串口”

            //必须手动添加处理串口数据接收
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(this.Port_DataReceived);//SerialDataReceived 
        }

        /*用户自定义更新可用串口函数*/
        private void Updata_Serialport_Name(ComboBox MycomboBox)
        {
            //SerialPort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出
            //定义字符串数组,数组名为 ArryPort
            //SerialPort.GetPortNames()在System.IO.Ports.SerialPort.GetPortNames()
            string[] ArryPort = SerialPort.GetPortNames();

            //清除当前组合框下拉菜单内容
            MycomboBox.Items.Clear();                       
            for (int i = 0; i < ArryPort.Length; i++)
            {
                //将所有的可用串口号添加到端口对应的组合框中
                MycomboBox.Items.Add(ArryPort[i]);  
            }
        }

        //串口数据信息接收
        private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)//SerialDataReceived 
        {
            //接收方式为字符模式,字符方式读
            //Checked:获取或设置一个值,该值指示是否已选中控件。
            if (!radioButton3.Checked)
            {
                //串口类会自动处理汉字。

                //字符串方式读缓冲区中的数据
                string str = serialPort1.ReadExisting();
                //把读取的数据添加至接收区。AppendText():向文本框的当前文本追加文本。
                textBox2.AppendText(str);
            }
            //接收方式为数值模式,数值方式读
            else
            {
                //定义一个缓冲器数组,读取串口的数据的字节数
                byte[] buffer = new byte[serialPort1.BytesToRead];
                //将缓冲器的数据存入数组中。操作系统的串口是非实时性的,所以一次串口可能是多个字节,串口事件触发时会响应。
                serialPort1.Read(buffer, 0, buffer.Length);
                //遍历数组
                foreach (byte Member in buffer)
                {
                    //转换为大写十六进制字符串
                    string str = Convert.ToString(Member, 16).ToUpper();
                    //对单个值,进行补0
                    textBox2.AppendText("0x" + ((str.Length == 1) ? "0" + str : str)+" ");
                }   
            }

        }

        //打开串口按钮
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                //在打开串口之前获取串口号和波特率
                serialPort1.PortName = comboBox1.Text;
                //转换为10进制,10可省略
                serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text,10);
                //打开串口
                serialPort1.Open();
                //打开串口按钮不可用,变成灰色
                button1.Enabled = false;
                //关闭串口按钮可用。
                button2.Enabled = true;
            }
            catch
            { 
                MessageBox.Show("端口错误,请检查串口","打开串口错误");
            }
           
        }

        //关闭串口按钮
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                //关闭串口
                serialPort1.Close();
                //打开串口按钮可用
                button1.Enabled = true;
                //关闭串口按钮不可用,变成灰色
                button2.Enabled = false;
            }
            catch
            {
                //一般关闭串口不出错,此处对程序不进行处理
            }
        }

        //发送按钮
        private void button3_Click(object sender, EventArgs e)
        {
            byte[] data = new byte[1];
            // IsOpen :获取一个值,该值指示 System.IO.Ports.SerialPort 对象的打开或关闭状态。
            // 返回结果: 如果串行端口已打开,则为 true;否则为 false。 默认值为 false。
            if (serialPort1.IsOpen)//串口打开
            { 
                //发送框不能为空
                if (textBox1.Text != "")
                { 
                    //发送模式为字符模式
                    if (!radioButton1.Checked)
                    {
                        try
                        {
                            //将发送的数据存在于缓冲区
                            serialPort1.WriteLine(textBox1.Text);
                        }
                        catch(Exception err)
                        {
                            MessageBox.Show("串口数据写入错误", "发送错误");
                        }
                    }
                    //发送模式为数值模式
                    else
                    {
                        try
                        {
                            //文本数据长度
                            int dataLength = textBox1.Text.Length;
                            //判断本本个数是奇数还是偶数
                            int dataRemain = textBox1.Text.Length % 2;
                            //(dataLength - dataRemain)/2 十六进制发送时,看有几个字节。

                            //处理前length-1个数据
                            for (int i = 0; i < (dataLength - dataRemain)/2; i++)
                            {
                                // Substring(): 
                                // 从此实例检索子字符串。 子字符串从指定的字符位置开始且具有指定的长度。
                                // 参数: 
                                //   startIndex:
                                //     此实例中子字符串的起始字符位置(从零开始)。
                                //   length:
                                //     子字符串中的字符数。
                                // 返回结果: 
                                //     与此实例中在 startIndex 处开头、长度为 length 的子字符串等效的一个字符串,如果 startIndex 等于此实例的长度且 length
                                //     为零,则为 System.String.Empty。
                                data[0] = Convert.ToByte(textBox1.Text.Substring(i*2,2),16);//将获取的数值转换为十六进制每两位两位存入data[0]这个字节中

                                //Convert.ToByte(): 
                                //将指定基数的数字的字符串表示形式转换为等效的 8 位无符号整数。
                                // 参数: 
                                //   value:
                                //     包含要转换的数字的字符串。
                                //   fromBase:
                                //     value 中数字的基数,它必须是 2、8、10 或 16。
                                // 返回结果: 
                                //     与 value 中数字等效的 8 位无符号整数,如果 value 为 null,则为 0(零)。

                                serialPort1.Write(data, 0, 1);//循环发送每一个字节,如abc则发0xab

                                // Write(data, 0, 1): 
                                // 使用缓冲区的数据将指定数量的字节写入串行端口。
                                // 参数: 
                                //   buffer:
                                //     包含要写入端口的数据的字节数组。
                                //   offset:
                                //     buffer 参数中从零开始的字节偏移量,从此处开始将字节复制到端口。
                                //   count:
                                //     要写入的字节数。

                            }

                            //处理奇数个数据的最后一位
                            if(textBox1.Text.Length % 2 != 0)
                            {   
                                //将最后一位转换为十六进制数据存入data中。
                                data[0] = Convert.ToByte(textBox1.Text.Substring(textBox1.Text.Length-1, 1),16);
                                //发送最后一位
                                serialPort1.Write(data, 0, 1);
                            }
                        }
                        catch (Exception err)
                        {
                            MessageBox.Show("发送数据错误", "发送错误");
                        }
                    }

                }
            }

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            //将滚动条调整至当前位置。
            textBox1.ScrollToCaret();
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            textBox2.ScrollToCaret();
        }
        //清空接收文本
        private void button4_Click(object sender, EventArgs e)
        {
            textBox2.Text = "";
        }
    }
}

详解可以查看之前的博客。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值