java对接斑马打印机打印标签

news2024/9/27 17:27:17
JAVA对接斑马打印机打印RFID标签和普通标签

1、打印RFID标签

在打印RFID标签时,如果机器在没有校准的情况下进行打印标签,此时如果还需要获取到RFID的epc值,那么打印机返回的EPC值,有可能不是当前标签的epc值。考虑到此种情形,我们采用zpl命令进行控制打印机打印:命令包含写入EPC,同时包含返回EPC值。用写入的epc是否等于返回的epc,加以校验,从而避免这种情况的发生。以下用zt411型号验证过的代码

所需第三方jar:

ZSDK_API.jar  斑马打印机sdk
ts24.lib     字体库

在程序启动时,首先加载字体库:

private byte[] dotFont;
......
/**
	 * 构造方法 加载中文字体支持
	 */
	public ZplPrinter() {
		String currentp = System.getProperty("user.dir");
		String tspath = currentp + File.separator + "lib" + File.separator + "ts24.lib";
		File file = new File(tspath);
		log.info("the path of ts24.lib is == " + tspath);
		FileInputStream fis;
		try {
			fis = new FileInputStream(file);
			dotFont = new byte[fis.available()];
			fis.read(dotFont);
			fis.close();
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
	}

拼接ZPL命令:

private String getRFIDZPL(MaterialInfo m) {

		StringBuilder sb = new StringBuilder("^XA^CW1,E:HEITI.TTF^FS^CI28");// 字体
		String fontsize = "^A1N,30,30";// 字体大小

		int x = 150;
		int y = 70;
		int step = 40;

		// 商品名称
		String str = "名称:" + m.getProductName();
		sb.append(fontsize);
		sb.append("^FO" + x + "," + (y + step) + "^FD" + str + "^FS");

		// 商品编码
		str = "编码:" + m.getProductCode();
		sb.append(fontsize);
		sb.append("^FO" + x + "," + (y + 2 * step) + "^FD" + str + "^FS");

		// 商品规格
		str = "规格:" + m.getSpecifications();
		sb.append(fontsize);
		sb.append("^FO" + x + "," + (y + 3 * step) + "^FD" + str + "^FS");

		// 商品批次
		str = "批次:" + m.getBatchNumber();
		sb.append(fontsize);
		sb.append("^FO" + x + "," + (y + 4 * step) + "^FD" + str + "^FS");

		// 商品效期
		str = "效期:" + m.getExpiredDate();
		sb.append(fontsize);
		sb.append("^FO" + x + "," + (y + 5 * step) + "^FD" + str + "^FS");

		// 商品生产厂家
		str = "供应商:" + m.getSupplier();
		sb.append(fontsize);
		sb.append("^FO" + x + "," + (y + 6 * step) + "^FD" + str + "^FS");

		String writec = "^RS8^RFW,H,1,2,1^FD3400^FS^RFW,H,2,12,1^FD" + m.getRfidCode() + "^FS";
		sb.append(writec);

		// 条形码
		sb.append("^BY3,3,60^FT150,70^BCN,50,Y,N^FD>:").append(m.getBarCode()).append("^FS");

		/// 二维码
		sb.append("^FT520,270^BQN,2,7^FH\\^FDLA,").append(m.getBarCode()).append("^FS");

		sb.append("^RS8,,,1 ^RFR,H,0,8,E^FN1^FS^HV1,,^FS");

		// 打印数量
		sb.append("^PQ1,0,1,Y");

		// 结束标识
		sb.append("^XZ");

		return sb.toString();

连接打印机,发送打印请求:

public void printRFID(String printerip, MaterialInfo m) throws Exception {
		Connection connection = ConnectionBuilder.build("TCP_MULTI:" + printerip + ":9100:9200");
		Integer timeout = 8000;
		Date date = new Date();
		try {
			connection.open();
			if (StringUtils.isBlank(m.getBarCode())) {
				String barcode = customerService.createSPDUniqueCode();// 自动生成spd唯一码
				m.setBarCode(barcode);
			}
			if (StringUtils.isBlank(m.getRfidCode())) {
				m.setRfidCode(com.yinghui.common.utils.uuid.UUID.get24UUID().toUpperCase());
			}
			String sendStr = getRFIDZPL(m);// getPrintData(m);
			if (log.isDebugEnabled()) {
				log.debug("耗材信息:[{}],rfid标签值:[{}],[{}]", JSON.toJSONString(m), m.getRfidCode(), sendStr);
			}
			StringBuilder epcBuilder = new StringBuilder();
			// ifid标签值
			byte[] sendAndWaitForResponse = connection.sendAndWaitForResponse(sendStr.getBytes(), timeout, timeout, "");
			epcBuilder = new StringBuilder();
			for (byte b : sendAndWaitForResponse) {
				char c = (char) b;
				String str = String.valueOf(c);
				epcBuilder.append(str);
			}

			String epc = epcBuilder.toString();
			log.info("the value of epc from printer is : " + epc + ", " + m.getRfidCode());
			if (!m.getRfidCode().equals(epc)) {
				throw new Exception("请重新校准打印机!");
			}


		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
			throw ex;
		} finally {
			try {
				connection.close();
			} catch (Exception ex) {
				log.error(ex.getMessage(), ex);
			}
		}
	}

2、打印普通标签

在打印普通标签时,排版比较复杂,所以我们可以采用先生成图片、然后打印图片的方式进行打印。以下是用zt410验证过的代码

同时,标签上面可能会用到二维码和条形码,需要引入第三方包:

<dependency>
			<groupId>com.google.zxing</groupId>
			<artifactId>core</artifactId>
			<version>3.4.0</version>
		</dependency>
		<dependency>
			<groupId>com.google.zxing</groupId>
			<artifactId>javase</artifactId>
			<version>3.4.0</version>
		</dependency>

生成图片:

public static BufferedImage createImage(MaterialInfo m) throws Exception {

		Font font1 = new Font("黑体", Font.BOLD, 36);// 标题字体
		Font font2 = new Font("宋体", Font.BOLD, 30);// 编号字体

		String productName = StringUtils.nvl(m.getProductName(),"");
		String specifications = StringUtils.nvl(m.getSpecifications(),"");
		String manufactor = StringUtils.nvl(m.getManufacturer(),"");
		String batchNumber = StringUtils.nvl(m.getBatchNumber(),"");
		String edate = StringUtils.nvl(m.getExpiredDate(),"");
		String deptname = StringUtils.nvl(m.getDeptName(),"");
		String barcode = StringUtils.nvl(m.getBarCode(),"");
		String unit = StringUtils.nvl(m.getUnit(),"");
		String beihuo = StringUtils.nvl(m.getOther(),"");

		// 创建图片
		// int width = 480;
		// int height = 300;

		int width = 650;
		int height = 500;
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);// 创建图片画布
		Graphics2D g = (Graphics2D) image.getGraphics();
		// g.setColor(Color.BLACK); // 先用白色填充整张图片,也就是背景
		g.fillRect(0, 0, width, height);// 画出矩形区域,以便于在矩形区域内写入文字
		g.setColor(Color.black);
		g.setFont(font1);
		// g.setPaintMode();
		int x = 20;
		int y = 35;
		int gap = 35;
		
		//顶部1/3
		
		g.drawString("▲" + productName, 5, y);// 商品名称
		g.setFont(font2);
		java.awt.FontMetrics fm = g.getFontMetrics(font2);
		g.drawString("规格:" + specifications, x, y * 1 + fm.getHeight()+10);// 规格
		
		//中间2/3
		g.drawString("厂家:" + manufactor, x, y * 2 + fm.getHeight()+gap*2);// 厂家
		g.drawString("批号:" + batchNumber, x, y * 3 + fm.getHeight()+gap*2);// 批号
		g.drawString("有效期:" + edate,x, y * 4 + fm.getHeight()+gap*2);// 有效期
		g.drawString("高值备货   "+beihuo, x, y * 5 + fm.getHeight()+gap*2);// 高值备货
		g.drawString(barcode, x, y * 6 + fm.getHeight()+gap*2);// spd唯一码

		// 二维码
		BufferedImage qrImage = getQrCodeImage(barcode,200,200);//MatrixToImageWriter.toBufferedImage(bitMatrix);
		g.drawImage(qrImage, 480, 80, qrImage.getWidth(), qrImage.getHeight(), null);

		
		//底部3/3
		g.setFont(font1);
		g.drawString("★高值寄售", x, y * 7 + fm.getHeight()+gap*3+10);// 高值寄售
		g.setFont(font2);
		g.drawString(deptname, 400, y * 7 + fm.getHeight()+gap*3+10);// 科室
		//条形码
		BufferedImage barcodeImage = getBarCodeImage(barcode, 380, 60);
		g.drawImage(barcodeImage, 350, 400, barcodeImage.getWidth(), barcodeImage.getHeight(), null);
		
		g.drawString(beihuo, x, y * 8 + fm.getHeight()+gap*3+10);
		g.drawString(barcode, x, y * 9 + fm.getHeight()+gap*3+10);
		String other = unit+"/"+productName+"/"+specifications;
		g.drawString(other, x, y * 10 + fm.getHeight()+gap*3+10);

		// 底下
		g.setColor(Color.black);// 再换成黑色,以便于写入文字
		// g.setFont(font1);// 设置画笔字体
		// g.drawString(title, 2, 50);
		g.setFont(font2);

		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setPaintMode();
		//int w = fm.stringWidth(title);
		// g.drawString(title, (width - w) / 2, (codeImg.getHeight() + heightDiff));
		g.dispose();

		return image;
	}
//生成条形码
private static BufferedImage getBarCodeImage(String vaNumber, int width, int height) {
		try {
			Code128Writer writer = new Code128Writer();
			// 编码内容, 编码类型, 宽度, 高度, 设置参数
			BitMatrix bitMatrix = writer.encode(vaNumber, BarcodeFormat.CODE_128, width, height, new HashMap());
			return MatrixToImageWriter.toBufferedImage(bitMatrix);
		} catch (WriterException e) {
			log.error(e.getMessage(), e);
		}
		return null;

	}
//生成二维码
	private static BufferedImage getQrCodeImage(String barcode, int width, int height) {
		// 二维码
		BitMatrix bitMatrix = null;
		Map hints = new HashMap();
		try {
			bitMatrix = new QRCodeWriter().encode(barcode, BarcodeFormat.QR_CODE, width, height, hints);
		} catch (WriterException e) {
			log.error(e.getMessage(),e);
		}
		// 将生成码位图转换成BufferedImage
		BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
		return qrImage;

	}

形如:
在这里插入图片描述

将生成的图片信息,转换成zpl命令:

package com.yinghui.tag.utils;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

/**
 * 实现思路: 1、获取图片的二值化字节数组 这一步是关键 2、将字节数组转为十六进制 3、压缩十六进制字符串
 * 结尾为1、0或者与上一行相同的;相同的连续字符压缩 4、拼凑ZPL编码,宽度需要扩大,因为需要时8个点(1字节)的整数倍
 */
public class Image2Zpl {

	public static int imgLength = 0;
	static Pattern ZEROS = Pattern.compile("0+$"), ONES = Pattern.compile("1+$"),
			MULTI_W = Pattern.compile("([0-9A-Z])\\1{2,}");

	public static void main(String[] args) throws IOException {
		System.out.println(image2Zpl(ImageIO.read(new File("d://label1.png"))));
	}

	/**
	 * 第一种:只把二维码图片转换成相对应的zpl指令
	 * 
	 * @param image
	 * @return
	 */
	public static String image2Zpl(BufferedImage image) {
		// 获取图片的字节数组
		DataBufferByte data = (DataBufferByte) getBinaryGrayImage(image).getRaster().getDataBuffer();
		byte[] imgData = data.getData();

		System.out.println("image.getWidth(): " + image.getWidth());
		int newW = (image.getWidth() + 7) / 8;// 实际每行字节大小,8个点,每个点1位,共8位
		String[] strs = byte2HexStr(imgData, newW);
		int bytes = imgData.length;
		imgLength = bytes;
		// return String.format("^XA~DG%d,%d,%d,%s^FO50,50^XG%d,1,1^FS^XZ", bytes,
		// bytes, newW, compress(strs),bytes);
		return String.format("~DG%d,%d,%d,%s", bytes, bytes, newW, compress(strs));
	}

	/**
	 * 把整个标签图片转换成完成的zpl指令
	 * 
	 * @param image
	 * @return
	 */
	public static String image2Zpl2(BufferedImage image) {
		// 获取图片的字节数组
		DataBufferByte data = (DataBufferByte) getBinaryGrayImage(image).getRaster().getDataBuffer();
		byte[] imgData = data.getData();

		System.out.println("image.getWidth(): " + image.getWidth());
		int newW = (image.getWidth() + 7) / 8;// 实际每行字节大小,8个点,每个点1位,共8位
		String[] strs = byte2HexStr(imgData, newW);
		int bytes = imgData.length;
		imgLength = bytes;
		return String.format("^XA~DG%d,%d,%d,%s^FO50,50^XG%d,1,1^FS^XZ", bytes, bytes, newW, compress(strs), bytes);
		// return String.format("~DG%d,%d,%d,%s", bytes, bytes, newW, compress(strs));
	}

	/**
	 * 获取二值化图,并取反
	 * 
	 * @param srcImage
	 * @return
	 */
	private static BufferedImage getBinaryGrayImage(BufferedImage srcImage) {
		BufferedImage dstImage = new BufferedImage(srcImage.getWidth(), srcImage.getHeight(),
				BufferedImage.TYPE_BYTE_BINARY);
		dstImage.getGraphics().drawImage(srcImage, 0, 0, null);
		for (int y = 0; y < dstImage.getHeight(); y++) {
			for (int x = 0; x < dstImage.getWidth(); x++) {
				Color color = new Color(dstImage.getRGB(x, y));
				// 获取该点的像素的RGB的颜色
				Color newColor = new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue());
				dstImage.setRGB(x, y, newColor.getRGB());
			}
		}
		return dstImage;
	}

	/**
	 * 压缩图片数据
	 * 
	 * @param data
	 * @return
	 */
	private static String compress(String[] data) {
		StringBuffer sb = new StringBuffer();
		String pre = null;
		for (String d : data) {
			String a = d;
			Matcher m = ZEROS.matcher(a);
			if (m.find()) {
				a = m.replaceFirst(",");
			}

			m = ONES.matcher(a);
			if (m.find()) {
				a = m.replaceFirst("!");
			}

			a = minimizeSameWord(a);

			if (pre != null && a.equals(pre)) {
				a = ":";
			} else {
				pre = a;
			}
			sb.append(a);
			sb.append("\n");
		}
		return sb.toString();
	}

	/**
	 * 十六进制串中相同字母压缩
	 * 
	 * @param str
	 * @return
	 */
	private static String minimizeSameWord(String str) {
		Matcher matcher = MULTI_W.matcher(str);
		while (matcher.find()) {
			String group = matcher.group();
			int len = group.length();
			String c = "";
			if (len > 20) {
				c = Character.toString((char) ('f' + len / 20));
			}
			if (len % 20 > 0) {
				c = c + Character.toString((char) ('F' + len % 20));
			}

			str = str.replaceFirst(group, c + group.charAt(0));
		}
		return str;
	}

	/**
	 * 字节数组转为十六进制
	 * 
	 * @param b
	 * @param rowSize
	 * @return
	 */
	private static String[] byte2HexStr(byte[] b, int rowSize) {
		int len = b.length / rowSize;
		String[] arr = new String[len];
		for (int n = 0; n < len; n++) {
			StringBuffer hs = new StringBuffer();
			for (int j = 0; j < rowSize; j++) {
				String stmp = Integer.toHexString(b[n * rowSize + j] & 0XFF);
				if (stmp.length() == 1)
					hs.append("0");
				hs.append(stmp);
			}
			arr[n] = hs.toString().toUpperCase();
		}
		return arr;
	}
}


