<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="https://blog.x-tools.top/feed/rss/category/MarkDown/">
<title>小夏的猪窝 - 笔记</title>
<link>https://blog.x-tools.top/category/MarkDown/</link>
<description>这里是笔记存放的地方！</description>
<items>
<rdf:Seq>
<rdf:li resource="https://blog.x-tools.top/archives/103/"/>
<rdf:li resource="https://blog.x-tools.top/archives/98/"/>
<rdf:li resource="https://blog.x-tools.top/archives/96/"/>
<rdf:li resource="https://blog.x-tools.top/archives/77/"/>
<rdf:li resource="https://blog.x-tools.top/archives/75/"/>
<rdf:li resource="https://blog.x-tools.top/archives/72/"/>
<rdf:li resource="https://blog.x-tools.top/archives/67/"/>
<rdf:li resource="https://blog.x-tools.top/archives/66/"/>
<rdf:li resource="https://blog.x-tools.top/archives/55/"/>
<rdf:li resource="https://blog.x-tools.top/archives/53/"/>
</rdf:Seq>
</items>
</channel>
<item rdf:about="https://blog.x-tools.top/archives/103/">
<title>Auto_Si9000 阻抗计算神器，让 PCB 设计效率飙升！</title>
<link>https://blog.x-tools.top/archives/103/</link>
<dc:date>2025-01-12T09:27:00+00:00</dc:date>
<description>前言该项目的上篇文章是：关于SI9000计算阻抗接口的研究；上篇讲解了Si9000的接口调用，可以被任何高级编程语言使用，如上篇文章中的Python；本篇发布前，本人也使用Python写了6个常见的模型，包括正算、反算，但由于Python的UI方面没有过多的知识储备，导致Python始终是使用命令行终端来呈现的... 总之难用就对了，而且终端的话无法做到批量的数据正算、反算；这里也放出Python的GitHub项目地址：Auto_Si9000_Py，仅供学习参考；以上这就是我转换到.NET C# WPF编写的原因；Auto_Si9000 功能1、支持常见的8个阻抗模型：外层单线不对地,外层单线对地,内层单线不对地,内层单线对地,外层双线不对地,外层双线对地,内层双线不对地,内层双线对地；2、支持批量阻抗的正算、反算；3、支持生成原生的Si9000软件界面的预览图，并支持复制到剪贴板；预览图中还圈出了重要的数据，如线宽、线距、对地数据，用于EQ的建议；软件截图程序主界面：预览界面：支持复制到剪贴板：项目地址https://github.com/XiaM-Admin/Auto_Si9000_WPF如果帮助到你，可以点一个小小的Star哦~</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/98/">
<title>关于SI9000计算阻抗接口的研究</title>
<link>https://blog.x-tools.top/archives/98/</link>
<dc:date>2024-11-26T01:50:24+00:00</dc:date>
<description>开篇在PCB设计中，阻抗控制主要是指控制信号线的特性阻抗，使其与传输线或连接设备的阻抗匹配，以确保信号在传输过程中不产生过多的反射和损耗，常用于传输线的设计中。上述的重点就是阻抗匹配，客户端若在PCB中存在阻抗管控的要求，需要某一段线路的阻抗在XΩ±Y%（例：50Ω±10%）的范围内，PCB厂商在生产的过程中需要尽量保证阻抗线完整、平滑。除了在生产过程中保证应该有的质量保证，还需要在工程设计阶段对资料中阻抗线的理论阻抗值进行模拟，如果模拟的阻抗值超出客户要求的阻抗管控范围，或偏差较大时，PCB厂商通常会对阻抗线进行建议调整，以确保阻抗值在客户要求的范围内。此外PCB生产完毕后，还需要指定的阻抗条测试模块，对PCB的阻抗进行测试，此时测量出来的就是板内实际的阻抗值了。那么，如何对阻抗进行模拟计算呢？Polar SI9000我们需要使用到各种阻抗模拟的软件，本文使用的软件为：Polar SI9000，SI9000是Polar公司开发的一款用于PCB设计的阻抗模拟软件，可以帮助设计师精确计算和优化传输线的特性阻抗。该软件中有各种阻抗线的模拟层叠结构，常用的有单线、单线共面、双线、双线共面，以及提供了内层、外层、盖油、不盖油的几类模拟阻抗模拟计算结构；若需要模拟阻抗，只需要选择一个符合客户资料设计的阻抗线模型，填入需要的参数后，点击Calculate(计算)即可实现对理论阻抗的模拟。接下来我们使用Coated Microstrip1B(外层单线盖油)模型来实现对阻抗的模拟计算：首先，填入软件需要的参数：介质层厚度(H1)、介质层介电常数(Er1)、线路下线宽(W1)、线路上线宽(W2)、线路厚度(T1)、基材上油墨厚度(C1)、线路上基材厚度(C2)、油墨介电常数(CEr)；这些参数根据PCB厂商总结的常规参数填入即可，其中W1与W2，阻抗线的上下线宽通常是相差1Mil（受蚀刻药水的影响），1Mil是PCB厂商的常规蚀刻要求侵蚀的量，W1-W2=1Mil；关于板材以及油墨的介电常数需要让板材、油墨供应商来提供；填完参数点计算即可出现相应的阻抗Zo值了。以上是一个阻抗仿真的步骤，实际上操作会比文本描述更加繁琐，更何况一个PCB中常规情况下不仅仅只有1个阻抗需要管控。并且SI9000的保存做的不是很好，如果PCB的层压叠构改变，所有阻抗都需要重新计算！非常难受... 这就让我产生了对SI9000阻抗程序的研究，找到软件的接口，制作一个基于SI9000计算接口的阻抗计算项目；CalcEngineBEMDll.dll旧版本的SI9000安装目录中，没有CalcEngineBEMDll.dll，应该是集成在软件中了，本文使用的SI9000版本是V7.1.0，其中CalcEngineBEMDll.dll版本为V3.30，PolarGraphDll.dll的版本为V1.30。该阻抗计算软件的接口均在CalcEngineBEMDll.dll中，SI9000.exe本体就是调用dll中的开放的接口来实现阻抗值的计算。为什么？因为SI8000是SI9000的老版本，8000的安装目录中提供了两个Excel文件，分别为Si8000.xls、Si8000Expert.xls，这些Excel中的VBA代码均被加密，使用网上的破解方法进入查看工程代码后，发现表中实现阻抗值计算的方法均是来自CalcEngineBEMDll.dll，该dll使用depends.exe加载后显示存在139个方法，其中阻抗计算的方法就有95个，在depends.exe加载的dll并不能展示方法所需的参数个数、参数类型等信息，但是在SI8000的Excel中VBA工程中所有方法的参数、参数类型都在其中！以上，我们可以知道，阻抗计算方法在DLL中，方法可以被调用，方法的传参可以参考VBA工程；但前提是，用户电脑上必须安装好SI9000软件才可以；接下来，本文中我将使用Python对DLL中计算方法进行调用，其它的语言请读者自行尝试。Python调用Python是一个强大的高级编程语言，简单易用，各种领域都会有它的身影，无论是大小项目，都可以使用现有的pip包轻松实现。示例项目使用的包为Python自带的ctypes，这个项目结构如下：|--Auto_SI9000|----main.py &gt; 调用calcFun中的类实现阻抗值计算|----models.py &gt; 定义一些需要使用的结构体|----si9000.py &gt; 加载DLL，定义DLL中方法的传参及返回值|----calcFun.py &gt; Calc类(单计算)，Calc_Plus类(多计算，继承Calc)|---lib文件夹 &gt; 存放需加载的DLL相关文件接下来展示一下调用DLL的简单代码流程：1、首先调用DLL中的ClaimFlexLicence方法，认证一下产品Key（仅需要认证一次）；2、使用IsCalculationModelAllowed方法，指定需要使用的模型并允许DLL可以准备开始计算；3、调用计算方法CoatedMicrostrip1B方法，并传入需要前面讲到的单线模型需要的一些参数（H1、Er1等），调用完成后会立刻返回，它的返回值是int(long)类型，1或0；该方法会将传入的参数进行检查，检查后会立刻返回检查的结果，返回1，则代表计算已经开始，返回0，代表计算参数存在错误，需要重新检查参数正确性！4、调用QueryCalculationFinished等待方法，等待计算结束；5、使用QueryCalculationResult方法获取阻抗计算结果，该方法如果直接传入结构体，会出现写入权限限制的问题，需要将变量的地址作为参数解决该问题；最后，结构体中的dImpedance就是结果阻抗值了！以上的调用流程均是来自VBA工程中的，其中部分方法可以跳过，或更改流程，读者可自行尝试。最后本文到此为止就结束了，更多的DLL方法请自行在VBA工程中解读；该项目目前还未完成，现只提供了一个单线模型的计算方法示例；我会在文本末尾添加上本次示例项目的下载链接（Python代码，SI9000安装包），请自行下载，感谢各位！项目下载链接：https://image.180402.xyz/S3/Auto_SI9000%20V2.exe</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/96/">
<title>关于Yolo在脚本中的应用及介绍</title>
<link>https://blog.x-tools.top/archives/96/</link>
<dc:date>2024-09-11T06:26:51+00:00</dc:date>
<description>YOLO，全称为"You Only Look Once"，是一种实时目标检测算法。它由Joseph Redmon、Santosh Divvala、Ross Girshick和Ali Farhadi在2016年提出，核心在于将目标检测任务视为一个回归问题，直接从完整的输入图像中预测出边界框（bbox）和类别的概率。YOLO的基本原理：统一检测：YOLO摒弃了传统两阶段检测法的复杂流程，采用单阶段策略，无需生成候选区域，直接在整张图像的SxS网格上执行检测。每个网格旨在判断是否有物体存在及其中心位置是否落于该网格。边界框预测：每个网格预测B个边界框，包含物体的位置信息（x, y, width, height）及置信度分数，该分数反映框内有物体的概率及框的准确度。同时，预测C个类别概率，指明框内物体可能所属的类别。损失函数：通过一个多任务损失函数整合分类、定位及置信度的误差，以此来训练网络，优化检测性能。  YOLO因其实时性和高效性，在诸如视频监控、自动驾驶、无人机等领域得到广泛应用，成为目标检测技术中的一个重要里程碑。YOLOv8版本介绍:YOLOv8是YOLO（You Only Look Once）系列目标检测模型的最新版本，由 Ultralytics 团队开发。YOLO 系列因其速度与准确性平衡而广受欢迎，尤其适合实时对象检测任务。YOLOv8 在继承了前代版本优势的基础上，引入了多项改进和新特性，主要亮点包括：基于PyTorch的模型架构：YOLOv8完全使用PyTorch构建，这使得模型更易于定制、调试和部署。无代码训练与推理：Ultralytics为YOLOv8提供了一个强大的命令行界面(CLI)工具，允许用户无需编写代码即可进行模型训练、微调、推理等操作，极大地降低了使用的门槛。模型优化：YOLOv8对模型架构进行了优化，引入了EfficientNet等高效网络结构作为骨干网络，提升了模型在不同尺寸目标上的检测性能，同时保持了高效的推理速度。自动注释与数据增强：集成了自动标注工具和先进的数据增强技术，帮助用户更高效地准备训练数据。多任务学习：除了基本的目标检测外，YOLOv8还支持实例分割、关键点检测等多种任务，实现了统一的模型框架处理多种计算机视觉任务。模型大小可选：YOLOv8提供了从Nano到X的大规模模型变体，用户可以根据具体需求选择合适的模型大小，平衡精度与速度。推理优化：针对推理速度进行了特别优化，支持ONNX、TensorRT、OpenVINO等多种推理加速方式，确保在各种硬件平台上都能实现快速推理。更新的损失函数与训练策略：采用更先进的损失函数和训练策略，如自适应anchors生成、更精细的梯度优化方法等，进一步提升训练效率和检测精度。  总的来说，YOLOv8是一个高度优化且用户友好的目标检测框架，不仅在性能上有所提升，而且在易用性和灵活性方面也做了大量改进，非常适合研究人员和开发者用于各种计算机视觉项目。阴阳师游戏中的实际应用场景:探索任务的优化：在Buff可以实现快速检测出：经验、金币、达摩（Buff）；同时检测出战斗标志，通过勾股定理找到Buff距离最近的战斗标志；2步骤的优化：可以检索出所有斜边的值，若在范围内，则点击战斗标志；3步骤的优化可以避免：场景内有一只需战斗的Buff怪，但没有这只怪的战斗图标时，此根据b的逻辑就会打其它不想打的Buff怪；场景识别的优化：YOLOv8有分类的功能，可以将游戏中所有场景进行归类，跑一个场景识别模型；目前根据猜想可以训练的场景分类有：庭院、式神录、战斗场景、斗技、逢魔之时等各种场景；（本人尚未有时间实现）CSharp中的YOLOv8:YOLOv8的实现是使用YOLOv8.NET（Nuget包）来实现的；经本人电脑测试，该包的GPU版本一致是报错（dll找不到、dll载入失败等），在CPU环境下使用YOLO会导致处理器占用急剧上升，但也还好，占用利用率差不多处于50%-70%之间（仅单线程测试）；YOLO在脚本软件中，如果是CPU支持，还是尽量少使用模型检测；后续还是会继续研究尝试，开启GPU使用...关于少用YOLO模型检查，可以做到的：在探索任务检测目标时的YOLO扫描频次减少、周期间隔增加；在场景判断时，优先使用大漠插件判断，若没有结果则启用模型检测；关于CSharp中多线程使用YOLO：作为静态辅助类（未测试多线程占用表现）：需加锁lock使用；多个模型切换时，可以缓存对象到本地，再次切换时直接调用缓存对象；动态实例类（未实现）：我的猜测时无需做加锁处理，因为每个实例对象均互不影响，后期做验证；</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/77/">
<title>STM32 - DS18B20驱动</title>
<link>https://blog.x-tools.top/archives/77/</link>
<dc:date>2022-11-16T10:05:00+00:00</dc:date>
<description>&lt;!--[toc]--&gt;DS18B20简单介绍一下，查询数据手册可以知道：一个温度传感器，测量范围在-55°C ~ +125°C，仅需要单片机一个IO接口，寄生电源模式（没玩过），宽电压范围 +3.0V ~ +5.5V。通信时序图时序图：参数表：如图有：写指令时序读数据时序重置重置时序检测时序写指令函数观察写指令时序图，首先将电平从低拉高后等待tREC的时间，时间查看参数表中最小为1us，最小延迟1us是为了使电平稳定。延迟1-2us后，将电平改变成有效数据位的高低电平后，观察时序图tSLOT一个周期时间在60-120us之间，所以我们延迟60us即可。如部分代码(其中使用了部分宏定义，若需要更全的文件，请跳至最后下载附件即可)：/*******************************************************************************
  * 函数名：DS18B20_WriteByte
  * 功  能：向DS18B20写入一个字节
  * 参  数：u8Data:要写入的数据
  * 返回值：无
  * 说  明：
*******************************************************************************/
void DS18B20_WriteByte(uint8_t u8Data)
{
    uint8_t tempIndex,tempData;
    DS18B20_DQModeOutput();//设置为输出
    for (tempIndex = 1; tempIndex &lt;= 8; tempIndex++)
    {
        tempData = (u8Data &amp; 0x01);
        u8Data &gt;&gt;= 1;
        if (tempData == 1)
        {
            DS18B20_DQReset();//低电平
            delay_us(2);
            DS18B20_DQSet();//高电平
            delay_us(60);//延时60us
        }else
        {
            DS18B20_DQReset();//低电平
            delay_us(60);//延时60us
            DS18B20_DQSet();//高电平
            delay_us(2);
        }        
    }
}读数据函数同样和写指令时序一样，一个周期为60us到120us内，读取电平的有效数据时间在15us内都是有效的，所以选择在12us后读取数据的电平，因为一个周期还没结束，所以多等待50us结束读取。拉低电平 -&gt; 等待2us -&gt; 拉高电平 -&gt; 等待12us -&gt; 读取电平 -&gt; 等待50us部分代码(其中使用了部分宏定义，若需要更全的文件，请跳至最后下载附件即可)：/*******************************************************************************
  * 函数名：DS18B20_ReadByte
  * 功  能：从DS18B20读取一个字节
  * 参  数：无
  * 返回值：u8Data读出的数据
  * 说  明：无
*******************************************************************************/
uint8_t DS18B20_ReadByte(void)
{
    uint8_t i,j, u8Ddata = 0;
    
    for (i = 1; i &lt;= 8; i++)
    {        
        j = DS18B20_ReadBit();
        u8Ddata = (j &lt;&lt; 7) | (u8Ddata &gt;&gt; 1);
    }    
    return u8Ddata;
}附件该附件包含：DS18B20.c 驱动文件DS18B20.h 驱动头文件maxim-ds18b20.pdf 传感器文档注意：此驱动使用的延迟方法利用定时器作为延迟，可自行更改。附件：DS18B20 STM32驱动.zip</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/75/">
<title>嵌入式 - 时序图写代码</title>
<link>https://blog.x-tools.top/archives/75/</link>
<dc:date>2022-11-16T06:27:00+00:00</dc:date>
<description>&lt;!--[toc]--&gt;IIC，I2（方）C ，利用总线SCL、SDA，写时序读取数据时序图：datasheet总线的概念总线占两线：SCL、SDA为什么是总线：可以在总线上连接很多IIC设备，这样可以节省2个io口从机地址从机地址：身份证、与生俱来，生产厂家规定当总线发送IIC的从机地址后，此IIC设备将返回一个应答信号从机地址是IIC设备独有的，可以可能被自己定义。从机地址一般为7位，通常情况下（24C02举例）：前四位固定后三位自定义最后一位：方向位 控制读写为0：主机写设备操作为1：主机读设备操作以上8位构成了寻址字节寻址字节单片机是怎么发送寻址字节IIC只有一位的数据接口，他只能一位一位的发送，所以IIC是串行发送首先建立通信需要向总线发送一个从机地址，并且最后一位方向位为0等待设备的应答信号，就能继续发送代码观察时序 写代码 24C02上图红框中为寻址字节。中间的存储单元地址为存储器存放数据的地址后方的数据为设备向单片机发送的数据上图红框部分与下图绿框部分一致。MSB意为数据 字节最高位ACK意为应答信号启动START函数带有参数的时序图首先分析启动部分（START CONDITION）：SCL：保持一段时间的高电平SDA：如图意思为，使SDA保持高电平一段时间（tCHDX）这样写代码即可。接下来继续分析SDA：以上一个START启动阶段就写完了。tCHCL：高时钟脉冲宽度寻址字节发送每经过一个SCL的方波周期，SDA就要发送一个数据其SCL经过一个高脉冲信号（由低电平转为高电平），IIC设备都会检测SDA信号那么就要先将SCL从高变为低，这样才会向设备发送一个高脉冲信号发送时，需要在SCL发送高脉冲信号前改变SDA的值后，才能有效的正确的发送读取。也就是当SCL处于低电平时改变SDA信号直至信号改变成功后，再将SCL调整到高电平。SCL从低电平转换为高电平结束的时间成为时钟周期上图中tCLDX表明：当SCL变为0后，SDA电平转换的时间上图中tDXCX为：输入转换到时钟转换 意思为：SDA电平转换后需要经过一段时间才能让SCL电平置为高电平因为tCHCL：低时钟脉冲宽度 中的时间包含 tDXCX，所以我们只需要考虑前者的时间间隔即可。应答信号当到达第九个时钟周期时，需要将SDA置为高电平，用于准备接受应答信号。当设备发送了应答信号后，就将SDA引脚的电平拉低，置为低电平。那么当SDA为0时，设备就回应了单片机的寻址地址指令，如图循环判断即可做到等待。等待应答，不是应该先把SCL拉低，然后SDA拉高，然后再拉高SCL读取SDA信号是否被拉低，因为在SCL为高电平的时候SDA电平不能变化STOP停止函数观察时序图，初始都为0，SCL为1 SDA需要在一段时间后调整至高电平即可。</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/72/">
<title>ESP32开发版 SPI接口查询记录</title>
<link>https://blog.x-tools.top/archives/72/</link>
<dc:date>2022-11-04T09:38:00+00:00</dc:date>
<description>&lt;!--[toc]--&gt;ESP32 SPI通信研究笔记使用ESP32加SPI通信连接TFT2.4寸屏幕 实现屏幕最基本的输出材料准备GOOUUU-ESP32开发版，某宝购入。2.4寸TFT液晶显示屏裸屏 驱动：ST7789V，某宝购入。[可选] 立创EDA自己画的装裸屏用的PCB板如果你买的是裸屏，就需要按照引脚、原理图自己画个底板。资料准备这里资料都是网上找的。2.4TFT7PIspi-GMT024-01.rar购入TFT屏幕时附赠的案例，已修改ESP32对应功能引脚。ESP32功能引脚图、以及IDE中数字引脚与功能的对应图。链接SPI通信SPI通信是一种全双工、高速的通信方式，其通信速度和IIC相比是遥遥领先...成功建立SPI通信至少需要4个引脚：MISO、MOSI、SCLK、CS，引脚作用分别是：主设备数据输入，从设备数据输出、主设备数据输出，从设备数据输入、时钟信号，由主设备产生、从设备片选信号，由主设备控制。MISO：主设备数据输入，从设备数据输出;
MOSI：主设备数据输出，从设备数据输入;
SCLK：时钟信号，由主设备产生;
CS：从设备片选信号，由主设备控制;操作本次TFT屏幕裸屏引出的引脚分别是：CS、DC、RST、SDA、SCL以及供电、供地。依次连接相关引脚：SCK - 22 - G22
SDA - 21 - G21
RST - 15 - G15
DC  - 32 - G32
CS  - 14 - G14连接后，验证上传程序，就可以看见效果...如图：完结本文只是测试TFT引脚连接对应ESP32功能引脚，并不是一个符合规范的程序示例。连接成功后，可以尝试使用更多外置的库文件，来使用此TFT屏幕。另外，嘉立创免费打板，6。</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/67/">
<title>CSharp - 判断当前环境是Debug还是Release</title>
<link>https://blog.x-tools.top/archives/67/</link>
<dc:date>2022-09-28T02:26:36+00:00</dc:date>
<description>最近在软件开发和发布过程中遇到了这样的烦恼：开发过程是在Debug模式下写的，需要与服务器对接一个指定的调试指令，才能正常调试。但是在发布时，需要手动将指令接口换成用户使用环境,切换至Release环境编译生产软件才可。这就导致，如果说，忘记了自己切换，这就影响了用户体验。那么怎么改成自动？我需要使用编译预处理指令#if等操作，如下：#if DEBUG
    Console.WriteLine(&quot;Debug模式&quot;);//调试环境
