串口通信学习(GPS模块)2021.5.10

1、串口通信简介

        串口通信(Serial Communication)是利用串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。**串口通信最重要的参数是波特率、数据位、停止位和奇偶校验**。

1.1 波特率

        波特率指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。

1.2 数据位

        当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。标准的ASCII码是0~127(7位),而扩展的ASCII码是0~255(8位),如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。

1.3 停止位

        停止位即用于表示单个包的最后一位。典型的值为1,1.5和2位。

1.4 奇偶校验位

        串口通信有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,假设传输的数据位为01001100,如果是奇校验,则奇校验位为0(要确保总共有奇数个1),如果是偶校验,则偶校验位为1(要确保总共有偶数个1)。

2、GPS模块串口通信配置

GPS 模块
正面
反面

2.1 驱动安装

        在GPS模块上的USB插入电脑之前,首先向客服人员索要驱动,得到PL2303_Prolific_GPS_AllInOne_1013.exe驱动安装包后,双击运行即可,安装完成后可在控制面板中查看已安装的程序中有PL-2303 USB-to-Serial,表示安装成功。



在这里插入图片描述

        当然也可以自己从网上下载相关的驱动安装包后安装,也没有问题,如下面的PL2303_Prolific_DriveInstaller_v130.exe和PL2303_64bit_Installer.exe均可。

2.2 插入GPS模块

        驱动安装成功后,可以将GPS模块的USB接口插入到电脑的USB接口上,这时电脑右下方会提示成功安装了设备驱动程序,同时在电脑->设备管理器中也可进行查看

        在设备管理器的端口(COM和LPT)下可以看到Prolific USB-to-Serial Comm Port(COM3),右键->属性可以查看该GPS模块对应端口的具体信息,其中最重要的就是端口设置中的波特率、数据位、停止位和奇偶校验这四个参数
在这里插入图片描述

常规
端口设置
驱动程序
详细信息

2.3 GPS模块串口通信数据简介

在这里插入图片描述

        由于GPS模块接收到的数据遵循NMEA-0183协议该协议采用ASCII码,其串行通信默认参数为:波特率=9600bps,数据位=8bit,开始位=1bit,停止位=1bit,无奇偶校验。由于数据中包含GPRMC、GPVTG、GPGNS、GPGGA、GPGSA、GPGLL等,但我只需要RMC中一条数据,所以打开串口助手SSCOM3.2,打开COM3串口后通过向GPS模块发送新行$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29使得模块只输出 GPRMC(这里是客服人员告诉我的指令)

串口调试助手

在这里插入图片描述

3、Java实现GPS模块串口通信

3.1 所需环境(Eclipse+Java)

Eclipse
Java

3.2 新建Java工程COMM

        打开Eclipse,文件->新建Java Project,输入项目名称为COMM,同时选择对应的JAVA JDK 1.8后确定即可,然后在src文件夹下新建三个Package包(bean、serialport和test),并在bean包下新建GPSRMCMessage类,在serialport包下新建CostomException类、ParamConfig类和SerialPortUtil类,在test包下新建hellodouble类和Operate类。

3.3 各个包下的java类代码

3.3.1 SerialPortUtils.java

package serialport;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Enumeration;
import java.util.TooManyListenersException;

import bean.GPSRMCMessage;
import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;

/**
 * 串口参数的配置 串口一般有如下参数可以在该串口打开以前进行配置: 包括串口号,波特率,输入/输出流控制,数据位数,停止位和奇偶校验。
 */
// 注:串口操作类一定要继承SerialPortEventListener
public class SerialPortUtils implements SerialPortEventListener {
	// 检测系统中可用的通讯端口类
	private CommPortIdentifier commPortId;
	// 枚举类型
	private Enumeration<CommPortIdentifier> portList;
	// RS232串口
	private SerialPort serialPort;
	// 输入流
	private InputStream inputStream;
	// 输出流
	private OutputStream outputStream;
	// 保存串口返回信息
	private String data;
	// 保存串口返回信息十六进制
	private String dataHex;
	// 解析后的数据
	private GPSRMCMessage gpsrmc_msg;
    public int resulti=1;//写txt的个数

	@SuppressWarnings("unchecked")
	public void init(ParamConfig paramConfig) throws CostomException {
		// 获取系统中所有的通讯端口
		portList = CommPortIdentifier.getPortIdentifiers();
		// 记录是否含有指定串口
		boolean isExsist = false;
		// 循环通讯端口
		while (portList.hasMoreElements()) {
			commPortId = portList.nextElement();
			// 判断是否是串口
			if (commPortId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				// 比较串口名称是否是指定串口
				if (paramConfig.getSerialNumber().equals(commPortId.getName())) {
					// 串口存在
					isExsist = true;
					// 打开串口
					try {
						// open:(应用程序名【随意命名】,阻塞时等待的毫秒数)
						serialPort = (SerialPort) commPortId.open(Object.class.getSimpleName(), 2000);
						// 设置串口监听
						serialPort.addEventListener(this);
						// 设置串口数据时间有效(可监听)
						serialPort.notifyOnDataAvailable(true);
						// 设置串口通讯参数:波特率,数据位,停止位,校验方式
						serialPort.setSerialPortParams(paramConfig.getBaudRate(), paramConfig.getDataBit(),
								paramConfig.getStopBit(), paramConfig.getCheckoutBit());
					} catch (PortInUseException e) {
						throw new CostomException("端口被占用");
					} catch (TooManyListenersException e) {
						throw new CostomException("监听器过多");
					} catch (UnsupportedCommOperationException e) {
						throw new CostomException("不支持的COMM端口操作异常");
					}
					// 结束循环
					break;
				}
			}
		}
		// 若不存在该串口则抛出异常
		if (!isExsist) {
			throw new CostomException("不存在该串口!");
		}
	}