调用打印机打印:

public void printCommon(String printerip, MaterialInfo m) throws Exception {
		Date date = new Date();
		Socket socket = null;
		OutputStream out = null;
		try {
			socket = new Socket(printerip, 9100);
			
			BufferedImage image = null;
			try {
				image = ImageProducerUtil.createImage(m);
			} catch (Exception ex) {
				log.error(ex.getMessage(), ex);
				throw new Exception(ex.getMessage());
			}

			String codeBegin = Image2Zpl.image2Zpl2(image);
			String content = codeBegin + "^FO50,70^XG" + Image2Zpl.imgLength + ",1,1^FS\n";

			out = socket.getOutputStream();
			// 发送ZPL指令到打印机
			out.write(content.getBytes("UTF-8")); // 使用UTF-8编码
			out.flush();


		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
			throw ex;
		} finally {
			try {
				out.close();
			} catch (Exception ex) {
				log.error(ex.getMessage(), ex);
			}
			try {
				socket.close();
			} catch (Exception ex) {
				log.error(ex.getMessage(), ex);
			}
		}
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2104431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

技能 | next.js服务端渲染技术

哈喽小伙伴们大家好,我是程序媛小李,今天为大家分享一项前端开发中比较主流的服务端渲染技术:next.js 首先,next.js是什么? 通俗来讲,它就是一个React框架, 它能干啥?它能实现服务端渲染. 什么是服务端渲染? 一句话它就是在服务端生成整个页面的内容,用户在客户端只需要…

VS-E5PH3006L-N3 600V 30A 高效低损耗整流器 二极管 电动 / 混动汽车电池充电的可靠之选

VS-E5PH3006L-N3参数特性&#xff1a; 反向电压&#xff08;VR&#xff09;&#xff1a;600V&#xff0c;这表示该整流器在电路中能承受的最大反向电压为 600 伏特&#xff0c;超过此电压可能会导致器件损坏。平均整流电流&#xff08;IF (AV)&#xff09;&#xff1a;30A&…

测试流程及注意事项,包括jemter和postman

一、接口测试需要考虑的地方有哪些&#xff1f; 1、考虑输入参数和输出参数的合法性&#xff0c;参数必填&#xff0c;默认值&#xff0c;参数长度和格式校验&#xff0c;边界等&#xff0c;图片长传考虑图片大小和格式。查询考虑数据排序&#xff0c;分页考虑分页显示等。 2…

linux 下一跳缓存,early demux(‌早期解复用)‌介绍

3.6版本以后的下一跳缓存 3.6版本移除了FIB查找前的路由缓存。这意味着每一个接收发送的skb现在都必须要进行FIB查找了。这样的好处是现在查找路由的代价变得稳定(consistent)了。3.6版本实际上是将FIB查找缓存到了下一跳(fib_nh)结构上&#xff0c;也就是下一跳缓存下一跳缓存…

【算法】蒙特卡洛模拟

一、引言 蒙特卡洛模拟算法是一种基于概率和统计理论的数值计算方法&#xff0c;通过随机抽样来近似复杂系统的概率问题。它以摩纳哥著名的赌场蒙特卡洛命名&#xff0c;象征着其基于随机性的特点。 二、算法原理 蒙特卡洛模拟算法的核心思想是利用随机抽样来估计一个函数的期望…

【SQL】删除表中重复数据的方法

很久之前我写入一张sql的数据表&#xff0c;它里面有很多重复的内容。然后我想只保留一条原始数据&#xff1a; 例如上面的时间&#xff0c;出现了很多重复值。 我最初用的是这种方法&#xff1a; SELECT * FROM table_name WHERE primary_key IN (SELECT max(primary_key)F…

2.4 SQL注入之高权限注入下

SQL注入之高权限注入 1.注入流程与上节实例相同 查询所有数据库名称 http://localhost/sqli-labs-master/Less-2/?id-2%20union%20select%201,group_concat(schema_name),3%20from%20information_schema.schemata查询数据库对应的表名 http://localhost/sqli-labs-master/Le…

JMeter之接口测试

在做接口测试之前&#xff0c;我们起码需要了解&#xff1a; 1、接口涉及的业务 2、接口的基本信息&#xff1a;访问地址、传值方式&#xff08;Post 或 Get&#xff09;、协议类型、域名或IP、端口、参数 3、接口参数是否加密或者有其他处理加工 很多时候&#xff0c;可能…

U8+ 提示子票区间开始输入不合法处理

手工做是否分包流转为是的商业汇票&#xff0c;提示如下&#xff1a; 处理方法&#xff1a; 第一步&#xff1a; 第二步 数据类型为数字&#xff0c;保存即可&#xff0c;填写值为1

STM32H7 串口 空闲中断 硬件FIFO 任意长接收 Hal库 IDLE

STM32H7 串口 空闲中断 硬件FIFO 任意长接收 Hal库 IDLE 由于工作原因好久不接触ST的芯片了&#xff0c;所以断更ST的东西了&#xff0c;不过偶尔玩玩也挺好的。 接着上篇继续说串口的事儿&#xff0c;这次是FIFO&#xff0c;STM32H7的串口都是带硬件FIFO&#xff0c;大小是发…

java重点学习-redis

一.redis 穿透无中生有key&#xff0c;布隆过滤nul隔离 锁与非期解难题。缓存击穿过期key&#xff0c; 雪崩大量过期key&#xff0c;过期时间要随机。 面试必考三兄弟&#xff0c;可用限流来保底。 1.1 Redis的使用场景 根据自己简历上的业务进行回答 缓存穿透、击穿、雪崩、双…

人工智能再次进化 善用AI提升营运效率

人工智能无疑为我们的生活带来不少便利&#xff0c;也为商界和社会发展作出了重大贡献。事实上&#xff0c;它的起源最早可以追溯到70年前&#xff0c;只可惜过往的 AI 技术尚未如现时般成熟&#xff0c;可以做到的事也远比现在少&#xff1b;直至近期的 AI 技术取得了重大突破…

Redis缓存预热方案详解:提升应用性能与用户体验

文章目录 引言1. 为什么需要缓存预热&#xff1f;2. 缓存预热的基本原理2.1 数据选择2.2 加载策略 3. Redis缓存预热方案设计3.1 方案概述3.2 数据选择3.3 加载策略3.4 实现方式 4. 测试与监控4.1 单元测试4.2 监控 5. 总结 引言 在现代Web应用中&#xff0c;缓存技术已经成为…

【并行计算】CUDA基础

cuda程序的后缀&#xff1a;.cu 编译&#xff1a;nvcc hello_world.cu 执行&#xff1a;./hello_world.cu 使用语言还是C。 1. 核函数 __global__ void add(int *a, int *b, int *c) {*c *a *b; }核函数只能访问GPU的内存。也就是显存。CPU的存储它是碰不到的。 并且核…

【技术解析】工厂内部导航系统:高精度定位与智能路径规划的技术实现

一、工厂内部导航系统概述 工厂内部导航系统集成了最新的GPS室内定位技术、蓝牙定位技术&#xff0c;实现了对工厂内部环境的无缝覆盖与高精度定位。无论是繁忙的生产线、错综复杂的仓库还是广阔的厂区&#xff0c;都能轻松应对。 二、工厂内部导航系统核心功能 实时定位&…

PromptReps: 解锁LLM的检索力量

论文&#xff1a;https://arxiv.org/pdf/2404.18424代码&#xff1a;https://github.com/ielab/PromptReps机构&#xff1a;CSIRO、昆士兰大学、滑铁卢大学领域&#xff1a;retrieval、embedding model发表&#xff1a;arXiv 当前大型语言模型用于zero-shot文档排序的方法主要有…

台球助教系统开发概述:技术架构与功能实现

在现代体育训练领域&#xff0c;技术的融合正不断推动运动教学方式的革新。台球&#xff0c;作为一项集策略、技巧与心理素质于一体的运动&#xff0c;其教学过程的优化显得尤为重要。因此&#xff0c;开发一套高效、智能的台球助教系统&#xff0c;旨在通过技术手段提升学员的…

【微处理器系统原理与应用设计第五讲】再探Cortex-M4处理器结构、总线、异常与中断、SysTick

一、处理器结构 如下图所示&#xff0c;主要包括处理器内核、嵌套向量中断控制器&#xff08;NVIC&#xff09;、系统节拍定时器&#xff08;SysTick&#xff09;以及可选的浮点单元&#xff0c;还有一些内部总线系统、可选的存储器保护单元&#xff08;MPU&#xff09;以及支…

【AI】前向和反向传播的关系

这个例子来自ChatGPT&#xff0c;很有趣的解释了一个模型在trian的过程中前向传播和反向传播的过程。 其中Sigmoid的导数是 自身乘以1-自身的结果。 这也是上述式子中为什么有0.622*&#xff08;1-0.622&#xff09;。

Android Telephony总结

1、Telephony 业务介绍 Android telephony涉及较多模块 1.1、STK业务介绍 1.1.1、STK域选 1.1.2、是否支持STK Telephon STK-CSDN博客 1.1.3、STK应用的安装卸载 1.2、SS补充业务 1.3、通话业务 1.3.1、紧急号码 ECC 号码总结_ecc号码-CSDN博客 1.4、SMS 1.4.1 短信发送方式…