#else
    Console.WriteLine(&quot;Release模式&quot;);//生产发布环境
#endif这就能做到在切换发布环境时，编译器自动编译相应的代码了。</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/66/">
<title>JavaScript - 轮播图</title>
<link>https://blog.x-tools.top/archives/66/</link>
<dc:date>2022-09-27T08:00:00+00:00</dc:date>
<description>轮播图的几点功能：鼠标移入 显示上一张、下一张，移出 则隐藏。点击上下一张，自动切换显示图片，做到有动画效果、无缝切换。鼠标移出时自动每3秒切换图片，鼠标移入时则不自动切换。移动图片时下方小圆点也跟随改变选中的图片位置。可以点击下方小圆点，切换图片。直接放自己写的例子：首先网页部分及css，自己画的有点潦草...css部分&lt;style&gt;
     * {
         margin: 0;
         padding: 0;
     }

     ol {
         list-style: none;
         position: absolute;
         left: 50%;
         bottom: 0;
         transform: translate(-55%, 0);
     }

     ol li {
         display: inline-block;
         width: 10px;
         height: 10px;
         background: rgba(91, 66, 66, 0.3);
         border-radius: 50%;
         border: solid 1px black;
         cursor: pointer;
     }

     .current {
         display: inline-block;
         width: 10px;
         height: 10px;
         background-color: white;
         border-radius: 50%;
         border: solid 1px black;
     }

     .banner {
         position: relative;
         margin: 50px auto 0 auto;
         width: 520px;
         height: 326px;
         overflow: hidden;
     }

     .banner ul {
         position: absolute;
         left: 0;
         top: 0;
         list-style: none;
         width: 550%;
         height: 100%;
         z-index: -1;
     }

     .banner #banner_pic li {
         float: left;

     }

     .banner a {
         display: inline-block;
         cursor: default;
     }

     .banner span {
         display: inline-block;
         width: 25px;
         height: 25px;
         text-align: center;
         font-size: 20px;
         line-height: 25px;
         cursor: pointer;
         color: white;
         background: rgba(0, 0, 0, .3);
     }

     .banner #next {
         display: none;
         position: absolute;
         left: 0;
         top: 150px;
         border-radius: 25%;
     }

     .banner #forward {
         display: none;
         position: absolute;
         right: 0;
         top: 150px;
         border-radius: 25%;
     }

     img {
         display: inline-block;
         width: 520px;
         height: 326px;
     }

     .circle li {
         margin: 0 2px 0 2px;
     }
 &lt;/style&gt;html部分&lt;body&gt;