	/**
	 * 实现接口SerialPortEventListener中的方法 读取从串口中接收的数据
	 */
	@Override
	public void serialEvent(SerialPortEvent event) {
		switch (event.getEventType()) {
		case SerialPortEvent.BI: // 通讯中断
		case SerialPortEvent.OE: // 溢位错误
		case SerialPortEvent.FE: // 帧错误
		case SerialPortEvent.PE: // 奇偶校验错误
		case SerialPortEvent.CD: // 载波检测
		case SerialPortEvent.CTS: // 清除发送
		case SerialPortEvent.DSR: // 数据设备准备好
		case SerialPortEvent.RI: // 响铃侦测
		case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 输出缓冲区已清空
			break;
		case SerialPortEvent.DATA_AVAILABLE: // 有数据到达
			// 调用读取数据的方法
			try {
				myReadComm();
			} catch (CostomException e) {
				e.printStackTrace();
			}
			break;
		default:
			break;
		}
	}

	public void myReadComm() throws CostomException {
		try {
			inputStream = serialPort.getInputStream();
			// 通过输入流对象的available方法获取数组字节长度
			byte[] readBuffer = new byte[inputStream.available()];
			// 从线路上读取数据流
			int len = 0;
			data = "";
			// 从输入流读取数据,直到遇到"\r\n"或数据为空,即读取一行数据
			while (true) {
				len = inputStream.read(readBuffer);
				if (len == -1 || len == 0)
					break;
				data = data.concat(new String(readBuffer, 0, len));
				if (data.endsWith("\r\n"))
					break;
			}
			System.out.print(data);
			// 转为十六进制数据
			//dataHex = bytesToHexString(data.getBytes());
			//System.out.println(dataHex);
			 //解析数据
			gpsrmc_msg = GPSRMCMessage.parse(data);
			System.out.print(gpsrmc_msg.toMyString());
			inputStream.close();
			inputStream = null;
//			//2021.4.11 By jzbg
//			FileOutputStream fos = null;
//			OutputStreamWriter writer = null;
//			String writetxtfilepath = "D:\\guotuziyuan\\zhongjiban\\system\\ActiveDemoEarth\\WindowsFormsApplication1\\bin\\x64\\Release\\tag\\result"+resulti+".txt";
//			File file = new File(writetxtfilepath);
//			fos = new FileOutputStream(file);
//			writer = new OutputStreamWriter(fos,"utf-8");
//			writer.write(msg.toJJGString());
//			writer.close();
//			fos.close();
			this.resulti++;
		} catch (IOException e) {
			throw new CostomException("读取串口数据时发生IO异常");
		}
	}

	public void readComm() throws CostomException {
		try {
			inputStream = serialPort.getInputStream();
			// 通过输入流对象的available方法获取数组字节长度
			byte[] readBuffer = new byte[inputStream.available()];
			// 从线路上读取数据流
			int len = 0;
			while ((len = inputStream.read(readBuffer)) != -1) {
				// 直接获取到的数据
				data = new String(readBuffer, 0, len).trim();
				// 转为十六进制数据
				dataHex = bytesToHexString(readBuffer);
				System.out.println("data:" + data);
				System.out.println("dataHex:" + dataHex);// 读取后置空流对象
				inputStream.close();
				inputStream = null;
				break;
			}
		} catch (IOException e) {
			throw new CostomException("读取串口数据时发生IO异常");
		}
	}

	public void sendComm(String data) throws CostomException {
		byte[] writerBuffer = null;
		try {
			writerBuffer = hexToByteArray(data);
		} catch (NumberFormatException e) {
			throw new CostomException("命令格式错误!");
		}
		try {
			outputStream = serialPort.getOutputStream();
			outputStream.write(writerBuffer);
			outputStream.flush();
		} catch (NullPointerException e) {
			throw new CostomException("找不到串口。");
		} catch (IOException e) {
			throw new CostomException("发送信息到串口时发生IO异常");
		}
	}

	public void closeSerialPort() throws CostomException {
		if (serialPort != null) {
			serialPort.notifyOnDataAvailable(false);
			serialPort.removeEventListener();
			if (inputStream != null) {
				try {
					inputStream.close();
					inputStream = null;
				} catch (IOException e) {
					throw new CostomException("关闭输入流时发生IO异常");
				}
			}
			if (outputStream != null) {
				try {
					outputStream.close();
					outputStream = null;
				} catch (IOException e) {
					throw new CostomException("关闭输出流时发生IO异常");
				}
			}
			serialPort.close();
			serialPort = null;
		}
	}

	/**
	 * 十六进制串口返回值获取
	 */
	public String getDataHex() {
		String result = dataHex;
		// 置空执行结果
		dataHex = null;
		// 返回执行结果
		return result;
	}

	/**
	 * 串口返回值获取
	 */
	public String getData() {
		String result = data;
		// 置空执行结果
		data = null;
		// 返回执行结果
		return result;
	}

