当前位置: 首页 > news >正文

C#上位机与三菱PLC的通信08---开发自己的通讯库(A-1E版)

1、A-1E报文回顾

 

具体细节请看:

C#上位机与三菱PLC的通信03--MC协议之A-1E报文解析

C#上位机与三菱PLC的通信04--MC协议之A-1E报文测试

2、为何要开发自己的通讯库

前面使用了第3方的通讯库实现了与三菱PLC的通讯,实现了数据的读写,对于通讯库,我们只要引用并调用相关的方法即可实现目的,为什么别人可以封装通讯库dll文件,自己能不能做到?当然可以,但写一个通讯库需要非凡的技术,需要考虑的东西很多,比如扩展性,通用性,等等之类的。通过封装通讯库达到更高的层次,想想,别人使用自己的东西,说明自己牛XXXX啊,大师就是这样锻造出来的,接下来马上安排,鸿鹄之志从小事做起,振兴工业自动化,匹夫有责。

3、空谈误国,实干兴邦

1、创建vs项目

2、添加类库项目

3、创建目录及基础类 

 

     

 

 

  AreaCode.cs代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Mitsubishi.Communication.MC.Mitsubishi.Base
{/// <summary>/// 存储区枚举/// </summary>public enum AreaCode{D = 0xA8,X = 0x9C,Y = 0x9D,M = 0x90,R = 0xAF,S = 0x98,TS = 0xC1,CN = 0xC5}
}