&lt;div class=&quot;banner&quot;&gt;
 &lt;span id=&quot;next&quot;&gt;&lt;&lt;/span&gt;
 &lt;span id=&quot;forward&quot;&gt;&gt;&lt;/span&gt;

 &lt;ul id=&quot;banner_pic&quot;&gt;
     &lt;li&gt;
         &lt;a href=&quot;JavaScript:&quot;&gt;
             &lt;img src=&quot;./updatas/1.png&quot; alt=&quot;图&quot;&gt;
         &lt;/a&gt;
     &lt;/li&gt;
     &lt;li&gt;
         &lt;a href=&quot;JavaScript:&quot;&gt;
             &lt;img src=&quot;./updatas/2.png&quot; alt=&quot;图&quot;&gt;
         &lt;/a&gt;
     &lt;/li&gt;
     &lt;li&gt;
         &lt;a href=&quot;JavaScript:&quot;&gt;
             &lt;img src=&quot;./updatas/3.png&quot; alt=&quot;图&quot;&gt;
         &lt;/a&gt;
     &lt;/li&gt;
     &lt;li&gt;
         &lt;a href=&quot;JavaScript:&quot;&gt;
             &lt;img src=&quot;./updatas/4.png&quot; alt=&quot;图&quot;&gt;
         &lt;/a&gt;
     &lt;/li&gt;
 &lt;/ul&gt;
 &lt;ol class=&quot;circle&quot;&gt;

 &lt;/ol&gt;