	/**
	 * Hex字符串转byte
	 * 
	 * @param inHex
	 *            待转换的Hex字符串
	 * @return 转换后的byte
	 */
	public static byte hexToByte(String inHex) {
		return (byte) Integer.parseInt(inHex, 16);
	}

	/**
	 * hex字符串转byte数组
	 * 
	 * @param inHex
	 *            待转换的Hex字符串
	 * @return 转换后的byte数组结果
	 */
	public static byte[] hexToByteArray(String inHex) {
		int hexlen = inHex.length();
		byte[] result;
		if (hexlen % 2 == 1) {
			// 奇数
			hexlen++;
			result = new byte[(hexlen / 2)];
			inHex = "0" + inHex;
		} else {
			// 偶数
			result = new byte[(hexlen / 2)];
		}
		int j = 0;
		for (int i = 0; i < hexlen; i += 2) {
			result[j] = hexToByte(inHex.substring(i, i + 2));
			j++;
		}
		return result;
	}

	/**
	 * 数组转换成十六进制字符串
	 * 
	 * @param byte[]
	 * @return HexString
	 */
	public static final String bytesToHexString(byte[] bArray) {
		StringBuffer sb = new StringBuffer(bArray.length);
		String sTemp;
		for (int i = 0; i < bArray.length; i++) {
			sTemp = Integer.toHexString(0xFF & bArray[i]);
			if (sTemp.length() < 2)
				sb.append(0);
			sb.append(sTemp.toUpperCase());
		}
		return sb.toString();
	}
}

3.3.2 CostomException.java

package serialport;

public class CostomException extends Exception{

	private static final long serialVersionUID = 4087486187456785575L;

	public CostomException() {
        super();
    }
	
	public CostomException(String message) {
        super(message);
    }
}

3.3.3 ParamConfig.java

package serialport;

public class ParamConfig {

    private String serialNumber;// 串口号
    private int baudRate;        // 波特率
    private int checkoutBit;    // 校验位
    private int dataBit;        // 数据位
    private int stopBit;        // 停止位
    
    public ParamConfig() {}
        
    /**
     * 构造方法
     * @param serialNumber    串口号
     * @param baudRate        波特率
     * @param checkoutBit    校验位
     * @param dataBit        数据位
     * @param stopBit        停止位
     */
    public ParamConfig(String serialNumber, int baudRate, int checkoutBit, int dataBit, int stopBit) {
        this.serialNumber = serialNumber;
        this.baudRate = baudRate;
        this.checkoutBit = checkoutBit;
        this.dataBit = dataBit;
        this.stopBit = stopBit;
    }

	public String getSerialNumber() {
		return serialNumber;
	}

	public void setSerialNumber(String serialNumber) {
		this.serialNumber = serialNumber;
	}

	public int getBaudRate() {
		return baudRate;
	}

	public void setBaudRate(int baudRate) {
		this.baudRate = baudRate;
	}

	public int getCheckoutBit() {
		return checkoutBit;
	}

	public void setCheckoutBit(int checkoutBit) {
		this.checkoutBit = checkoutBit;
	}

	public int getDataBit() {
		return dataBit;
	}

	public void setDataBit(int dataBit) {
		this.dataBit = dataBit;
	}

	public int getStopBit() {
		return stopBit;
	}

	public void setStopBit(int stopBit) {
		this.stopBit = stopBit;
	}


}

3.3.4 GPSRMCMessage.java

package bean;

public class GPSRMCMessage 
{
	private String RMCID; // $GPRMC,语句 ID,表明该语句为 Recommended Minimum (RMC)推荐最小定位信息
	private double UTCTime; // UTC 时间,hhmmss.sss 格式
	private String state; // 状态,A=定位,V=未定位
	private double lat; // 纬度 ddmm.mmmm,度分格式(前导位数不足则补 0)
	private String LatDirection; // 纬度 N(北纬)或 S(南纬)
	private double lon; // 经度 dddmm.mmmm,度分格式(前导位数不足则补 0)
	private String LonDirection; // 经度 E(东经)或 W(西经)
	private double speed; // 速度,节,Knots
	private double α; // 方位角,度
	private int UTCDate; // UTC 日期,DDMMYY 格式
	private double δ; // 磁偏角,(000 - 180)度(前导位数不足则补 0)
	private double δDirection; // 磁偏角方向,E=东 W=西
	private String verification_value; // 校验值
	//$GNRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
	public GPSRMCMessage() 
	{
		this.RMCID = ""; 
		this.UTCTime = 0;
		this.state = "";
		this.lat = 0;
		this.LatDirection = "";
		this.lon = 0;
		this.LonDirection = "";
		this.speed = 0;
		this.α = 0;
		this.UTCDate = 0;
		this.δ  =0;
		this.δDirection = 0; 
		this.verification_value = "";
	}

	public static GPSRMCMessage parse(String data) 
	{
		GPSRMCMessage msg = new GPSRMCMessage();
		String[] s = data.split(",");
		msg.RMCID = s[0]; 
		msg.UTCTime = Double.valueOf(s[1]);
		msg.state = "";
		Double temp = Double.valueOf(s[3]);
		msg.lat =  temp/100.0 - (temp%100.0)/100.0 + (temp%100.0)/60.0;
		msg.LatDirection = "";
		temp = Double.valueOf(s[5]);
		msg.lon = temp/100.0 - (temp%100.0)/100.0 + (temp%100.0)/60.0;
		msg.LonDirection = "";
		msg.speed = Double.valueOf(s[7]);
		msg.α = Double.valueOf(s[8]);
		msg.UTCDate = Integer.valueOf(s[9]);;
		msg.δ  =0;
		msg.δDirection = 0; 
		msg.verification_value =s[12];
		return msg;
	}

