使用RXTX实现简单串口通信调试工具

article/2025/10/31 14:03:29

最终效果如下图:
这里写图片描述

1、把rxtxParallel.dll、rxtxSerial.dll拷贝到:C:\WINDOWS\system32下。
2、RXTXcomm.jar 添加到项目类库中。

package serialPort;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.TooManyListenersException;import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;/**串口服务类,提供打开、关闭串口,读取、发送串口数据等服务*/
public class SerialTool {private static SerialTool serialTool = null;static {//在该类被ClassLoader加载时就初始化一个SerialTool对象if (serialTool == null) {serialTool = new SerialTool();}}//私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象private SerialTool() {}	/*** 获取提供服务的SerialTool对象* @return serialTool*/public static SerialTool getSerialTool() {if (serialTool == null) {serialTool = new SerialTool();}return serialTool;}/*** 查找所有可用端口* @return 可用端口名称列表*/public static final List<String> findPort() {//获得当前所有可用串口@SuppressWarnings("unchecked")Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();	List<String> portNameList = new ArrayList<>();//将可用串口名添加到List并返回该Listwhile (portList.hasMoreElements()) {String portName = portList.nextElement().getName();portNameList.add(portName);}return portNameList;}/*** 打开串口* @param portName 端口名称* @param baudrate 波特率* @return 串口对象* @throws UnsupportedCommOperationException* @throws PortInUseException* @throws NoSuchPortException*/public static final SerialPort openPort(String portName, int baudrate) throws UnsupportedCommOperationException, PortInUseException, NoSuchPortException {//通过端口名识别端口CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);//打开端口,并给端口名字和一个timeout(打开操作的超时时间)CommPort commPort = portIdentifier.open(portName, 2000);//判断是不是串口if (commPort instanceof SerialPort) {SerialPort serialPort = (SerialPort) commPort;//设置一下串口的波特率等参数serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);                              return serialPort;}return null;}/*** 关闭串口* @param serialport 待关闭的串口对象*/public static void closePort(SerialPort serialPort) {if (serialPort != null) {serialPort.close();serialPort = null;}}/*** 往串口发送数据* @param serialPort 串口对象* @param order	待发送数据* @throws IOException */public static void sendToPort(SerialPort serialPort, byte[] order) throws IOException  {OutputStream out = null;out = serialPort.getOutputStream();out.write(order);out.flush();out.close();}/*** 从串口读取数据* @param serialPort 当前已建立连接的SerialPort对象* @return 读取到的数据* @throws IOException */public static byte[] readFromPort(SerialPort serialPort) throws IOException {InputStream in = null;byte[] bytes = null;try {in = serialPort.getInputStream();int bufflenth = in.available();	//获取buffer里的数据长度while (bufflenth != 0) {                             bytes = new byte[bufflenth]; //初始化byte数组为buffer中数据的长度in.read(bytes);bufflenth = in.available();} } catch (IOException e) {throw e;} finally {if (in != null) {in.close();in = null;}}return bytes;}/**添加监听器* @param port     串口对象* @param listener 串口监听器* @throws TooManyListenersException */public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListenersException {//给串口添加监听器port.addEventListener(listener);//设置当有数据到达时唤醒监听接收线程port.notifyOnDataAvailable(true);//设置当通信中断时唤醒中断线程port.notifyOnBreakInterrupt(true);}
}
package serialPort;import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TooManyListenersException;import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;/*** 监测数据显示类* @author Zhong**/
public class SerialView extends JFrame {/***/private static final long serialVersionUID = 1L;//设置window的iconToolkit toolKit = getToolkit();Image icon = toolKit.getImage(SerialView.class.getResource("computer.png"));DateTimeFormatter df= DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSS");private JComboBox<String> commChoice;private JComboBox<String> bpsChoice;private JButton openSerialButton;private JButton sendButton;private JTextArea sendArea;private JTextArea receiveArea;private JButton closeSerialButton;private List<String> commList = null;	//保存可用端口号private SerialPort serialPort = null;	//保存串口对象/**类的构造方法* @param client*/public SerialView() {init();TimerTask task = new TimerTask() {  @Override  public void run() {  commList = SerialTool.findPort(); //程序初始化时就扫描一次有效串口//检查是否有可用串口,有则加入选项中if (commList == null || commList.size()<1) {JOptionPane.showMessageDialog(null, "没有搜索到有效串口!", "错误", JOptionPane.INFORMATION_MESSAGE);}else{commChoice.removeAllItems();for (String s : commList) {commChoice.addItem(s);}}}};Timer timer = new Timer();  timer.scheduleAtFixedRate(task, 0, 10000);listen();}/***/private void listen(){//打开串口连接openSerialButton.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {//获取串口名称String commName = (String) commChoice.getSelectedItem();			//获取波特率String bpsStr = (String) bpsChoice.getSelectedItem();//检查串口名称是否获取正确if (commName == null || commName.equals("")) {JOptionPane.showMessageDialog(null, "没有搜索到有效串口!", "错误", JOptionPane.INFORMATION_MESSAGE);			}else {//检查波特率是否获取正确if (bpsStr == null || bpsStr.equals("")) {JOptionPane.showMessageDialog(null, "波特率获取错误!", "错误", JOptionPane.INFORMATION_MESSAGE);}else {//串口名、波特率均获取正确时int bps = Integer.parseInt(bpsStr);try {//获取指定端口名及波特率的串口对象serialPort = SerialTool.openPort(commName, bps);SerialTool.addListener(serialPort, new SerialListener());if(serialPort==null) return;//在该串口对象上添加监听器closeSerialButton.setEnabled(true);sendButton.setEnabled(true);openSerialButton.setEnabled(false);String time=df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));receiveArea.append(time+" ["+serialPort.getName().split("/")[3]+"] : "+" 连接成功..."+"\r\n");receiveArea.setCaretPosition(receiveArea.getText().length());  } catch (UnsupportedCommOperationException | PortInUseException | NoSuchPortException | TooManyListenersException e1) {e1.printStackTrace();}}}}});//发送数据sendButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {if(!sendButton.isEnabled())return;String message= sendArea.getText();//"FE0400030001D5C5"try {SerialTool.sendToPort(serialPort, hex2byte(message));} catch (IOException e1) {e1.printStackTrace();}}});//关闭串口连接closeSerialButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {if(!closeSerialButton.isEnabled())return;SerialTool.closePort(serialPort);String time=df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));receiveArea.append(time+" ["+serialPort.getName().split("/")[3]+"] : "+" 断开连接"+"\r\n");receiveArea.setCaretPosition(receiveArea.getText().length());  openSerialButton.setEnabled(true);closeSerialButton.setEnabled(false);sendButton.setEnabled(false);}});}/*** 主菜单窗口显示;* 添加JLabel、按钮、下拉条及相关事件监听;*/private void init() {this.setBounds(WellcomView.LOC_X, WellcomView.LOC_Y, WellcomView.WIDTH, WellcomView.HEIGHT);this.setTitle("串口调试");this.setIconImage(icon);this.setBackground(Color.gray);this.setLayout(null);Font font =new Font("微软雅黑", Font.BOLD, 16);receiveArea=new JTextArea(18, 30);receiveArea.setEditable(false);JScrollPane receiveScroll = new JScrollPane(receiveArea);receiveScroll.setBorder(new TitledBorder("接收区"));//滚动条自动出现 FE0400030001D5C5receiveScroll.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); receiveScroll.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); receiveScroll.setBounds(52, 20, 680,340);this.add(receiveScroll);JLabel chuankou=new JLabel(" 串口选择: ");chuankou.setFont(font);chuankou.setBounds(50, 380, 100,50);this.add(chuankou);JLabel botelv=new JLabel(" 波 特 率: ");botelv.setFont(font);botelv.setBounds(290, 380, 100,50);this.add(botelv);//添加串口选择选项commChoice = new JComboBox<String>();	//串口选择(下拉框)commChoice.setBounds(145, 390, 100, 30);this.add(commChoice);//添加波特率选项bpsChoice = new JComboBox<String>();	//波特率选择bpsChoice.setBounds(380, 390, 100, 30);bpsChoice.addItem("1500");bpsChoice.addItem("2400");bpsChoice.addItem("4800");bpsChoice.addItem("9600");bpsChoice.addItem("14400");bpsChoice.addItem("19500");bpsChoice.addItem("115500");this.add(bpsChoice);//添加打开串口按钮openSerialButton = new JButton("连接");openSerialButton.setBounds(540, 390, 80, 30);openSerialButton.setFont(font);openSerialButton.setForeground(Color.darkGray);this.add(openSerialButton);//添加关闭串口按钮closeSerialButton = new JButton("关闭");closeSerialButton.setEnabled(false);closeSerialButton.setBounds(650, 390, 80, 30);closeSerialButton.setFont(font);closeSerialButton.setForeground(Color.darkGray);this.add(closeSerialButton);sendArea=new JTextArea(30,20);JScrollPane sendScroll = new JScrollPane(sendArea);sendScroll.setBorder(new TitledBorder("发送区"));//滚动条自动出现sendScroll.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); sendScroll.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); sendScroll.setBounds(52, 450, 500,100);this.add(sendScroll);sendButton = new JButton("发 送");sendButton.setBounds(610, 520, 120, 30);sendButton.setFont(font);sendButton.setForeground(Color.darkGray);sendButton.setEnabled(false);this.add(sendButton);this.setResizable(false);	//窗口大小不可更改this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);}/**字符串转16进制* @param hex* @return*/private byte[] hex2byte(String hex) {String digital = "0123456789ABCDEF";String hex1 = hex.replace(" ", "");char[] hex2char = hex1.toCharArray();byte[] bytes = new byte[hex1.length() / 2];byte temp;for (int p = 0; p < bytes.length; p++) {temp = (byte) (digital.indexOf(hex2char[2 * p]) * 16);temp += digital.indexOf(hex2char[2 * p + 1]);bytes[p] = (byte) (temp & 0xff);}return bytes;}/**字节数组转16进制* @param b* @return*/private String printHexString(byte[] b) {StringBuffer sbf=new StringBuffer();for (int i = 0; i < b.length; i++) { String hex = Integer.toHexString(b[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sbf.append(hex.toUpperCase()+"  ");}return sbf.toString().trim();}/*** 以内部类形式创建一个串口监听类* @author zhong*/class SerialListener implements SerialPortEventListener {/*** 处理监控到的串口事件*/public void serialEvent(SerialPortEvent serialPortEvent) {switch (serialPortEvent.getEventType()) {case SerialPortEvent.BI: // 10 通讯中断JOptionPane.showMessageDialog(null, "与串口设备通讯中断", "错误", JOptionPane.INFORMATION_MESSAGE);break;case SerialPortEvent.OE: // 7 溢位(溢出)错误break;case SerialPortEvent.FE: // 9 帧错误break;case SerialPortEvent.PE: // 8 奇偶校验错误break;case SerialPortEvent.CD: // 6 载波检测break;case SerialPortEvent.CTS: // 3 清除待发送数据break;case SerialPortEvent.DSR: // 4 待发送数据准备好了break;case SerialPortEvent.RI: // 5 振铃指示break;case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 输出缓冲区已清空break;case SerialPortEvent.DATA_AVAILABLE: // 1 串口存在可用数据String time=df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));byte[] data;//FE0400030001D5C5try {data = SerialTool.readFromPort(serialPort);receiveArea.append(time+" ["+serialPort.getName().split("/")[3]+"] : "+ printHexString(data)+"\r\n");receiveArea.setCaretPosition(receiveArea.getText().length());  } catch (IOException e) {e.printStackTrace();}break;default:break;}}}
}
package serialPort;import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;import javax.swing.JFrame;
import javax.swing.JLabel;/*** @author bh* 如果运行过程中抛出 java.lang.UnsatisfiedLinkError 错误,* 请将rxtx解压包中的 rxtxParallel.dll,rxtxSerial.dll 这两个文件复制到 C:\Windows\System32 目录下即可解决该错误。*/
public class WellcomView {/** 程序界面宽度*/public static final int WIDTH = 800;/** 程序界面高度*/public static final int HEIGHT = 620;/** 程序界面出现位置(横坐标) */public static final int LOC_X = 200;/** 程序界面出现位置(纵坐标)*/public static final int LOC_Y = 70;private JFrame jFrame;/**主方法* @param args	//*/public static void main(String[] args) {new WellcomView();}public WellcomView() {init();listen();}/***/private void listen() {//添加键盘监听器jFrame.addKeyListener(new KeyAdapter() {public void keyReleased(KeyEvent e) {int keyCode = e.getKeyCode();if (keyCode == KeyEvent.VK_ENTER) {	//当监听到用户敲击键盘enter键后执行下面的操作jFrame.setVisible(false);	//隐去欢迎界面new SerialView();	//主界面类(显示监控数据主面板)}}});	}/*** 显示主界面*/private void init() {jFrame=new JFrame("串口调试");jFrame.setBounds(LOC_X, LOC_Y, WIDTH, HEIGHT);	//设定程序在桌面出现的位置jFrame.setLayout(null);//设置window的icon(这里我自定义了一下Windows窗口的icon图标,因为实在觉得哪个小咖啡图标不好看 = =)Toolkit toolKit = jFrame.getToolkit();Image icon = toolKit.getImage(WellcomView.class.getResource("computer.png"));jFrame.setIconImage(icon); jFrame.setBackground(Color.white);	//设置背景色JLabel huanyin=new JLabel("欢迎使用串口调试工具");huanyin.setBounds(170, 80,600,50);huanyin.setFont(new Font("微软雅黑", Font.BOLD, 40));jFrame.add(huanyin);JLabel banben=new JLabel("Version:1.0   Powered By:cyq");banben.setBounds(180, 390,500,50);banben.setFont(new Font("微软雅黑", Font.ITALIC, 26));jFrame.add(banben);JLabel enter=new JLabel("————点击Enter键进入主界面————");enter.setBounds(100, 480,600,50);enter.setFont(new Font("微软雅黑", Font.BOLD, 30));jFrame.add(enter);jFrame.setResizable(false);	//窗口大小不可更改jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jFrame.setVisible(true);	//显示窗口}
}

无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里可以跳转到教程。


http://chatgpt.dhexx.cn/article/yF82yxdW.shtml

相关文章

Springboot + rxtx 实现串口读写 案例

经过大量翻阅文章总结出springboot连接串口最可行的方法&#xff01;希望能帮到大家( •̀ ω •́ )✧ 使用Rxtx实现串口通信 1、配置pom.xml <!-- 串口内容读取 --><dependency><groupId>org.bidib.jbidib.org.qbang.rxtx</groupId><artifactId&…

java使用RXTX的详细总结

1 简介 项目要求&#xff1a;读取串口信息&#xff0c;并输出展示相应的图像&#xff0c;本篇文章不深入谈前端的内容着重于后端遇到的问题。2021-01-08更新&#xff0c;发现一个重大的问题&#xff1a;如果有人能解决的话请在评论区回复&#xff1a; 在连上串口后&#xff0c…

JAVA使用RXTXcomm进行串口通信(一)

1.引入RXTXcomm.JAR包 首先下载相应的jar文件 压缩包包括:RXTXcomm.jar(64位环境)、win32com.dll和javax.comm.properties。 下载地址:https://www.aliyundrive.com/s/JSeSQsAyYeZ 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需…

SpringBoot使用RXTX连接串口教程及遇到的坑总结

文章目录 SpringBoot使用RXTX连接串口教程及遇到的坑总结一、所用环境及依赖二、部署流程2.1 下载RXTXComm包2.2 部署RXTXComm包 三、编写串口使用程序3.1 编写RXTXConfig.java3.2 编写实体类SerialPortEntity3.3 编写监听器SerialPortListener3.4 编写工具类SerialPortUtil3.5…

【计算机基础|计算机组成原理】【10】海明校验码

海明校验码 海明校验码思路 偶校验&#xff1a;1010 → 01010&#xff0c;能发现奇数位错误&#xff0c;但无法确定是哪一位出错 → 1个校验位只能携带2种状态信息&#xff1a;对/错 海明码设计思路&#xff1a;将信息位分组进行偶校验 → 多个校验位能携带多种状态信息&#x…

计算机组成原理汉明校验,海明校验码(计算机组成原理11)

海明校验码 视频链接地址&#xff1a; https://www.bilibili.com/video/BV1BE411D7ii?fromsearch&seid6420326887479343502 前言 在本篇中&#xff0c;你将掌握 海明码的基本思想 海明码的求解步骤和全校验码 在计算机内部进行存储、计算的数据都是以二进制形式传送&#…

海明校验码纠错设计原理

本文不阐述海明码计算方式&#xff0c;为了节省您的时间&#xff0c;请先学习海明码/奇偶校验是如何计算的&#xff0c;如果好奇其海明码的纠错设计思路再来看此文章&#xff01; 信息为位数为n&#xff0c;校验位数为k&#xff0c;正确状态占1位&#xff0c;所以总位数&#…

2.21 海明校验码

海明校验码 需要了解海明码的编码规则&#xff0c;要会计算需要多少位校验位。 海明码的编码规则 校验位&#xff1a; 校验位的位置是有规律的。都是位于2n。 比如20(1),21(2),22(4)。。都是校验位。 信息位&#xff1a;不是校验位的其他位置。 举个例子 当信息位有1位&am…

【软考学习7】数据校验——海明校验码、循环校验码、奇偶校验码

一、检错、纠错和码距 1.1 检错 从接收的报文中&#xff0c;检查出错误。 1.2 纠错 从接收的报文中检查出错误&#xff0c;并改正错误。 一般通过加冗余信息&#xff08;增大码距&#xff09;来实现。 1.3 码距 码距是整个编码系统中任意两个码字的最小距离。 也就是说&a…

超详细的海明校验码方法解读

海明校验码原理&#xff1a;在有效的信息为中加入几个校验位形成海明码&#xff0c;使码距[rjazgj1] 比较均匀地拉大&#xff0c;并把海明码的每个二进制位分配到几个奇偶校验组[rjazgj2] 中。当某一位出错后&#xff0c;就会引起有关的几个校验位的值发生变化&#xff0c;这不…

海明校验码原理以及作用机制的介绍

什么是海明校验码&#xff1f; 由Richard Hamming于1950年提出、还被广泛采用的一种很有效的校验方法&#xff0c;是只要增加少数几个校验位&#xff0c;就能检测出二位同时出错、亦能检测出一位出错并能自动恢复该出错位的正确值的有效手段&#xff0c;后者被称为自动纠错。 它…

海明校验码的计算及检验

海明校验码的计算及检验 目录 海明校验码的计算及检验知识背景计算海明校验码步骤一&#xff1a;计算校验码位数步骤二&#xff1a;确定校验组步骤三&#xff1a;计算校验码的值得出海明校验码 利用海明校验码校验数据其他 总结 最近和兄弟探讨一个海明校验码的题目&#xff0c…

海明校验码举例

海明校验码举例&#xff1a; 编制ASCII字符M的海明校验码。 解&#xff1a;M的ASCII码为A6A5A4A3A2A1A01001101 M为7位那么海明码最少需要2i&#xff0c;也就是说需要&#xff0c;才能表示出来&#xff0c;&#xff08;238&#xff09; 用哪些信息位分别被哪些校验位效验如…

计算机底层:海明校验码。

计算机底层&#xff1a;海明校验码。 海明校验码是由奇偶校验码中的偶校验延申出来的&#xff1a; 计算机底层&#xff1a;奇偶校验码_srhqwe的博客-CSDN博客 了解海明校验码之前需要先了解奇偶校验码。 海明校验码设计思路&#xff1a; 需要知道&#xff1a;多个校验位就能携…

海明校验码

1. 海明码的特点&#xff1a; 其中m表示数据位的位数&#xff0c;k表示海明校验码的位数 k位海明校验码一共可以表示种校验信息结果&#xff0c;其中有一种要用来表示没有出错的情况&#xff0c;则其余还剩-1种结果&#xff0c;为了使校验结果可以指出任一位出错的位置&#x…

计算机组成原理学习笔记:海明校验码

概述 海明校验码又可以称为汉明校验码, 这只是一个音译的问题, 作者是 Richard Hamming海明校验码对于信息纠错这个领域的贡献十分巨大&#xff0c;Richard Hamming 获得了1968年的图灵奖内容主要包括&#xff1a;海明校验码的思想、如何构建海明校验码、如何使用海明校验码 …

海明码校验【简单详细】

海明码 1.什么是海明码: 一个名叫Richard Hanming老爷爷在1950年提出的检验纠错方法&#xff0c;它具有一位纠错能力。 2.海明码的计算方法: 设欲检测的二进制代码为n位,K为检测位(提供纠错),总共nk位代码 当中检测位满足的关系: 2 k 2^{k} 2k>(nk1) 此关系也是求不同代码长…

一文看懂海明校验码及其计算方法(详细总结)

网上看了好几篇文章后终于算是捋明白了&#xff0c;但是看到的这些资源要么说得云里雾里&#xff0c;要么干脆说得有问题&#xff08;然后还被点了好多赞。。。&#xff09;&#xff0c;无论如何这些都容易误导小白。作为C站多年老潜水员&#xff0c;我还是把海明校验码的要点总…

ResNets

ResNets 背景&#xff1a; 非常非常深的神经网络是很难训练的&#xff0c;因为存在梯度消失和梯度爆炸问题。 《转载更改》 https://blog.csdn.net/qq_29893385/article/details/81207203 ResNets是由残差块&#xff08;Residual block&#xff09;构建的 首先解释一下什么是…

正确定位混淆后Crash代码行数

Android--定位混淆后Crash代码行数 一、需求背景二、前期准备三、对混淆日志进行还原四、示例 一、需求背景 打包时需要对代码进行混淆&#xff0c;目的是增加安全性&#xff0c;防⽌反编译。但这会导致App崩溃时&#xff0c;抓到的日志堆栈中显示的代码行数对应不上&#xff…