&lt;/div&gt;
&lt;/body&gt;JavaScript部分 let main_box = document.querySelector(&quot;.banner&quot;);
 let to_left = main_box.children[0];
 let to_right = main_box.children[1];
 let now_pic = 0;
 let pic_count = 0;
 let pic_ul = document.querySelector(&quot;#banner_pic&quot;);
 let ol = document.querySelector(&quot;.circle&quot;);

 let ThrottleValve = false;
 /**
  * 自动下一章操作
  */
 const auto_fun = function () {
     if (ThrottleValve) return;
     else ThrottleValve = true;

     if (now_pic &gt; pic_count - 1)
         now_pic = 0;
     else if (now_pic === pic_count - 1) {//无缝处理
         new EaseAnimation(pic_ul, (now_pic + 1) * -520, function () {
             pic_ul.style.left = 0 + &quot;px&quot;;
             ThrottleValve = false;//节流阀
         });
         now_pic = 0;
         for (let i = 0; i &lt; ol.children.length; i++) {
             ol.children[i].className = &quot;&quot;;
         }
         ol.children[now_pic].className = &quot;current&quot;;
         return;
     } else
         now_pic++;

     new EaseAnimation(pic_ul, now_pic * -520, function () {
         ThrottleValve = false;//节流阀
     });
     for (let i = 0; i &lt; ol.children.length; i++) {
         ol.children[i].className = &quot;&quot;;
     }
     ol.children[now_pic].className = &quot;current&quot;;
 }
 /**
  * 选中一张操作
  */
 const TogglePicture = function (i) {
     now_pic = i;
     new EaseAnimation(pic_ul, now_pic * -520);
     for (let i = 0; i &lt; ol.children.length; i++) {
         ol.children[i].className = &quot;&quot;;
     }
     ol.children[now_pic].className = &quot;current&quot;;
 }

 //对齐小圆点
 for (let i = 0; i &lt; pic_ul.children.length; i++) {
     let li = document.createElement(&quot;li&quot;);
     if (i === now_pic) {
         li.className = &quot;current&quot;;
     }
     li.addEventListener(&quot;click&quot;, function () {
         TogglePicture(i);
     });
     ol.appendChild(li)
     pic_count++;
 }

 //实现无缝切换
 //1. 拷贝第一张复制到最后
 let pic_start = pic_ul.children[0].cloneNode(true);
 pic_ul.appendChild(pic_start)


 let auto_timer = setInterval(auto_fun, 3000);
 TogglePicture(now_pic);
 main_box.addEventListener(&quot;mouseenter&quot;, function () {
     to_left.style.display = &quot;block&quot;;
     to_right.style.display = &quot;block&quot;;
     clearInterval(auto_timer);
 })

 main_box.addEventListener(&quot;mouseleave&quot;, function () {
     main_box.children[0].style.display = &quot;none&quot;;
     main_box.children[1].style.display = &quot;none&quot;;
     auto_timer = setInterval(auto_fun, 3000);
 })

 to_left.addEventListener(&quot;click&quot;, function () {
     if (ThrottleValve) return;
     else ThrottleValve = true;

     if (now_pic &lt; 0)
         now_pic = pic_count - 1;
     if (now_pic === 0) {//无缝处理
         pic_ul.style.left = pic_count * -520 + &quot;px&quot;;
         now_pic = pic_count - 1;
     } else
         now_pic--;
     console.log(now_pic)
     new EaseAnimation(pic_ul, now_pic * -520, function () {
         ThrottleValve = false;
     });
     for (let i = 0; i &lt; ol.children.length; i++) {
         ol.children[i].className = &quot;&quot;;
     }
     ol.children[now_pic].className = &quot;current&quot;;
 })

 to_right.addEventListener(&quot;click&quot;, function () {
     auto_fun();
 })
还需要js外部文件的一个函数：/**
 * 缓动动画
 * @param obj 目标对象
 * @param target 目标位置
 * @param callback 回调函数
 * @constructor
 */
function EaseAnimation(obj, target, callback) {
 clearInterval(obj.timer);
 obj.timer = setInterval(function () {
     if (obj.offsetLeft === target) {
         clearInterval(obj.timer);
         callback &amp;&amp; callback();
     } else {
         let step = (target - obj.offsetLeft) / 10;
         step = step &gt; 0 ? Math.ceil(step) : Math.floor(step);
         obj.style.left = obj.offsetLeft + step + &quot;px&quot;;
     }
 }, 20)
}B站课程中将下面的圆点索引和第几张图分开了，我不是按照课程上的写的。我把图片和圆点使用同一个索引，将两者联系在一起。轮播图前面还是挺简单的，但是无缝切换的要求给我绕半天....注意：当我们过快的点击切换图片时，动画效果会不好，所以我们需要节流阀利用一个flag标志，来控制用户过快的行为，当用户切换图片时关闭阀门，不允许用户再进行操作，我们开始执行动画效果展示，当动画完成时再将阀门打开。这就是原生的JavaScript轮播图。</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/55/">
<title>CSharp - 硬件信息查询监控</title>
<link>https://blog.x-tools.top/archives/55/</link>
<dc:date>2022-08-04T15:45:47+00:00</dc:date>
<description>说明本篇文章采用第三方开源库openhardwaremonitor来辅助编写查询信息，并且网上大多都是采用这种方式监控硬件信息。常用的硬件信息有：温度、时钟频率、电压、内存占用、存储空间占用、网络传输状态···这里仅获取到CPU温度以及GPU温度，其他查询方式类似，自己琢磨...一.下载第三方库下载方式：项目开源地址：https://github.com/hexagon-oss/openhardwaremonitor，自己去releases中下载最新版本并且自己编译好后，找到生成文件夹中的OpenHardwareMonitorLib.dll，我们就使用它！这里提供文章的第三方dll文件OpenHardwareMonitorLib.rar，解压打开即可(Ver：0.9.7.11)二.引用dll文件如图打开项目 - 右键引用 - 添加引用 点击"浏览" - 选中下载解压好的dll文件即可。三.使用这里首先引用命名空间using OpenHardwareMonitor.Hardware;
using System;然后复制粘贴下面的类 public class UpdateVisitor : IVisitor
 {
     public void VisitComputer(IComputer computer)
     {
         computer.Traverse(this);
     }

     public void VisitHardware(IHardware hardware)
     {
         hardware.Update();
         foreach (IHardware subHardware in hardware.SubHardware)
             subHardware.Accept(this);
     }

     public void VisitSensor(ISensor sensor) { }

     public void VisitParameter(IParameter parameter) { }
 }

 public class ComputerCore
 {
     private UpdateVisitor updateVisitor = new UpdateVisitor();
     private Computer computer = new Computer();

     public ComputerCore()
     {
         computer.Open();
         computer.CPUEnabled = true;//开启CPU信息监控
         computer.GPUEnabled = true;//开启GPU信息监控
         computer.Accept(updateVisitor);
     }

     /// &lt;summary&gt;
     /// 获取CPU温度
     /// &lt;/summary&gt;
     /// &lt;returns&gt;&lt;/returns&gt;
     public float GetCpuTemp()
     {
         computer.Accept(updateVisitor);
         float num = 0;
         float cc = 0;
         float avg = 0;
         for (int i = 0; i &lt; computer.Hardware.Length; i++)
         {
             //查找硬件类型为CPU
             if (computer.Hardware[i].HardwareType == HardwareType.CPU)
             {
                 for (int j = 0; j &lt; computer.Hardware[i].Sensors.Length; j++)
                 {
                     //找到温度传感器
                     if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature)
                     {
                         if (computer.Hardware[i].Sensors[j].Value is null)
                             continue;

                         num += (float)computer.Hardware[i].Sensors[j].Value;
                         if((float)computer.Hardware[i].Sensors[j].Value!=0)
                             cc++;
                         avg = num / cc;
                     }
                 }
             }
         }
         return avg;
     }

     /// &lt;summary&gt;
     /// 获取GPU温度
     /// &lt;/summary&gt;
     /// &lt;param name=&quot;isNva&quot;&gt;是不是英伟达GPU&lt;/param&gt;
     /// &lt;returns&gt;&lt;/returns&gt;
     public float GetGpuTemp(bool isNva = true)
     {
         computer.Accept(updateVisitor);
         HardwareType type = isNva ? HardwareType.GpuNvidia : HardwareType.GpuAti;

         for (int i = 0; i &lt; computer.Hardware.Length; i++)
         {
             //查找硬件类型为CPU
             if (computer.Hardware[i].HardwareType == type)
             {
                 for (int j = 0; j &lt; computer.Hardware[i].Sensors.Length; j++)
                 {
                     //找到温度传感器
                     if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature)
                     {
                         if (computer.Hardware[i].Sensors[j].Value is null)
                             continue;

                         return (float)computer.Hardware[i].Sensors[j].Value;
                     }
                 }
             }
         }
         return 0;
     }

 }