MelsecBase.cs代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace Mitsubishi.Communication.MC.Mitsubishi.Base
{/// <summary>/// mc协议基类/// </summary>public class MelsecBase{/// <summary>/// plc的ip地址/// </summary>public string _ip;/// <summary>/// plc的端口号/// </summary>public int _port;/// <summary>/// socket对象/// </summary>public Socket socket = null;/// <summary>/// 超时事件/// </summary>ManualResetEvent TimeoutObject = new ManualResetEvent(false);/// <summary>/// 连接状态/// </summary>bool connectState = false;/// <summary>/// 构造方法/// </summary>/// <param name="ip"></param>/// <param name="port"></param>public MelsecBase(string ip, short port){_ip = ip;_port = port;// 初始化一个通信对象socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);}/// <summary>/// 连接PLC/// </summary>/// <param name="timeout">超时时间</param>/// <returns></returns>public Result Connect(int timeout = 50){TimeoutObject.Reset();Result result = new Result();try{if (socket == null){socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);}int count = 0;while (count < timeout){if (!(!socket.Connected || (socket.Poll(200, SelectMode.SelectRead) && (socket.Available == 0)))){return result;}try{socket?.Close();socket.Dispose();socket = null;socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//异步连接 socket.BeginConnect(_ip, _port, callback =>{connectState = false;var cbSocket = callback.AsyncState as Socket;if (cbSocket != null){connectState = cbSocket.Connected;if (cbSocket.Connected){cbSocket.EndConnect(callback);}}TimeoutObject.Set();}, socket);TimeoutObject.WaitOne(2000, false);if (!connectState){throw new Exception();}else{break;}}catch (SocketException ex){if (ex.ErrorCode == 10060){throw new Exception(ex.Message);}}catch (Exception ex){throw new Exception(ex.Message);}finally{count++;}}if (socket == null || !socket.Connected || ((socket.Poll(200, SelectMode.SelectRead) && (socket.Available == 0)))){throw new Exception("网络连接失败");}}catch (Exception ex){result.IsSuccessed = false;result.Message = ex.Message;}return result;}/// <summary>/// 构建开始地址/// </summary>/// <param name="areaCode">存储区</param>/// <param name="startAddr">开始地址</param>/// <returns></returns>/// <exception cref="Exception"></exception>public List<byte> StartToBytes(AreaCode areaCode, string startAddr){List<byte> startBytes = new List<byte>();if (areaCode == AreaCode.X || areaCode == AreaCode.Y){string str = startAddr.ToString().PadLeft(8, '0');for (int i = str.Length - 2; i >= 0; i -= 2){string v = str[i].ToString() + str[i + 1].ToString();startBytes.Add(Convert.ToByte(v, 16));}}else{int addr = 0;if (!int.TryParse(startAddr, out addr)){throw new Exception("软元件地址不支持!");}startBytes.Add((byte)(addr % 256));startBytes.Add((byte)(addr / 256 % 256));startBytes.Add((byte)(addr / 256 / 256 % 256));startBytes.Add((byte)(addr / 256 / 256 / 256 % 256));}return startBytes;}/// <summary>/// 发送报文/// </summary>/// <param name="reqBytes">字节集合</param>/// <param name="count">字节长度</param>/// <returns></returns>public virtual List<byte> Send(List<byte> reqBytes, int count){return null;}/// <summary>/// 数据解析/// </summary>/// <typeparam name="T">读取的数据类型</typeparam>/// <param name="datas">数据列表</param>/// <param name="typeLen">类型长度</param>/// <returns></returns>/// <exception cref="Exception"></exception>public List<T> AnalysisDatas<T>(List<byte> datas, int typeLen){List<T> resultDatas = new List<T>();if (typeof(T) == typeof(bool))//bool类型{for (int i = 0; i < datas.Count; i++){// 10 10 10 10 10string binaryStr = Convert.ToString(datas[i], 2).PadLeft(8, '0');dynamic state = binaryStr.Substring(0, 4) == "0001";resultDatas.Add(state);state = binaryStr.Substring(4) == "0001";resultDatas.Add(state);}}else//其他类型:ushort,short,float{for (int i = 0; i < datas.Count;){List<byte> valueByte = new List<byte>();for (int sit = 0; sit < typeLen * 2; sit++){valueByte.Add(datas[i++]);}Type tBitConverter = typeof(BitConverter);MethodInfo method = tBitConverter.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(mi => mi.ReturnType == typeof(T)) as MethodInfo;if (method == null){throw new Exception("未找到匹配的数据类型转换方法");}resultDatas.Add((T)method?.Invoke(tBitConverter, new object[] { valueByte.ToArray(), 0 }));}}return resultDatas;}/// <summary>/// 计算长度/// </summary>/// <typeparam name="T">读取的数据类型</typeparam>/// <returns></returns>public int CalculatLength<T>(){int typeLen = 1;if (!typeof(T).Equals(typeof(bool))){typeLen = Marshal.SizeOf<T>() / 2;// 每一个数据需要多少个寄存器}return typeLen;}/// <summary>/// 获取数据的字节列表/// </summary>/// <typeparam name="T">数据类型</typeparam>/// <param name="values">数据列表</param>/// <returns></returns>public List<byte> GetDataBytes<T>(List<T> values){List<byte> datas = new List<byte>();int count = values.Count;if (typeof(T) == typeof(bool))//bool类型的数据{dynamic value = false;// 添加一个填充数据,保存一个完整字节if (values.Count % 2 > 0){values.Add(value);}for (int i = 0; i < values.Count; i += 2){byte valueByte = 0;if (bool.Parse(values[i].ToString())){valueByte |= 16;}if (bool.Parse(values[i + 1].ToString())){valueByte |= 1;}datas.Add(valueByte);}}else //其他类型:float,short,int16{for (int i = 0; i < values.Count; i++){dynamic value = values[i];datas.AddRange(BitConverter.GetBytes(value)); // MC不需要字节的颠倒}}return datas;}}
}

Result.cs代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Mitsubishi.Communication.MC.Mitsubishi.Base
{/// <summary>/// 结果类/// </summary>/// <typeparam name="T"></typeparam>public class Result<T>{/// <summary>/// 状态/// </summary>public bool IsSuccessed { get; set; }/// <summary>/// 对应的消息/// </summary>public string Message { get; set; }/// <summary>/// 数据列表/// </summary>public List<T> Datas { get; set; }public Result() : this(true, "OK") { }public Result(bool state, string msg) : this(state, msg, new List<T>()) { }public Result(bool state, string msg, List<T> datas){this.IsSuccessed = state; Message = msg; Datas = datas;}}public class Result : Result<bool> { }
}

确保上面的三个类文件编译成功,继续干

4、编写核心的通信类A1E.cs 

  

A1E.cs完整代码: 

