[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-20 读写I2C接口的RTC时钟芯片

软件版本:Anlogic -TD5.9.1-DR1_ES1.1

操作系统:WIN10 64bit

硬件平台:适用安路(Anlogic)FPGA

实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板

板卡获取平台:https://milianke.tmall.com/

登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

目录

1 概述

1.1 RTC时钟DS1337介绍

1.2 DS1337时序

1.3 硬件电路分析

2 用户程序设计

2.1 用户接口时序

2.2 UART发送控制器

2.3 用户控制状态机

2.4 程序源码

3 FPGA工程

4 下载演示

4.1 硬件连接

4.2 运行结果


1 概述

本节课继续利用I2C总线控制器实现对RTC时钟芯片,DS1337的读写访问,进一步验证我们设计的i2c控制器的可靠性。有了前面的基础,这节课内容学习起来很轻松。本节课主要是基于我们编写的I2C控制器的应用,侧重点是应用,所以不再给出RTL级别的仿真结果,直接通过控制器访问DS1337芯片。

在完成本实验前,请确保已经完成前面的实验,包括已经掌握以下能力:

1:完成了TD软件安装

2:完成了modelsim安装以及TD库的编译

3:掌握了TD仿真环境的设置

4:掌握了modesim通过do文件启动仿真

1.1 RTC时钟DS1337介绍

DS1337是低功耗、两线制串行读写接口、日历和时钟数据按BCD码存取的时钟/日历芯片。它提供秒、分、小时、星期、日期、月和年等时钟日历数据。另外它还集成了如下几点功能:

(1)56字节掉电时电池保持的SRAM 数据存储器

(2)可编程的方波信号输出

(3)掉电检测和自动切换电池供电模式

引脚说明:

VCC:直流电源,输入范围在1.8~5.5V

GND:接地端

X1/X2:标准的32.768kHz的石英晶振接入端

SCL:串行时钟输入

SDA:串行数据输入/输出

SQW/OUT:方波/中断输出

VBAT:中断输出端

寄存器地址空间:

DS1337的寄存器地址空间如下,我们的代码也就是读写以下地址空间。常用的时间寄存器地址为00H~06H,用这七个寄存器来存储秒、分、时、星期、日、月、年,通过写相应的寄存器字段来设置和初始化时间/日历,寄存器的数据格式以BCD码表示(4位二进制数来表示1位十进制数0~9)。

地址空间中详细的参数定义如下表

00H秒/01H分寄存器:计数范围为00~59,BIT0~BIT3表示个位。BIT4~BIT6表示十位。

02H小时寄存器:BIT6被定义为12小时模式(“1”)或24小时模式(“0”)选择位。在12小时模式时,计数范围为1~12,BIT5是AM(“0”)或PM(“1”)标志位;当在24小时模式时,计数范围为00~23,需要6位才能存下0~23的数据,BIT5是第二个十位(表示20到23小时)。

03H星期寄存器:计数范围为1~7,BIT0~BIT3表示个位。

04H日寄存器:计数范围为01~31,BIT0~BIT3表示个位,BIT4~BIT5表示十位。

05H月寄存器:BIT7是世纪位,当年寄存器从0到99溢出时,该位发生变化。

06H年寄存器:计数范围为00~99,BIT0~BIT3表示个位,BIT4~BIT7表示十位。

注意:07H~0FH为控制寄存器和状态寄存器,用于控制实时时钟、闹钟和方波的输出,本实验并未使用,详细介绍自行查阅芯片手册。

DS1337的读与写

写时序如下:

写时序很容易理解,和我们前面写EEPROM一样,主器件发起开始条件,先发送器件地址和写命令1101000,等待从器件的应答,再发送寄存器的地址,等待从器件的应答,之后是连续写数据,从器件应答,主器件发送结束信号,代表完成一次写数据过程。

读时序如下:

读时序我们采用上图的方式,主器件发起开始条件,先发送器件地址和写命令11010000,等待从器件的应答,再发送寄存器的地址,等待从器件的应答,然后主器件再重新发送开始条件,再发送从器件的地址和读命令11010001,等待从器件的应答,接收从器件发来的数据,主器件应答。这种方式比较方便,大家学习I2C的课程,如果和ZYNQ 部分SDK对比会发现SDK里面操作比较麻烦,而且采取的不是这种方式,这是因为SDK里面的I2C控制不能发送Repeated Start位的原因。

我们这里只针对时、分、秒的读写,而且上电后默认的控制寄存器不需要设置,采用默认参数就可以。

1.2 DS1337时序

根据手册我们可以知道I2C时钟频率、建立时间、保持时间、两次读写之间的时间间隔有没有限制等。由图可知DS1337的I2C支持快速和标准模式,串行时钟SCL频率可以位于0~400KHz。而建立时间Tsu和保持时间Thd在快速模式下都小于1us。I2C接口在发送一个STOP条件后到发送下一个START条件之间的最小间隔时间(Bus Free Time Between a STOP and START Condition)在快速模式(Fast mode)下,不小于1.3微秒、,而在标准模式(Standard mode)下,不小于4.7微秒,这段时间内总线上必须保持空闲。

1.3 硬件电路分析

因为FPGA一般不需要中断功能,所以中断管脚和方波编程输出引脚没有使用,进行悬空处理。X1、X2引脚接入32.768KHz的晶振构成一个振荡电路,生成芯片所需要的参考时钟信号。IIC总线需要上拉电阻。

用户程序设计

本次实验读写IIC接口的RTC时钟,首先写入一个时间初始值到RTC相应的地址空间,再读取时间值,因为是实时时钟,时钟数据是一直变化的,所以我们需要一直不断的读取时钟的值并将读取的时间通过串口发送到上位机。实验包含3个模块,I2C MASTER控制器驱动模块、UART发送控制器模块、用户控制模块。以下给出系统框图,关于IIC MASTER控制器驱动、UART发送控制器驱动的详细描述请看前面的实验,我们主要看用户控制模块关于状态机的部分。

2.1 用户接口时序

先温习下前面课程内容中关于I2C控制器的功能模块可以接口信号:

IO_sda为I2C双向数据总线

O_scl为I2C时钟

I_wr_cnt写数据字节长度,包含了器件地址,发送I_iic_req前,预设该值

I_rd_cnt读数据字节长度,仅包含读回有效部分,发送I_iic_req前,预设该值

I_wr_data写入的数据

O_rd_data读出的数据,如果是读请求,当O_iic_busy从高变低代表数据读回有效

I_iic_req I2C操作请求,根据I_rd_cnt是否大于0决定是否有读请求

I_iic_mode是否支持随机读写,发送I_iic_req前,预设该值

O_iic_busy总线忙

请求一次I2C传输的控制时序如下:

首先在O_iic_busy=0即I2C总线空闲情况下,设置I_wr_cnt,I_rd_cnt,I_wr_data,并且设置I_iic_req=1,启动I2C传输。当O_iic_busy=1说明I2C控制器开始传输,这时候可以设置I_iic_req=0,结束本次请求,并且等待O_iic_busy=0,当O_iic_busy=0代表本次传输结束.如果发送的是读请求(当I_rd_cnt>0),则此时O_rd_data有效可以读走数据。

2.2 UART发送控制器

将IIC读取到的RTC时间并行数据转成串行数据,并通过UART发送驱动模块,将数据通过uart发送串行总线(O_uart_tx)发回上位机。

2.3 用户控制状态机

首先进行通过复位进行数据初始化。

TS_S=0:板子刚上电时,首先初始化RTC寄存器的时间,设置需要访问的寄存器起始地址,并进入到下一个状态;如果已经完成对RTC芯片初始化,等待1000ms定时使能信号拉高,再次读取RTC寄存器的数据。

TS_S=1:当总线非忙,设置iic_req=1,请求操作I2C控制器,并设置需要写入的字节数(此时不需要读操作)。

TS_S=2:总线忙,重置 iic_req =0,此时为写数据过程。

TS_S=3:等待总线非忙,代表前面写数据已完成,设置iic_req=1请求操作I2C控制。读操作前需要先写1BYTE器件地址,1BYTE 寄存器起始地址,再读取3个时间寄存器。

TS_S=4:等待总线非忙,表示一次读RTC寄存器操作完成。回到状态0

2.程序源码

`timescale 1ns / 1ns//仿真时间刻度/精度module rtc_clock_ds1337#
(
parameter SYSCLKHZ   =  100_000_000 //定义系统时钟
)
(
input  wire I_sysclk, //系统时钟输入
output wire O_iic_scl,  //I2C总线,SCL时钟
inout  wire IO_iic_sda, //I2C总线,SDA数据
output wire O_uart_tx   //UART串行发送总线
);localparam T1000MS_CNT   =  (SYSCLKHZ-1); //定义访问RTC的时间间隔为1000MS
localparam [7:0] RTC_DEV_ADDR =  8'b1101_0000;reg [8 :0]  rst_cnt 	  = 9'd0;//上电延迟复位
reg [29:0]  t_cnt = 30'd0;//定时计数器
wire t_en = (t_cnt==T1000MS_CNT);//定时使能  wire [23:0] wr_data;//写数据信号
wire [23:0] rd_data;//读数据信号
wire 		iic_busy;//I2C总线忙
reg  [7 :0] wr_cnt = 8'd0;//写数据计数器
reg  [7 :0] rd_cnt = 8'd0;//读数据计数器
reg  		iic_req = 1'b0;//i2c 控制器请求信号
reg  [2 :0] TS_S   = 3'd0;//状态机reg  [7	:0] rtc_addr;//RTC的寄存器地址
reg         wr_done = 1'b0; //写RTC初值完成信号//初始化时间的BDC码,12:00:00
wire [7 :0] WSecond = {4'd0,4'd0};//妙
wire [7 :0] WMinute = {4'd0,4'd0};//分
wire [7 :0] WHour   = {4'd1,4'd2};//时
reg  [23:0] rtime   = 24'd0; //用于保存读取的时间,格式为BCD码assign wr_data   = {WHour,WMinute,WSecond};//写数据初值//**********上电延迟复位***************************/
always@(posedge I_sysclk) beginif(!rst_cnt[8]) rst_cnt <= rst_cnt + 1'b1;
end//**********500ms定时计数器**********************/
always@(posedge I_sysclk) beginif(t_cnt == T1000MS_CNT) t_cnt <= 0;else t_cnt <= t_cnt + 1'b1;
end//读写RTC时钟芯片状态机
always@(posedge I_sysclk) beginif(!rst_cnt[8])begin//复位初始化寄存器rtc_addr <= 8'd0;iic_req  <= 1'b0;wr_done  <= 1'b0;rd_cnt   <= 8'd0; wr_cnt   <= 8'd0;TS_S     <= 2'd0;    endelse begincase(TS_S)0:if(wr_done == 1'b0)begin//上电后,wr_done=0,对RTC时间寄存器初始化,给定初始时间wr_done  <= 1'b1;//设置wr_done=1rtc_addr <= 8'd0;//设置需要访问的寄存器起始地址TS_S     <= 3'd1;//下一个状态endelse begin //已经对RTC芯片初始化完成iic_req  <= 1'b0; //重置 iic_req =0if(t_en)//每间隔1000ms进行一次读操作TS_S     <= 3'd3;//下一个状态,进入读寄时间寄存器状态机end1:if(!iic_busy)begin//当总线非忙,才可以操作I2C控制器iic_req  <= 1'b1;//请求操作I2C控制器rd_cnt   <= 8'd0;//由于本操作是写数据,不需要读数据,读数据寄存器设置0 wr_cnt   <= 8'd5;//需要写入5 BYTES,包括1字节的器件地址,1字节的寄存器起始地址,3字节的BCD时间参数TS_S     <= 3'd2;//下一个状态机end2:if(iic_busy)begin//等待总线忙iic_req  <= 1'b0;//重置 iic_req =0TS_S     <= 3'd3;//下一个状态机	end3:if(!iic_busy)begin//该状态读RTC时间寄存器iic_req  <= 1'b1;//请求操作I2C控制器rtc_addr <= 8'd0;//读RTC寄存器的起始地址wr_cnt   <= 8'd2;//读操作需要些1BYTE器件地址,1BYTE 寄存器起始地址rd_cnt   <= 8'd3;//读取3个时间寄存器 TS_S     <= 3'd4;//下一个状态	end 4:if(iic_busy)begin//等待总线空闲iic_req  <= 1'b0;//重置 iic_req =0TS_S     <= 3'd0;//下一个状态	end   default: TS_S    <= 3'd0;//default状态回到0endcaseend
end//***********保存从RTC读取到的时间寄存器,时间为BCD格式***********//
always@(posedge I_sysclk) beginif(!rst_cnt[8])rtime <=0;else if(TS_S == 3)rtime[23: 0] <= rd_data;//读取的时间包括 时:分:秒,BCD格式
end//例化I2C控制模块
uii2c#
(
.WMEN_LEN(5),//最大支持一次写入4BYTE(包含器件地址)
.RMEN_LEN(3),//最大支持一次读出3BYTE
.CLK_DIV(SYSCLKHZ/100000)//100KHZ I2C总线时钟
)
uii2c_inst
(
.I_clk(I_sysclk),//系统时钟
.I_rstn(rst_cnt[8]),//系统复位
.O_iic_scl(O_iic_scl),//I2C SCL总线时钟
.IO_iic_sda(IO_iic_sda),//I2C SDA数据总线
.I_wr_data({wr_data,rtc_addr,RTC_DEV_ADDR}),//写数据寄存器
.I_wr_cnt(wr_cnt),//需要写的数据BYTES
.O_rd_data(rd_data), //读数据寄存器
.I_rd_cnt(rd_cnt),//需要读的数据BYTES
.I_iic_req(iic_req),//I2C控制器请求
.I_iic_mode(1'b1),//读模式
.O_iic_busy(iic_busy)//I2C控制器忙
//.iic_bus_error(iic_bus_error),//总线错误信号标志
//.IO_iic_sda_dg(IO_iic_sda_dg)//debug IO_iic_sda
); //以下完成BCD码赚ASCII码,这样通过串口打印可以方便观察
function signed[7:0] ascii ;   //定义ascii码转换函数,只需要转换BCD数据 input[7:0] bcd; //输入参数  begin                                                    case(bcd)0 :		ascii	=	{8'h30};//ascii 码0	1 :		ascii	=	{8'h31};//ascii 码1		2 :		ascii	=	{8'h32};//ascii 码2	3 :		ascii	=	{8'h33};//ascii 码34 :		ascii	=	{8'h34};//ascii 码4	5 :		ascii	=	{8'h35};//ascii 码5			6 :		ascii	=	{8'h36};//ascii 码6	7 :		ascii	=	{8'h37};//ascii 码7	8 :		ascii	=	{8'h38};//ascii 码8	9 :		ascii	=	{8'h39};//ascii 码9default:ascii	=	{8'h00};	endcase                                
end  endfunction   //例化UART发送模块
uart_tx_block #
(
.TX_BYTES(10),//设置需要发送的字节数
.BAUD_DIV(SYSCLKHZ/115200 -1) //设置串口波特率
)
u_uart_tx_block
(
.I_sysclk(I_sysclk),//系统时钟输入
.O_uart_tx(O_uart_tx),//UART 串行总线数据发送
//高位,8'h0a,8'h0d,为回车+换行控制字符
.I_uart_tx_buf({8'h0a,8'h0d,ascii(rtime[3:0]),ascii(rtime[7:4]),8'h2d,ascii(rtime[11:8]),ascii(rtime[15:12]),8'h2d,ascii(rtime[19:16]),ascii(rtime[23:20])}),
.I_uart_tx_buf_en(t_en)//t_en也是发送使能
);endmodule

3 FPGA工程

fpga工程的创建过程不再重复

米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹

01_rtl:放用户编写的rtl代码

02_sim:仿真文件或者工程

03_ip:放使用到的ip文件

04_pin:放fpga的pin脚约束文件或者时序约束文件

05_boot:放编译好的bit或者bin文件(一般为空)

06_doc:放本一些相关文档(一般为空)

下载演示

4.1 硬件连接

(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)

请确保下载器和开发板已经正确连接,并且开发板已经上电(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)

4.2 运行结果

在配套demo路径下我们也提供了可以用串口打印的demo

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

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

相关文章

超声波清洗机选哪款比较好?推荐四款性价比超高型号

2024年的超声波清洗机技术已经取得了显著进步。市面上的超声波清洗机种类繁多&#xff0c;功能各异&#xff0c;有的可以彻底清洁眼镜&#xff0c;有的还能进行消毒等。今天&#xff0c;我向大家推荐几款我亲自测试过的超声波清洗机&#xff0c;它们的性能都相当优秀&#xff0…

分布式搜索引擎ES-elasticsearch入门

1.分布式搜索引擎&#xff1a;luceneVS Solr VS Elasticsearch 什么是分布式搜索引擎 搜索引擎&#xff1a;数据源&#xff1a;数据库或者爬虫资源 分布式存储与搜索&#xff1a;多个节点组成的服务&#xff0c;提高扩展性(扩展成集群) 使用搜索引擎为搜索提供服务。可以从海量…

Android获取当前屏幕显示的是哪个activity

在 Android 中&#xff0c;要获取当前屏幕显示的 Activity&#xff0c;可以使用以下几种方法&#xff1a; 方法一&#xff1a;使用 ActivityManager 获取当前运行的任务信息 这是一个常见的方法&#xff0c;尽管从 Android 5.0 (API 21) 开始&#xff0c;有些方法变得不太可靠…

Java语言程序设计——篇五(2)

有关数组的方法 &#x1f4a5;增强的for循环实战演练 数组元素的复制实战演练 数组参数与返回值&#x1f4a2;java.util.Arrays类数组的排序实战演练 元素的查找数组元素的复制填充数组元素数组的比较实战演练 &#x1f4a5;增强的for循环 增强的for循环&#xff0c;它是Java …

MySQL(6)内置函数,复合查询.

目录 1.内置函数; 2.复合查询; 1.内置函数: 1.1 日期函数: 时分秒: 时间戳: 基本日期上加日期: 基本日期减去日期: 日期相差天数: &#x1f330; 创建一张表&#xff0c;记录生日: 创建一个留言表: 显示所有留言信息&#xff0c;发布日期只显示日期&#xff0c;不用显示时间: …

tree组件实现折叠与展开功能(方式1 - expandedTree计算属性)

本示例节选自vue3最新开源组件实战教程大纲&#xff08;持续更新中&#xff09;的tree组件开发部分。考察响应式对象列表封装和computed计算属性的使用&#xff0c;以及数组reduce方法实现结构化树拍平处理的核心逻辑。 实现思路 第一种方式&#xff1a;每次折叠或展开后触发…

node管理工具nvm

使用nvm可以切换node版本、命令安装node 一、nvm下载安装 1、下载 nvm-setup.zip - 蓝奏云 在github可以选择最新版的【nvm】&#xff1a;&#xff08;nvm-windows 最新下载地址&#xff09;Releases coreybutler/nvm-windows GitHub nvm-noinstall.zip&#xff1a; 这个…

基于edk2编译arm64版intel网卡undi驱动

本文介绍如何在edk2下面编译intel undi驱动。 edk2版本edk2-stable202305 文章目录 一、源码下载二、驱动编译2.1 第一次编译IntelXGigUndi及修改2.2 Intel其他undi驱动编译三、驱动二进制文件四、驱动使用方法一、源码下载 intel 网卡驱动下载地址 https://www.intel.com/con…

MySQL 数据库 - 事务

MySQL 数据库&#xff08;基础&#xff09;- 事务 事务简介 事务 是一组操作集合&#xff0c;他是一个不可分割的工作单位&#xff0c;事务会把所有的操作看作是一个整体一起向系统发送请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 比如&#xff1a;张…

C#医学影像管理系统源码(VS2013)

目录 一、概述 二、系统功能 系统维护 工作站 三、功能介绍 影像采集 统计模块 专业阅片 采集诊断报告 报告管理 一、概述 医学影像存储与传输系统&#xff08;PACS&#xff09;是一种集成了影像存储、传输、管理和诊断功能的系统。它基于数字化成像技术、计算机技术和…

STM32CubeMX配置STM32G071输入捕获(HAL库开发)

1.时钟配置HSI主频配置64M 2.配置好串口&#xff0c;选择异步模式 3.配置TIM1_CH1产生1KHz的信号&#xff0c;主频64MHz&#xff0c;分频&#xff08;64-1&#xff09;&#xff0c;计数周期&#xff08;1000-1&#xff09;&#xff0c;这样即可生成1KHz信号。 4.配置TIM3_CH1和…

农业旅游与乡村旅游:融合绿色田野与诗意远方的经济新篇章

在这个快节奏的时代&#xff0c;人们对于回归自然、体验淳朴生活的渴望日益增强。农业旅游与乡村旅游&#xff0c;作为新兴的旅游形态&#xff0c;正逐步成为连接城市与乡村的桥梁&#xff0c;不仅为都市人提供了一片心灵的栖息地&#xff0c;也为农村地区带来了前所未有的发展…

昇思25天学习打卡营第15天|munger85

K近邻算法实现红酒聚类 现在数据集这个就是红酒的分类的数据集红酒每一个都会有很多的属性有三个属性下载数据集&#xff0c;这个是红酒的分类的数据集&#xff0c;红酒每一个都会有很多的属性&#xff0c;有三个属性。这十三个属性就可以用来分辨它是哪一个13个属性就可以用来…

Nacos部署升级1.4.2到2.3.1版本

一.下载安装&#xff1a; https://github.com/alibaba/nacos/releases/download/2.3.1/nacos-server-2.3.1.zip 下载完成解压即可 二.新旧版本数据结构有变化需要同步数据结构&#xff1a; ALTER TABLE config_info ADD encrypted_data_key TEXT NOT NULL COMMENT ‘秘钥’;…

【第5章】Spring Cloud之Nacos服务注册和服务发现

文章目录 前言一、提供者1. 引入依赖2.配置 Nacos Server 地址3. 开启服务注册 二、消费者1. 引入依赖2.配置 Nacos Server 地址3. 开启服务注册 三、服务列表四、服务发现1. 获取服务列表2. 测试2.1 获取所有服务2.2 根据服务名获取服务信息 五、更多配置项总结 前言 本节通过…

hot100 | 十四、贪心

1-leetcode121. 买卖股票的最佳时机 注意&#xff1a; Labuladong的套路太厉害了&#xff0c;分析的很清晰状态转移方程 public int maxProfit(int[] prices) {int n prices.length;int[][] dp new int[n][2];for (int i 0; i < n; i) {if (i-1 -1){// base casedp[…

基于Python+Django+MySQL的心理咨询预约系统

心理咨询预约系统 DjangoMySQL 基于PythonDjangoMySQL的心理咨询预约系统 项目主要依赖Django3.2&#xff0c;MySQL 支持随机验证码生成与登录验证 简介 基于PythonDjangoMySQL的心理咨询预约系统通过连接数据库获取数据&#xff0c;登录新增随机数字验证码验证。具体可以看…

Ruby爬虫技术:深度解析Zhihu网页结构

在互联网时代&#xff0c;数据的价值日益凸显&#xff0c;尤其是在社交媒体和问答平台如Zhihu&#xff08;知乎&#xff09;上&#xff0c;用户生成的内容蕴含着丰富的信息和洞察。本文将深入探讨如何使用Ruby爬虫技术来解析Zhihu的网页结构&#xff0c;并获取有价值的数据。 …

泛域名ssl生成

ssl生成 参考文档 https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E安装acme curl https://get.acme.sh | sh -s email[此处放githup的邮箱]例&#xff1a;curl https://get.acme.sh | sh -s emailmyexample.com手动 dns 方式 // 1.触发验证&#xf…

某安居客滑块验证码

⚠️前言⚠️ 本文仅用于学术交流。 学习探讨逆向知识&#xff0c;欢迎私信共享学习心得。 如有侵权&#xff0c;联系博主删除。 请勿商用&#xff0c;否则后果自负。 网址 aHR0cHM6Ly93d3cuYW5qdWtlLmNvbS9jYXB0Y2hhLXZlcmlmeS8/Y2FsbGJhY2s9c2hpZWxkJmZyb209YW50aXNwYW0 …