调用即可实例化：public ComputerCore CCore= new ComputerCore();CPU温度：CCore.GetCpuTemp()GPU温度：CCore.GetGpuTemp()(英伟达显卡) - CCore.GetGpuTemp(false)(非英伟达显卡)注意项目框架的Framework 版本要求 4.8引用后直接使用会出错，这里需要下载一个NuGet包作者使用的就是5.0.0版本，我也就没找事，用最新版。可自行测试。CPU温度因为有很多内核 每个内核温度不一样，所以我取了平均值。</description>
</item>
<item rdf:about="https://blog.x-tools.top/archives/53/">
<title>记录一次服务器配置测试过程</title>
<link>https://blog.x-tools.top/archives/53/</link>
<dc:date>2022-07-20T16:42:00+00:00</dc:date>
<description>服务器自启动我希望服务器在开机自启动某些python文件，可以使用shell命令操作。使用chkconfig服务配置shell文件存放目录：/etc/rc.d/init.d只要将自己的sh脚本文件放入目录中即可，这里使用的是start.sh文件名。增加脚本可执行权限chmod +x  /etc/rc.d/init.d/start.sh添加脚本到开机自动启动项目中cd /etc/rc.d/init.d
chkconfig --add start.sh
chkconfig start.sh on注意：自己的自启动脚本文件中开始的3行必须按照如下格式：#!/bin/sh
#chkconfig:2345 80 90
#decription:autostart具体解释参照这个博客链接即可修改linux的DNS解析本人使用的腾讯云服务器，在挂机器人启动GOCQ时，会出现如图的问题：(上面一条红色信息请无视~)我们只需要：修改resolv.conf即可，目录为/etc/resolv.confvi /etc/resolv.conf添加 或修改文件中的dns，无须重启服务器，保存立即生效; generated by /usr/sbin/dhclient-script
nameserver 114.114.114.114
nameserver 183.60.83.19
nameserver 183.60.82.98效果展示：自启动Python的FastApi需上面的步骤只需要在自己的脚本中加入# 自己python文件的位置
cd /PY/myapi
# 后台启用即可
nohup uvicorn main:app --port 3520 --reload  &gt; log.txt 2&gt;&amp;1 &amp;</description>
</item>
</rdf:RDF>