using Mitsubishi.Communication.MC.Mitsubishi.Base;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;namespace Mitsubishi.Communication.MC.Mitsubishi
{/// <summary>/// A1E报文通讯库/// </summary>public class A1E : MelsecBase{/// <summary>/// 构造方法/// </summary>/// <param name="ip"></param>/// <param name="port"></param>public A1E(string ip, short port) : base(ip, port){}#region 读取数据/// <summary>/// 读取数据/// </summary>/// <typeparam name="T">读取的数据类型</typeparam>/// <param name="address">开始地址</param>/// <param name="count">读取长度</param>/// <returns></returns>public Result<T> Read<T>(string address, short count){AreaCode areaCode;string start;(areaCode, start) = this.AnalysisAddress(address);return Read<T>(areaCode, start, count);}/// <summary>/// 读取数据/// </summary>/// <typeparam name="T">读取的数据类型</typeparam>/// <param name="areaCode">存储区代码</param>/// <param name="startAddr">开始地址</param>/// <param name="count">读取长度</param>/// <returns></returns>public Result<T> Read<T>(AreaCode areaCode, string startAddr, short count){Result<T> result = new Result<T>();try{var connectState = this.Connect();if (!connectState.IsSuccessed){throw new Exception(connectState.Message);}//读取类型byte readCode = (byte)(typeof(T) == typeof(bool) ? 0x00 : 0x01);//起始地址List<byte> startBytes = this.StartToBytes(areaCode, startAddr);//存储区代码List<byte> areaBytes = this.AreaToBytes(areaCode);//读取长度int typeLen = this.CalculatLength<T>();//组装报文List<byte> command = new List<byte> {readCode,///读取类型0xFF,0x0A,0x00,//0xFF指PLC编号,0x0A,0x00指超时时间,超时时间是以250ms为单位 startBytes[0],startBytes[1],startBytes[2],startBytes[3], // 起始地址,占4个字节areaBytes[0],areaBytes[1], // 存储区,占2个字节(byte)(typeLen*count%256),// 读取长度,低位(byte)(typeLen*count/256%256) // 读取长度,高位};//计算响应报文的长度int respLen = typeLen * 2 * count;if (typeof(T) == typeof(bool)){respLen = (int)Math.Ceiling(typeLen * count * 1.0 / 2);}//发送报文List<byte> respBytes = this.Send(command, respLen);//数据解析result.Datas = this.AnalysisDatas<T>(respBytes, typeLen);}catch (Exception ex){result = new Result<T>(false, ex.Message);}return result;}#endregion #region 写入数据/// <summary>/// 写数据/// </summary>/// <typeparam name="T">写入的数据类型</typeparam>/// <param name="values">数据值列表</param>/// <param name="addr">开始地址</param>/// <returns></returns>public Result Write<T>(List<T> values, string addr){AreaCode areaCode; string start;(areaCode, start) = this.AnalysisAddress(addr);return this.Write<T>(values, areaCode, start);}/// <summary>/// 写数据/// </summary>/// <typeparam name="T">写入的数据类型</typeparam>/// <param name="values">数据值列表</param>/// <param name="areaCode">存储区代码</param>/// <param name="startAddr">开始地址</param>/// <returns></returns>public Result Write<T>(List<T> values, AreaCode areaCode, string startAddr){Result result = new Result();try{var connectState = this.Connect();if (!connectState.IsSuccessed){throw new Exception(connectState.Message);}// 写操作的类型 //0x00 批量位读取 //0x01 批量字读取 //0x02 批量位写入 //0x03 批量字写入 //0x04 随机位写入 //0x05 随机字写入byte writeCode = (byte)(typeof(T) == typeof(bool) ? 0x02 : 0x03);//开始地址List<byte> startBytes = this.StartToBytes(areaCode, startAddr);//存储区代码List<byte> areaBytes = this.AreaToBytes(areaCode);//构建数据的字节列表int count = values.Count;List<byte> datas = this.GetDataBytes<T>(values);//判断写入的长度,如果是float类型则长度要扩大2倍int length = count;//长度等于值的个数 if (typeof(T) == typeof(float)){length = length * 2;}//拼装报文List<byte> command = new List<byte> {writeCode,0xFF, 0x0A, 0x00,//0xFF指PLC编号,0x0A,0x00指超时时间,超时时间是以250ms为单位 startBytes[0], startBytes[1], startBytes[2], startBytes[3], // 起始地址areaBytes[0], areaBytes[1], // 存储区 //写入的长度的低位和高位 (byte)(length % 256),(byte)(length / 256 % 256),};command.AddRange(datas);//写入的具体数据//发送报文socket.Send(command.ToArray());// 判断写入的结果 byte[] respBytes = new byte[2];socket.Receive(respBytes);if (respBytes[0] != (writeCode |= 0x80)){throw new Exception("响应报文结构异常。" + respBytes[0].ToString());}if (respBytes[1] != 0x00){throw new Exception("响应异常。" + respBytes[1].ToString());}}catch (Exception ex){result.IsSuccessed = false;result.Message = ex.Message;}return result;}#endregion#region PLC启停,区别功能码  0x13,0x14public Result Run(){return PlcState(0x13);}public Result Stop(){return PlcState(0x14);}private Result PlcState(byte commandCode){Result result = new Result();try{var connectState = this.Connect();if (!connectState.IsSuccessed){throw new Exception(connectState.Message);}List<byte> commandBytes = new List<byte>{commandCode,0xFF,0x0A,0x00};socket.Send(commandBytes.ToArray());// 先判断响应状态byte[] respBytes = new byte[2];socket.Receive(respBytes);if (respBytes[0] != (commandCode |= 0x80)){throw new Exception("响应报文结构异常。" + respBytes[0].ToString());}if (respBytes[1] != 0x00){throw new Exception("响应异常。" + respBytes[1].ToString());}}catch (Exception ex){result.IsSuccessed = false;result.Message = ex.Message;}return result;}#endregion#region 内部方法/// <summary>/// 构建存储区代码/// </summary>/// <param name="areaCode">存储区代码</param>/// <returns></returns>private List<byte> AreaToBytes(AreaCode areaCode){List<byte> areaBytes = new List<byte>();string areaStr = areaCode.ToString();areaBytes.AddRange(Encoding.ASCII.GetBytes(areaStr));if (areaBytes.Count == 1){areaBytes.Add(0x20);}areaBytes.Reverse(); //字节反转return areaBytes;}/// <summary>/// 发送报文/// </summary>/// <param name="reqBytes">报文字节集合</param>/// <param name="len">报文字节长度</param>/// <returns></returns>/// <exception cref="Exception"></exception>public override List<byte> Send(List<byte> reqBytes, int len){socket.Send(reqBytes.ToArray()); //发送报文// 先判断响应状态byte[] respBytes = new byte[2];socket.Receive(respBytes);if (respBytes[0] != (reqBytes[0] |= 0x80)){throw new Exception("响应报文结构异常。" + respBytes[0].ToString());}if (respBytes[1] != 0x00){throw new Exception("响应异常。" + respBytes[1].ToString());}respBytes = new byte[len];socket.Receive(respBytes, 0, len, SocketFlags.None);return new List<byte>(respBytes);}/// <summary>/// 地址解析,输入的地址:X100    X1A0    M100    D100   TN10/// </summary>/// <param name="address">地址字符串</param>/// <returns>返回元组</returns>public Tuple<AreaCode, string> AnalysisAddress(string address){// 取两个字符string area = address.Substring(0, 2);if (!new string[] { "TN", "TS", "CS", "CN" }.Contains(area)){area = address.Substring(0, 1);}string start = address.Substring(area.Length);// 返回元组(一个对象,该对象包括编号和地址)var obj = new Tuple<AreaCode, string>((AreaCode)Enum.Parse(typeof(AreaCode), area), start);return obj;}#endregion }
}

