GPS串口通信学习实践 2021.5.10

  • 1、串口通信简介
    • 1.1 波特率
    • 1.2 数据位
    • 1.3 停止位
    • 1.4 奇偶校验位
  • 2、GPS模块串口通信配置
    • 2.1 驱动安装
    • 2.2 插入GPS模块
    • 2.3 GPS模块串口通信数据简介
  • 3、Java实现GPS模块串口通信
    • 3.1 所需环境(Eclipse+Java)
    • 3.2 新建Java工程COMM
    • 3.3 各个包下的java类代码
      • 3.3.1 SerialPortUtils.java
      • 3.3.2 CostomException.java
      • 3.3.3 ParamConfig.java
      • 3.3.4 GPSRMCMessage.java
      • 3.3.5 Operate.java(主函数所在类)
      • 3.3.6 hellodouble.java
    • 3.4 添加串口通信依赖包
    • 3.5 运行结果
  • 4、C#实现GPS模块串口通信(使用SerialPort)
    • 4.1 所需环境(VS 2015 +C#)
    • 4.2 新建C#Windows窗体项目SerailCOMMWindows
    • 4.3 C#项目代码
      • 4.3.1 窗体设计器代码Form1.Designer.cs(对照即可)
      • 4.3.2 窗体代码Form1.cs
      • 4.3.3 程序主函数代码Program.cs(无需编写,自动生成)
    • 4.4 运行结果

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中的方法 读取从串口中接收的数据*/@Overridepublic 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; // 速度,节,Knotsprivate 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*50public 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();}#endregionprivate 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);//写入serialPort1this.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);//写入serialPort1string 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字符,点击关闭串口则停止接收数据。



串口通信学习(GPS模块)2021.5.10相关推荐

  1. 32、树莓派的简单测试串口通信和超声波模块测距

    基本思想:随手记录一下众灵科技树莓派的测试串口通信和超声波模块,其镜像还是很nice,基本的库都给你安装了,比较大 链接:https://pan.baidu.com/s/11tMdoRh3bHmcYz ...

  2. STM32串口通信学习总结

                                                                             STM32串口通信学习总结 1.概述 1.1学习目的 ...

  3. wemos学习之串口通信和ESP8266wifi模块的调用

    1.ESP8266的应用模式:ESP266支撑单AP模式.单STA模式和混合模式.简单的来说就是: AP:可以将ESP8266作为热点,可以让其他的设备连接上它: STA:可以连接上当前环境下的WIF ...

  4. Android应用开发转车载工程师——串口通信学习

    串口简介 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口.串行接口(Serial Interface)是指数据一位一位地顺序传送.其特点是通信线路简 ...

  5. C#串口通信学习笔记

    因为参加一个小项目,需要对继电器进行串口控制,所以这两天学习了基本的串口编程.同事那边有JAVA的串口通信包,不过是从网上下载的,比较零乱,难以准确掌握串口通信的流程和内含.因此,个人通过学习网上大牛 ...

  6. 蓝桥杯单片机串口通信学习提升笔记

    今日得以继续蓝桥杯国赛备赛之旅: 有道是 "不知何事萦怀抱,醒也无聊,醉也无聊,梦也何曾到谢桥." 那我们该如何 让这位诗人纳兰 "再听乐府曲 ,畅解相思苦"呢 ...

  7. 第三篇 树莓派的串口通信和语音识别模块

    目录 一.串口(UART) 二. wiringPi提供的串口API 三.语音识别模块 1.阅读模块代码 ①代码阅读工具:Souces Insight4.0安装.激活.汉化等 ②语音识别(口令模式)源码 ...

  8. 基于天问block编译环境下ASRPRO语音芯片程序编写教程(三)串口通信,多线程模块,ADC篇

    本篇教程将基于天问block内的官方范例代码讲解如何编写ASRPRO语音芯片程序以实现串口通信多线程模块编程和ADC数据读入功能. 1.串口通信 ASRPRO语音芯片具有3组可用串口(UART1对应P ...

  9. 【嵌入式】蓝牙串口通信透传模块(HC-08)的使用

    一 使用蓝牙透传模块简介 HC-08 蓝牙串口通信模块是新一代的基于 Bluetooth Specification V4.0 BLE 蓝牙协议的数传模块.无线工作频段为 2.4GHz ISM,调制方 ...

最新文章

  1. 熊猫直播Rancho发布系统构建之路
  2. 大学生创新创业大赛案例_第五届“南博杯”大学生创新创业大赛决赛举行
  3. python3.5安装-Linux:Python3.5安装和配置
  4. 关于Advisor注入
  5. zookeeper-01
  6. 配置JDK时发生'javac'不是内部或外部命令的现象与解决过程
  7. 纪念我曾经的 JAVA 姿势--转
  8. 四则运算栈c语言程序,四则运算   c语言编程
  9. linux的命令窗口,(翻译)Linux命令行(二)
  10. bi导入数据失败 power_主机数据库平台迁移 6 个典型问题
  11. android ant build.xml实例
  12. 数学建模——模糊数学
  13. matlab 正交park变换 功率守恒,克拉克(CLARKE)和帕克(PARK)变换.doc
  14. Quartz定时任务执行原理
  15. 云开发之模糊搜索的三种方式
  16. RegSVR32 找不到指定模块问题解决
  17. python灰色预测_【数学建模】灰色预测及Python实现
  18. win10+VS2012+opencv2.4.11的安装和配置
  19. 工业互联网·能耗监控暖通空调远程监控系统方案
  20. Babylon.js 踩坑之正交摄像机,平行投影的相关设置

热门文章

  1. matlab相干解调,心电信号的调制与解调(AM调制、相干解调)
  2. 真实生活的记录:我三年的外企生涯(1)出处:天涯虚拟社区
  3. Jetson AGX xavier测试六叶树Usb转Can卡通信记录笔记
  4. vm虚拟机安装教程及注意事项
  5. lnmp架构之使用openresty构建memc+srcache
  6. AO采集用友oracle,AO2011系统如何采集用友GRP-R9导出的ASD文件
  7. CSS布局:CSS三大特性、盒子模型
  8. 2021年11月15日到2021年11月21日笔记
  9. 【面试题】面试题Redis
  10. 『XXG探索』canvas 获取图片主体颜色