	public String toMyString()
	{
		return 	"推荐最小定位信息:"	+this.RMCID
		+ "UTC:" +this.UTCTime
		+ "状态:"+this.state
		+ "纬度:"+this.lat
		+ "纬度方向:"+this.LatDirection
		+ "经度:"+this.lon
		+ "经度方向:"+this.LonDirection
		+ "速度:"+this.speed
		+ "方位角:"+this.α
		+ "UTC日期:"+this.UTCDate
		+ "磁偏角:"+this.δ
		+ "磁偏角方向:"+this.δDirection
		+ "校验值:"+this.verification_value;
	}
}

3.3.5 Operate.java(主函数所在类)

package test;

import serialport.CostomException;
import serialport.ParamConfig;
import serialport.SerialPortUtils;

public class Operate 
{
	public static void Execute() throws CostomException
	{
		// 实例化串口操作类对象
        SerialPortUtils serialPort = new SerialPortUtils();
        // 创建串口必要参数接收类并赋值,赋值串口号,波特率,校验位,数据位,停止位
        ParamConfig paramConfig = new ParamConfig("COM3", 9600, 0, 8, 1);
        // 初始化设置,打开串口,开始监听读取串口数据,并打印数据
        serialPort.init(paramConfig);
	}

	public static void main(String[] args) throws Exception 
	{
        Operate.Execute();
    }
}

3.3.6 hellodouble.java

package test;

public class hellodouble 
{
	public static void main(String[] args) 
	{
		double a =11421.1059 ,b=3031.7611;
		double temp =a;
		System.out.println(temp/100.0 - (temp%100.0)/100.0 + (temp%100.0)/60.0);
	}
}

3.4 添加串口通信依赖包

        java代码编写完成后,如果直接运行Operate.java会提示java库路径中没有rxtxSerial链接,所以要在COMM项目中添加串口通信相关的依赖。
在这里插入图片描述
        串口通信项目所依赖的jar包(RXTXcomm.jar)和dll(rxtxParallel.dll和rxtxSerial.dll)如下图所示,将两个dll文件和一个jar包复制到Java项目COMM中,同时将jar包添加到项目COMM的Java Build Path运行路径当中,再次运行Operate.java即可成功运行,接收数据。

配置Java Build Path
复制依赖包

3.5 运行结果

        如下图所示,控制台中输出了接收到的GNRMC数据如$GNRMC,023724.000,A,3031.7606,N,11421.0989,E,0.40,356.63,100521,,,A*7F,同时也对数据进行了解析,得到如推荐最小定位信息:$GNRMCUTC:23724.0状态:纬度:30.529343333333333纬度方向:经度:114.35164833333334经度方向:速度:0.4方位角:356.63UTC日期:100521磁偏角:0.0磁偏角方向:0.0校验值:A*7F
在这里插入图片描述

4、C#实现GPS模块串口通信(使用SerialPort)