确保项目编译成功,可以进行下一步

4、测试通讯库

1、添加项目引用    

 2、启动MC服务器 

3、利用通讯库读写数据

 1 读取X区100开始的4个bool数据

 

 2、读取D区100开始的5个float数据

 3、读取M区200开始的2个short数据

4、写入M区200开始的2个short数据 

 

5、写入D区200开始的5个float数据 

 4、完整代码

using Mitsubishi.Communication.MC.Mitsubishi;
using Mitsubishi.Communication.MC.Mitsubishi.Base;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Mitsubishi.Communication.Test
{internal class Program{static void Main(string[] args){MCLibTestA1E(); Console.WriteLine("执行完成!");Console.ReadKey();}/// <summary>/// 测试A-1E通讯库/// </summary>static void MCLibTestA1E(){A1E a1E = new A1E("192.168.1.7", 6000);#region 读数据Console.WriteLine("读取X区100开始的4个bool数据");var result1 = a1E.Read<bool>(AreaCode.X, "100", 4);if (result1.IsSuccessed){result1.Datas.ForEach(d => Console.WriteLine(d));}else{Console.WriteLine(result1.Message);}Console.WriteLine("读取D区200开始的5个float数据");var result2 = a1E.Read<float>(AreaCode.D, "200", 5);if (result2.IsSuccessed){result2.Datas.ForEach(d => Console.WriteLine(d));}else{Console.WriteLine(result2.Message);}Console.WriteLine("读取M区200开始的2个short数据");var result3 = a1E.Read<short>(AreaCode.M, "200", 2);if (result3.IsSuccessed){result3.Datas.ForEach(d => Console.WriteLine(d));}else{Console.WriteLine(result3.Message);}#endregion#region 写数据Console.WriteLine("写入M区200开始的2个short数据");var result4 = a1E.Write<short>(new List<short> { 61, 72 }, "M200");if (result4.IsSuccessed){Console.WriteLine(result4.Message);}Console.WriteLine("写入D区200开始的5个float数据");var result5 = a1E.Write<float>(new List<float> { 3.2f, -2.5f, 0, 35, -98 }, "D200");if (result5.IsSuccessed){Console.WriteLine(result5.Message);}#endregion}}
}

5、小结

原创真的不容易,走过路过不要错过,点赞关注收藏又圈粉,共同致富。

原创真的不容易,走过路过不要错过,点赞关注收藏又圈粉,共同致富。

原创真的不容易,走过路过不要错过,点赞关注收藏又圈粉,共同致富

相关文章:

C#上位机与三菱PLC的通信08---开发自己的通讯库(A-1E版)

1、A-1E报文回顾 具体细节请看&#xff1a; C#上位机与三菱PLC的通信03--MC协议之A-1E报文解析 C#上位机与三菱PLC的通信04--MC协议之A-1E报文测试 2、为何要开发自己的通讯库 前面使用了第3方的通讯库实现了与三菱PLC的通讯&#xff0c;实现了数据的读写&#xff0c;对于通…...

ABAQUS应用04——集中质量的添加方法

文章目录 0. 背景1. 集中质量的编辑2. 约束的设置3. 总结 0. 背景 混塔ABAQUS模型中&#xff0c;机头、法兰等集中质量的设置是模型建立过程中的一部分&#xff0c;需要研究集中质量的添加。 1. 集中质量的编辑 集中质量本身的编辑没什么难度&#xff0c;我已经用Python代码…...

[嵌入式系统-24]:RT-Thread -11- 内核组件编程接口 - 网络组件 - TCP/UDP Socket编程

目录 一、RT-Thread网络组件 1.1 概述 1.2 RT-Thread支持的网络协议栈 1.3 RT-Thread如何选择不同的网络协议栈 二、Socket编程 2.1 概述 2.2 UDP socket编程 2.3 TCP socket编程 2.4 TCP socket收发数据 一、RT-Thread网络组件 1.1 概述 RT-Thread 是一个开源的嵌入…...

【ansible】认识ansible,了解常用的模块

目录 一、ansible是什么&#xff1f; 二、ansible的特点&#xff1f; 三、ansible与其他运维工具的对比 四、ansible的环境部署 第一步&#xff1a;配置主机清单 第二步&#xff1a;完成密钥对免密登录 五、ansible基于命令行完成常用的模块学习 模块1&#xff1a;comma…...

【LeetCode】升级打怪之路 Day 01:二分法

今日题目&#xff1a; 704. 二分查找35. 搜索插入位置34. 在排序数组中查找元素的第一个和最后一个位置 目录 今日总结Problem 1: 二分法LeetCode 704. 二分查找 【easy】LeetCode 35. 搜索插入位置 ⭐⭐⭐⭐⭐LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置 【medi…...

单片机stm32智能鱼缸

随着我国经济的快速发展而给人们带来了富足的生活&#xff0c;也有越来越多的人们开始养鱼&#xff0c;通过养各种鱼类来美化居住环境和缓解压力。但是在鱼类饲养过程中&#xff0c;常常由于鱼类对水质、水位及光照强度有着很高的要求&#xff0c;而人们也由于工作的方面而无法…...

面试经典150题——生命游戏

​"Push yourself, because no one else is going to do it for you." - Unknown 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力求解 之所以先暴力求解&#xff0c;是因为我开始也没什么更好的思路&#xff0c;所以就先写一种解决方案&#xff0c;没准写着写…...

【C++】C++11下线程库

C11下线程库 1. thread类的简单介绍2.线程函数参数3.原子性操作库(atomic)4.mutex的种类5. RAII风格加锁解锁5.1Lock_guard5.2unique_lock 6.condition_variable 1. thread类的简单介绍 在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和平台相关的&#xff0c;比如wi…...

面试经典150题——矩阵置零

​"Dream it. Wish it. Do it." - Unknown 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力求解 思路一很简单&#xff0c;就是尝试遍历矩阵的所有元素&#xff0c;如果发现值等于0&#xff0c;就把当前行与当前列的值分别置为0。同时我们需要注意&#xff0c;…...

多端开发围炉夜话

文章目录 一、多端开发 一、多端开发 uni-app 官网 UNI-APP中的UI框架&#xff1a;介绍常用的UI框架及其特点 uView UIVant WeappColor UIMint UI uniapp嵌入android原生开发的功能 uniapp使用安卓原生sdk uni-app中的uni.requireNativePlugin...

分治算法总结(Java)

目录 分治算法概述 快速排序 练习1&#xff1a;排序数组 练习2&#xff1a;数组中的第K个最大元素 练习3&#xff1a;最小k个数 归并排序 练习4&#xff1a;排序数组 练习5&#xff1a;交易逆序对的总数 练习6&#xff1a;计算右侧小于当前元素的个数 练习7&#xff1…...

【云原生系列之kubernetes】--Ingress使用

service的缺点&#xff1a; 不支持基于URL等机制对HTTP/HTTPS协议进行高级路由、超时、重试、基于流量的灰度等高级流量治理机制难以将多个service流量统一管理 1.1ingress的概念 ingress是k8s中的一个对象&#xff0c;作用是如何将请求转发到service的规则ingress controlle…...

练习:鼠标类设计之2_类和接口

前言 续鼠标类设计之1&#xff0c;前面解决了鼠标信号问题&#xff0c;这里解决显示问题 引入 鼠标伴随操作系统而生&#xff0c;考虑在屏幕上怎样显示 思路 1>鼠标显示是一个动态效果&#xff0c;所以需要一个“动态效果类”对象&#xff0c;添加进鼠标类的属性里。 在面…...

【程序员英语】【美语从头学】初级篇(入门)(笔记)Lesson 15 At the Department Store 在百货商店

《美语从头学初级入门篇》 注意&#xff1a;被 删除线 划掉的不一定不正确&#xff0c;只是不是标准答案。 文章目录 Lesson 15 At the Department Store 在百货商店会话A会话B笔记 Lesson 15 At the Department Store 在百货商店 会话A A: Can you help me, please? B: Sur…...

linux 安装、删除 JTAG驱动

安装 安装驱动需要sudo访问权限&#xff0c;所以得手动安装。 在petalinux安装目录下&#xff1a; 文件的路径。 cd tools/xsct/data/xicom/cable_drivers/lin64/install_script/install_drivers 然后执行文件 install_drivers。 sudo ./install_drivers安装成功。 删除 …...

CSS的伪类选择器:nth-child()

CSS的伪类选择器:nth-child() CSS的伪类选择器 :nth-child() 是一个非常强大的工具&#xff0c;它允许你根据元素在其父元素中的位置&#xff08;序数&#xff09;来选择特定的子元素。这个选择器可以应用于任何元素&#xff0c;并且可以与类型选择器、类选择器或ID选择器结合…...

python celery使用队列

在celery的配置方法中有个参数叫task_routes&#xff0c;是用来设置不同的任务 消费不同的队列&#xff08;也就是路由&#xff09;。 格式如下&#xff1a; { ‘task name’: { ‘queue’: ‘queue name’ }}直接上代码&#xff0c;简单明了&#xff0c;目录格式如下&#x…...

四非保研之旅

大家好&#xff0c;我是工藤学编程&#xff0c;虽有万分感概&#xff0c;但是话不多说&#xff0c;先直接进入正题&#xff0c;抒情环节最后再说&#xff0c;哈哈哈 写在开头 我的分享是来给大家涨信心的&#xff0c;网上的大佬们都太强了&#xff0c;大家拿我涨涨信心&#…...

基于Java+SpringBoot的旅游路线规划系统(源码+论文)

文章目录 目录 文章目录 前言 一、功能设计 二、功能实现 1.1 前端首页模块的实现 1.2 景点新闻 1.3 景点在线预订 1.4 酒店在线预订 1.5 管理员景点管理 1.6 管理员旅游线路管理 1.7 酒店信息管理 三、库表设计 前言 随着我国的经济的不断发展&#xff0c;现在的一些热门的景…...

AI与测试自动化:未来已来

AI与测试自动化注定融合。软件开发的速度和准确性要求已经远远超出了预期。测试自动化通过重复、详细和数据密集型测试来解决这个问题&#xff0c;确保敏捷和持续交付环境中的软件质量。AI的学习、适应和预测能力以完美的效率和准确性增强了测试自动化。复杂的算法现在充当质量…...

深度学习基础之《TensorFlow框架(6)—张量》

一、张量 1、什么是张量 张量Tensor和ndarray是有联系的&#xff0c;当我们print()打印值的时候&#xff0c;它返回的就是ndarray对象 TensorFlow的张量就是一个n维数组&#xff0c;类型为tf.Tensor。Tensor具有以下两个重要的属性&#xff1a; &#xff08;1&#xff09;typ…...

第三百六十六回

文章目录 1. 概念介绍2. 使用方法2.1 List2.2 Map2.3 Set 3. 示例代码4. 内容总结 我们在上一章回中介绍了"convert包"相关的内容&#xff0c;本章回中将介绍collection.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章回中介绍的内容是col…...

Fiddler工具 — 18.Fiddler抓包HTTPS请求(一)

1、Fiddler抓取HTTPS过程 第一步&#xff1a;Fiddler截获客户端发送给服务器的HTTPS请求&#xff0c;Fiddler伪装成客户端向服务器发送请求进行握手 。 第二步&#xff1a;服务器发回相应&#xff0c;Fiddler获取到服务器的CA证书&#xff0c; 用根证书&#xff08;这里的根证…...

多租户数据库的缓冲区共享和预分配方案设计

多租户数据库的缓冲区共享和预分配方案设计 文章目录 多租户数据库的缓冲区共享和预分配方案设计简介初始化输入交互输出输入部分的输出交互部分的输出 评分注意点语言要求需要使用的模块系统框架图方案设计初始化阶段交互阶段 修改进度规划最终代码 简介 云计算技术使企业能够…...

C++:C++入门基础

创作不易&#xff0c;感谢三连 &#xff01;&#xff01; 一、什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要高度的抽象和建模时&#xff0c;C语言则不合适。为了解决软件危机&#xff…...

利用System.Web.HttpRuntime.Cache制作缓存工具类

用到的依赖介绍 当谈到 ASP.NET 中的缓存管理时&#xff0c;常涉及到以下三个类&#xff1a;CacheDependency、HttpRuntime.Cache 和 System.Web.Caching。 CacheDependency&#xff08;缓存依赖项&#xff09;&#xff1a; CacheDependency 类用于指定一个或多个文件或目录作…...

266.【华为OD机试真题】抢7游戏(深度优先搜索DFS-JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-抢7游戏二.解题思路三.题解代码Python题解代码…...

工具分享:在线键盘测试工具

在数字化时代&#xff0c;键盘作为我们与计算机交互的重要媒介之一&#xff0c;其性能和稳定性直接影响到我们的工作效率和使用体验。为了确保键盘的每个按键都能正常工作&#xff0c;并帮助用户检测潜在的延迟、连点等问题&#xff0c;一款优质的在线键盘测试工具显得尤为重要…...

Arcmap excel转shp

使用excel表格转shp的时候&#xff0c;如果你的excel里面有很多字段&#xff0c;直接转很大概率会出现转换结果错误的情况&#xff0c;那么就需要精简一下字段的个数。将原来的表格文件另存一份&#xff0c;在另存为的文件中只保留关键的经度、纬度、和用于匹配的字段即可&…...

14. rk3588自带的RKNNLite检测yolo模型(python)

首先将文件夹~/rknpu2/runtime/RK3588/Linux/librknn_api/aarch64/下的文件librknnrt.so复制到文件夹/usr/lib/下&#xff08;该文件夹下原有的文件librknnrt.so是用来测试resnet50模型的&#xff0c;所以要替换成yolo模型的librknnrt.so&#xff09;&#xff0c;如下图所示&am…...