4.1 所需环境(VS 2015 +C#)

4.2 新建C#Windows窗体项目SerailCOMMWindows

        使用Visual Studio新建一个C#下的Windows窗体应用程序,将Form1窗体名称改为串口调试助手,同时利用左侧的工具箱向窗体中拖入以下控件:4个GroupBox组合框、7个Button按钮、8个Label标签、5个ComBox下拉框、2个RadioButton单选框、4个TextBox文本框、1个SerialPort串行端口、1个StatusStrip状态栏,具体说明如下:

groupBox1 为串口设置组合框
groupBox2 为数据接收组合框
groupBox3 为数据发送组合框
groupBox4 为文件操作组合框
button2 为打开串口按钮
button3 为关闭串口按钮
button4 为清空数据按钮
button5 为发送数据按钮
button6 为打开文件按钮
button7 为保存文件按钮
label1 为串口号标签
label2 为波特率标签
label3 为停止位标签
label4 为奇偶校验标签
label5 为数据位标签
label6 为间隔标签
label8 为文件路径标签
comboBox1 为串口号对应下拉框
comboBox2 为波特率对应下拉框
comboBox3 为停止位对应下拉框
comboBox4 为奇偶校验对应下拉框
comboBox5 为数据位对应下拉框
radioButton1 为字符显示单选框
radioButton2 为hex显示单选框
textBox1 为数据接收下侧文本框
textBox2 为间隔右侧文本框
textBox3 为文件路径右侧文本框
textBox4 为数据发送下侧文本框

        设计好的Windows窗体布局见下图
在这里插入图片描述

4.3 C#项目代码

4.3.1 窗体设计器代码Form1.Designer.cs(对照即可)

namespace SerialCOMMWindows
{
    partial class Form1
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗体设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要修改
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.button3 = new System.Windows.Forms.Button();
            this.textBox2 = new System.Windows.Forms.TextBox();
            this.label7 = new System.Windows.Forms.Label();
            this.label6 = new System.Windows.Forms.Label();
            this.radioButton2 = new System.Windows.Forms.RadioButton();
            this.radioButton1 = new System.Windows.Forms.RadioButton();
            this.button2 = new System.Windows.Forms.Button();
            this.comboBox5 = new System.Windows.Forms.ComboBox();
            this.comboBox4 = new System.Windows.Forms.ComboBox();
            this.label5 = new System.Windows.Forms.Label();
            this.label4 = new System.Windows.Forms.Label();
            this.comboBox3 = new System.Windows.Forms.ComboBox();
            this.comboBox2 = new System.Windows.Forms.ComboBox();
            this.label3 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.comboBox1 = new System.Windows.Forms.ComboBox();
            this.label1 = new System.Windows.Forms.Label();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.groupBox3 = new System.Windows.Forms.GroupBox();
            this.textBox4 = new System.Windows.Forms.TextBox();
            this.button5 = new System.Windows.Forms.Button();
            this.button4 = new System.Windows.Forms.Button();
            this.groupBox4 = new System.Windows.Forms.GroupBox();
            this.label8 = new System.Windows.Forms.Label();
            this.textBox3 = new System.Windows.Forms.TextBox();
            this.button7 = new System.Windows.Forms.Button();
            this.button6 = new System.Windows.Forms.Button();
            this.statusStrip1 = new System.Windows.Forms.StatusStrip();
            this.serialPort1 = new System.IO.Ports.SerialPort(this.components);
            this.groupBox1.SuspendLayout();
            this.groupBox2.SuspendLayout();
            this.groupBox3.SuspendLayout();
            this.groupBox4.SuspendLayout();
            this.SuspendLayout();
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.button3);
            this.groupBox1.Controls.Add(this.textBox2);
            this.groupBox1.Controls.Add(this.label7);
            this.groupBox1.Controls.Add(this.label6);
            this.groupBox1.Controls.Add(this.radioButton2);
            this.groupBox1.Controls.Add(this.radioButton1);
            this.groupBox1.Controls.Add(this.button2);
            this.groupBox1.Controls.Add(this.comboBox5);
            this.groupBox1.Controls.Add(this.comboBox4);
            this.groupBox1.Controls.Add(this.label5);
            this.groupBox1.Controls.Add(this.label4);
            this.groupBox1.Controls.Add(this.comboBox3);
            this.groupBox1.Controls.Add(this.comboBox2);
            this.groupBox1.Controls.Add(this.label3);
            this.groupBox1.Controls.Add(this.label2);
            this.groupBox1.Controls.Add(this.comboBox1);
            this.groupBox1.Controls.Add(this.label1);
            this.groupBox1.Location = new System.Drawing.Point(44, 32);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(538, 135);
            this.groupBox1.TabIndex = 0;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "串口设置";
            // 
            // button3
            // 
            this.button3.Location = new System.Drawing.Point(442, 49);
            this.button3.Name = "button3";
            this.button3.Size = new System.Drawing.Size(75, 23);
            this.button3.TabIndex = 17;
            this.button3.Text = "关闭串口";
            this.button3.UseVisualStyleBackColor = true;
            this.button3.Click += new System.EventHandler(this.button3_Click);
            // 
            // textBox2
            // 
            this.textBox2.Location = new System.Drawing.Point(388, 85);
            this.textBox2.Name = "textBox2";
            this.textBox2.Size = new System.Drawing.Size(63, 21);
            this.textBox2.TabIndex = 16;
            this.textBox2.Text = "1000";
            // 
            // label7
            // 
            this.label7.AutoSize = true;
            this.label7.Location = new System.Drawing.Point(457, 88);
            this.label7.Name = "label7";
            this.label7.Size = new System.Drawing.Size(17, 12);
            this.label7.TabIndex = 15;
            this.label7.Text = "ms";
            // 
            // label6
            // 
            this.label6.AutoSize = true;
            this.label6.Location = new System.Drawing.Point(353, 88);
            this.label6.Name = "label6";
            this.label6.Size = new System.Drawing.Size(29, 12);
            this.label6.TabIndex = 14;
            this.label6.Text = "间隔";
            // 
            // radioButton2
            // 
            this.radioButton2.AutoSize = true;
            this.radioButton2.Location = new System.Drawing.Point(223, 85);
            this.radioButton2.Name = "radioButton2";
            this.radioButton2.Size = new System.Drawing.Size(65, 16);
            this.radioButton2.TabIndex = 13;
            this.radioButton2.TabStop = true;
            this.radioButton2.Text = "hex显示";
            this.radioButton2.UseVisualStyleBackColor = true;
            // 
            // radioButton1
            // 
            this.radioButton1.AutoSize = true;
            this.radioButton1.Location = new System.Drawing.Point(146, 85);
            this.radioButton1.Name = "radioButton1";
            this.radioButton1.Size = new System.Drawing.Size(71, 16);
            this.radioButton1.TabIndex = 12;
            this.radioButton1.TabStop = true;
            this.radioButton1.Text = "字符显示";
            this.radioButton1.UseVisualStyleBackColor = true;
            // 
            // button2
            // 
            this.button2.Location = new System.Drawing.Point(352, 49);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(75, 23);
            this.button2.TabIndex = 11;
            this.button2.Text = "打开串口";
            this.button2.UseVisualStyleBackColor = true;
            this.button2.Click += new System.EventHandler(this.button2_Click);
            // 
            // comboBox5
            // 
            this.comboBox5.FormattingEnabled = true;
            this.comboBox5.Items.AddRange(new object[] {
            "8",
            "7",
            "5",
            "6"});
            this.comboBox5.Location = new System.Drawing.Point(205, 51);
            this.comboBox5.Name = "comboBox5";
            this.comboBox5.Size = new System.Drawing.Size(56, 20);
            this.comboBox5.TabIndex = 9;
            // 
            // comboBox4
            // 
            this.comboBox4.FormattingEnabled = true;
            this.comboBox4.Items.AddRange(new object[] {
            "无校验",
            "奇校验",
            "偶校验"});
            this.comboBox4.Location = new System.Drawing.Point(207, 23);
            this.comboBox4.Name = "comboBox4";
            this.comboBox4.Size = new System.Drawing.Size(54, 20);
            this.comboBox4.TabIndex = 8;
            // 
            // label5
            // 
            this.label5.AutoSize = true;
            this.label5.Location = new System.Drawing.Point(146, 54);
            this.label5.Name = "label5";
            this.label5.Size = new System.Drawing.Size(53, 12);
            this.label5.TabIndex = 7;
            this.label5.Text = "数据位:";
            // 
            // label4
            // 
            this.label4.AutoSize = true;
            this.label4.Location = new System.Drawing.Point(146, 26);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(65, 12);
            this.label4.TabIndex = 6;
            this.label4.Text = "奇偶校验:";
            // 
            // comboBox3
            // 
            this.comboBox3.FormattingEnabled = true;
            this.comboBox3.Items.AddRange(new object[] {
            "1",
            "1.5",
            "2"});
            this.comboBox3.Location = new System.Drawing.Point(66, 82);
            this.comboBox3.Name = "comboBox3";
            this.comboBox3.Size = new System.Drawing.Size(74, 20);
            this.comboBox3.TabIndex = 5;
            // 
            // comboBox2
            // 
            this.comboBox2.FormattingEnabled = true;
            this.comboBox2.Items.AddRange(new object[] {
            "9600",
            "4800"});
            this.comboBox2.Location = new System.Drawing.Point(65, 51);
            this.comboBox2.Name = "comboBox2";
            this.comboBox2.Size = new System.Drawing.Size(74, 20);
            this.comboBox2.TabIndex = 4;
            // 
            // label3
            // 
            this.label3.AutoSize = true;
            this.label3.Location = new System.Drawing.Point(7, 85);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(53, 12);
            this.label3.TabIndex = 3;
            this.label3.Text = "停止位:";
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(6, 54);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(53, 12);
            this.label2.TabIndex = 2;
            this.label2.Text = "波特率:";
            // 
            // comboBox1
            // 
            this.comboBox1.FormattingEnabled = true;
            this.comboBox1.Location = new System.Drawing.Point(66, 23);
            this.comboBox1.Name = "comboBox1";
            this.comboBox1.Size = new System.Drawing.Size(74, 20);
            this.comboBox1.TabIndex = 1;
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(7, 26);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(53, 12);
            this.label1.TabIndex = 0;
            this.label1.Text = "串口号:";
            // 
            // groupBox2
            // 
            this.groupBox2.Controls.Add(this.textBox1);
            this.groupBox2.Location = new System.Drawing.Point(44, 181);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(544, 136);
            this.groupBox2.TabIndex = 1;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "数据接收";
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(6, 11);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.textBox1.Size = new System.Drawing.Size(532, 119);
            this.textBox1.TabIndex = 0;
            // 
            // groupBox3
            // 
            this.groupBox3.Controls.Add(this.textBox4);
            this.groupBox3.Controls.Add(this.button5);
            this.groupBox3.Controls.Add(this.button4);
            this.groupBox3.Location = new System.Drawing.Point(44, 337);
            this.groupBox3.Name = "groupBox3";
            this.groupBox3.Size = new System.Drawing.Size(538, 68);
            this.groupBox3.TabIndex = 2;
            this.groupBox3.TabStop = false;
            this.groupBox3.Text = "数据发送";
            // 
            // textBox4
            // 
            this.textBox4.Location = new System.Drawing.Point(6, 11);
            this.textBox4.Multiline = true;
            this.textBox4.Name = "textBox4";
            this.textBox4.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.textBox4.Size = new System.Drawing.Size(445, 51);
            this.textBox4.TabIndex = 2;
            // 
            // button5
            // 
            this.button5.Location = new System.Drawing.Point(457, 39);
            this.button5.Name = "button5";
            this.button5.Size = new System.Drawing.Size(75, 23);
            this.button5.TabIndex = 1;
            this.button5.Text = "发送数据";
            this.button5.UseVisualStyleBackColor = true;
            this.button5.Click += new System.EventHandler(this.button5_Click);
            // 
            // button4
            // 
            this.button4.Location = new System.Drawing.Point(457, 9);
            this.button4.Name = "button4";
            this.button4.Size = new System.Drawing.Size(75, 23);
            this.button4.TabIndex = 0;
            this.button4.Text = "清空数据";
            this.button4.UseVisualStyleBackColor = true;
            this.button4.Click += new System.EventHandler(this.button4_Click);
            // 
            // groupBox4
            // 
            this.groupBox4.Controls.Add(this.label8);
            this.groupBox4.Controls.Add(this.textBox3);
            this.groupBox4.Controls.Add(this.button7);
            this.groupBox4.Controls.Add(this.button6);
            this.groupBox4.Location = new System.Drawing.Point(44, 424);
            this.groupBox4.Name = "groupBox4";
            this.groupBox4.Size = new System.Drawing.Size(410, 69);
            this.groupBox4.TabIndex = 3;
            this.groupBox4.TabStop = false;
            this.groupBox4.Text = "文件操作";
            // 
            // label8
            // 
            this.label8.AutoSize = true;
            this.label8.Location = new System.Drawing.Point(9, 30);
            this.label8.Name = "label8";
            this.label8.Size = new System.Drawing.Size(53, 12);
            this.label8.TabIndex = 3;
            this.label8.Text = "文件路径";
            // 
            // textBox3
            // 
            this.textBox3.Location = new System.Drawing.Point(64, 26);
            this.textBox3.Name = "textBox3";
            this.textBox3.Size = new System.Drawing.Size(244, 21);
            this.textBox3.TabIndex = 2;
            // 
            // button7
            // 
            this.button7.Location = new System.Drawing.Point(319, 40);
            this.button7.Name = "button7";
            this.button7.Size = new System.Drawing.Size(75, 23);
            this.button7.TabIndex = 1;
            this.button7.Text = "保存文件";
            this.button7.UseVisualStyleBackColor = true;
            // 
            // button6
            // 
            this.button6.Location = new System.Drawing.Point(319, 15);
            this.button6.Name = "button6";
            this.button6.Size = new System.Drawing.Size(75, 23);
            this.button6.TabIndex = 0;
            this.button6.Text = "打开文件";
            this.button6.UseVisualStyleBackColor = true;
            // 
            // statusStrip1
            // 
            this.statusStrip1.Location = new System.Drawing.Point(0, 500);
            this.statusStrip1.Name = "statusStrip1";
            this.statusStrip1.Size = new System.Drawing.Size(650, 22);
            this.statusStrip1.TabIndex = 4;
            this.statusStrip1.Text = "statusStrip1";
            // 
            // serialPort1
            // 
            this.serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.serialPort1_DataReceived);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(650, 522);
            this.Controls.Add(this.statusStrip1);
            this.Controls.Add(this.groupBox4);
            this.Controls.Add(this.groupBox3);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.groupBox1);
            this.Name = "Form1";
            this.Text = "串口调试助手";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.groupBox2.ResumeLayout(false);
            this.groupBox2.PerformLayout();
            this.groupBox3.ResumeLayout(false);
            this.groupBox3.PerformLayout();
            this.groupBox4.ResumeLayout(false);
            this.groupBox4.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.Button button3;
        private System.Windows.Forms.TextBox textBox2;
        private System.Windows.Forms.Label label7;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.RadioButton radioButton2;
        private System.Windows.Forms.RadioButton radioButton1;
        private System.Windows.Forms.Button button2;
        private System.Windows.Forms.ComboBox comboBox5;
        private System.Windows.Forms.ComboBox comboBox4;
        private System.Windows.Forms.Label label5;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.ComboBox comboBox3;
        private System.Windows.Forms.ComboBox comboBox2;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.ComboBox comboBox1;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.GroupBox groupBox2;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.GroupBox groupBox3;
        private System.Windows.Forms.Button button5;
        private System.Windows.Forms.Button button4;
        private System.Windows.Forms.GroupBox groupBox4;
        private System.Windows.Forms.Label label8;
        private System.Windows.Forms.TextBox textBox3;
        private System.Windows.Forms.Button button7;
        private System.Windows.Forms.Button button6;
        private System.Windows.Forms.TextBox textBox4;
        private System.Windows.Forms.StatusStrip statusStrip1;
        private System.IO.Ports.SerialPort serialPort1;
    }
}

4.3.2 窗体代码Form1.cs

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

namespace SerialCOMMWindows
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void CheckPort()//检查串口是否可用
        {
            this.comboBox1.Items.Clear();//清除控件中的当前值
            bool havePort = false;
            string[] names = SerialPort.GetPortNames();
            if (names != null)
            {

                for (int i = 0; i < names.Length; i++)
                {
                    bool use = false;
                    try
                    {
                        SerialPort t = new SerialPort(names[i]);
                        t.Open();
                        t.Close();
                        use = true;
                    }
                    catch
                    {
                    }
                    if (use)
                    {
                        this.comboBox1.Items.Add(names[i]);
                        havePort = true;
                    }
                }
            }
            if (havePort)
            {
                this.comboBox1.SelectedIndex = 0;
            }
            else
            {
                MessageBox.Show("无可用串口.", "错误");
            }
        }
        private void SetPort()//设置串口
        {
            try
            {
                serialPort1.PortName = this.comboBox1.Text.Trim();//串口名给了串口类
                serialPort1.BaudRate = Convert.ToInt32(this.comboBox2.Text.Trim());//Trim除去前后空格,讲文本转换为32位字符给予串口类
                if (this.comboBox4.Text.Trim() == "奇校验")
                {
                    serialPort1.Parity = Parity.Odd;//将奇校验位给了serialPort1的协议
                }
                else if (this.comboBox4.Text.Trim() == "偶校验")
                {
                    serialPort1.Parity = Parity.Even;
                }
                else
                {
                    serialPort1.Parity = Parity.None;
                }
                if (this.comboBox3.Text.Trim() == "1.5")
                {
                    serialPort1.StopBits = StopBits.OnePointFive;//设置停止位有几位
                }
                else if (this.comboBox3.Text.Trim() == "2")
                {
                    serialPort1.StopBits = StopBits.Two;
                }
                else
                {
                    serialPort1.StopBits = StopBits.One;
                }
                serialPort1.DataBits = Convert.ToInt16(this.comboBox5.Text.ToString().Trim());//数据位
                serialPort1.Encoding = Encoding.UTF8;//串口通信的编码格式
                serialPort1.Open();
            }
            catch { }

        }
        private string HexToASCII(string str)
        {
            try
            {
                string[] mystr1 = str.Trim().Split(' ');
                byte[] t = new byte[mystr1.Length];
                for (int i = 0; i < t.Length; i++)
                {
                    t[i] = Convert.ToByte(mystr1[i], 16);
                }
                return Encoding.UTF8.GetString(t);

            }
            catch (Exception ex)
            {
                MessageBox.Show("转换失败!" + ex.Message, "错误提示");
                return str;
            }
        }
        private string ASCIIToHex(string my2)
        {
            try
            {
                byte[] a = Encoding.UTF8.GetBytes(my2.Trim());
                string mystr1 = "";
                for (int i = 0; i < a.Length; i++)
                {
                    mystr1 += a[i].ToString("X2") + " ";
                }
                return mystr1;
            }
            catch (Exception ex)
            {
                MessageBox.Show("转换失败!" + ex.Message, "错误提示");
                return my2;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.comboBox1.Items.Clear();
            CheckPort();
            this.comboBox1.SelectedIndex = 0;
            this.comboBox2.SelectedIndex = 0;
            this.comboBox3.SelectedIndex = 0;
            this.comboBox4.SelectedIndex = 0;
            this.comboBox5.SelectedIndex = 0;
            this.statusStrip1.Text = "";
            this.radioButton1.Checked = true;
        }

        private void button5_Click(object sender, EventArgs e)
        {
            try
            {

                Byte[] a = Encoding.UTF8.GetBytes(this.textBox4.Text);
                this.serialPort1.Write(a, 0, a.Length);//写入serialPort1
                this.statusStrip1.Text = "发送成功!";
            }
            catch
            {
                this.statusStrip1.Text = "发送失败";
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            SetPort();
            if (serialPort1.IsOpen)
            {
                this.statusStrip1.Text = "串口" + this.comboBox1.Text + "已打开!";
            }
            else
            {
                try
                {
                    serialPort1.Open();
                    this.statusStrip1.Text = "串口" + this.comboBox1.Text + "打开成功!";
                }
                catch (Exception ex)
                {
                    MessageBox.Show("串口" + this.comboBox1.Text + "打开失败,失败原因:" + ex.Message, "错误提示");
                    this.statusStrip1.Text = "串口" + this.comboBox1.Text + "打开失败,失败原因:" + ex.Message;
                }
            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(500);//等待

            this.Invoke((EventHandler)(delegate //异步委托一个线程
            {
                try
                {
                    Byte[] a = new Byte[serialPort1.BytesToRead];//读出缓冲区串口通信的字节
                    this.serialPort1.Read(a, 0, a.Length);//写入serialPort1
                    string my2 = Encoding.UTF8.GetString(a);
                    string b = "";
                    if (this.radioButton2.Checked)
                    {
                        b = ASCIIToHex(my2);
                        this.textBox1.Text += b + "\r\n";
                        this.textBox1.Focus();//获取焦点
                        this.textBox1.Select(this.textBox1.TextLength, 0);//光标定位到文本最后
                        this.textBox1.ScrollToCaret();//滚动到光标处
                        this.statusStrip1.Text = "正在接收数据!";
                    }
                    else
                    {
                        b = my2;
                        this.textBox1.Text += b + "\r\n";
                        String[] lonandlat = b.Split(',');
                        double temp = Convert.ToDouble(lonandlat[3]);
                        temp = temp / 100.0 - (temp % 100.0) / 100.0 + (temp % 100.0) / 60.0;
                        this.textBox1.Text += "纬度:" + temp;
                        temp = Convert.ToDouble(lonandlat[5]);
                        temp = temp / 100.0 - (temp % 100.0) / 100.0 + (temp % 100.0) / 60.0;
                        this.textBox1.Text += " 经度:" + temp + "\r\n";
                        this.textBox1.Focus();//获取焦点
                        this.textBox1.Select(this.textBox1.TextLength, 0);//光标定位到文本最后
                        this.textBox1.ScrollToCaret();//滚动到光标处
                        this.statusStrip1.Text = "正在接收数据!";
                    }
                }
                catch
                {
                    this.statusStrip1.Text = "接收失败!";
                }
                this.serialPort1.DiscardInBuffer();
            }));
        }

        private void button4_Click(object sender, EventArgs e)
        {
            this.textBox1.Text = "";
            this.textBox4.Text = "";
        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                this.serialPort1.Close(); //关闭串口
                this.statusStrip1.Text = "串口" + this.comboBox1.Text + "关闭成功!";
            }
            catch (Exception ex)
            {
                MessageBox.Show("串口" + this.comboBox1.Text + "关闭失败,错误提示:" + ex.Message, "错误提示");
                this.statusStrip1.Text = "串口" + this.comboBox1.Text + "关闭失败,错误提示:" + ex.Message;
            }
        }

        private void groupBox1_Enter(object sender, EventArgs e)
        {

        }
    }
}

4.3.3 程序主函数代码Program.cs(无需编写,自动生成)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SerialCOMMWindows
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

4.4 运行结果

在这里插入图片描述

        启动程序运行后,在串口调试助手窗体中选择串口号COM3,点击打开串口,会看到数据接收下方文本框中显示接收到的GPS数据,选中hex显示则接收到的数据会显示为十六进制,选中字符显示则显示为正常ASCII字符,点击关闭串口则停止接收数据。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值