源码系列:基于FPGA的串口UART设计(附源工程)

原创 FPGA技术江湖 2024-12-30 07:31

大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。


今天给大侠带来基于FPGA的UART设计,附源码,获取源码,请在“FPGA技术江湖”公众号内回复“UART设计源码”,可获取源码文件。话不多说,上货。


设计背景



串口的出现是在1980年前后,数据传输率是115kbps~230kbps。串口出现的初期是为了实现连接计算机外设的目的,初期串口一般用来连接鼠标和外置Modem以及老式摄像头和写字板等设备。串口也可以应用于两台计算机(或设备)之间的互联及数据传输。由于串口(COM)不支持热插拔及传输速率较低,部分新主板和大部分便携电脑已开始取消该接口。串口多用于工控和测量设备以及部分通信设备中。

串口是串行接口的简称,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口(Serial Interface)是指数据一位一位地顺序传送。其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。

通信协议是指通信双方的一种约定。约定包括对数据格式、同步方式、传送速度、传送步骤、检纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。串口通信的两种最基本的方式为:同步串行通信方式和异步串行通信方式。

同步串行通信是指SPI(Serial Peripheral interface)的缩写,顾名思义就是串行外围设备接口。SPI是一种高速的全双工通信总线。封装芯片上总共有四根线,PCB布局布线也简单,所以现在很多芯片集成了这个协议。主要用于CPU和各种外围器件进行通信,TRM450是SPI接口。

异步串行通信是指UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。UART是一个并行输入成为串行输出的芯片,通常集成在主板上。UART包含TTL电平的串口和RS232电平的串口。RS232也称标准串口,也是最常用的一种串行通讯接口。RS-232-C 标准对两个方面作了规定,即信号电平标准和控制信号线的定义。RS-232-C 采用负逻辑规定逻辑电平,信号电平与通常的TTL电平也不兼容,RS-232-C 将-5V~-15V 规定为“1”,+5V~+15V 规定为“0”。


设计原理



uart的示意图如下:


其端口对应的功能表如下:


在设计过程中只需要关心RS232_TXD和RS232_RXD两个信号, RS232_TXD是数据发送端口,RS232_RXD是数据接收端口。

本设计将通过串口建立起计算机和实验板(ZX_1)之间的通信和控制关系,也就是通常所说的上下位机通信。要实现这样的通信,首先需要用到一个外部的电平转换芯片MAX232,其具体配置电路原理图如下:



解析:

MAX232芯片是美信(MAXIM)公司专为RS-232标准串口设计的单电源电平转换芯片,使用+5v单电源供电。


主要特点:

1、符合所有的RS-232C技术标准;

2、只需要单一+5V电源供电;

3、片载电荷泵具有升压、电压极性反转能力,能够产生+10V和-10V电压V+、V-;

4、功耗低,典型供电电流5mA;

5、内部集成2个RS-232C驱动器;

6、高集成度,片外最低只需4个电容即可工作。


本设计还需要分析在通信过程中,UART所对应的数据格式如下:

起始位:线路空闲时为高电平,当截获第一个低电平比特时,则为起始位;

信息位:在起始位之后,按照低位首发原则,顺序发送信息位的最低位到最高位,信息位的宽度可以是4、5、6、7、8中的一个;

奇偶校验位:信息位之后则是一个可选的奇偶校验位,它可以是无校验(NONE)、奇校验(ODD)、偶校验(EVEN)中的任意一个,无校验时,信息位之后就是停止位。奇偶校验是,使得信息位和校验位的所有1的个数保持奇数或者偶数位;

停止位:停止位的长度可以是1、1.5或2中的任意一个,它为高电平;

空闲位:持续的高电平。


波特率:每秒传输的数据位(bit)数为波特率。RS-232-C的波特率可以是50、75、100、150、300、600、1200、2400、4800、9600、19200波特。

通过分析上述的数据格式,在本设计中,将波特率设置为9600,起始位设置为1比特,信息位设置为8比特,奇偶校验位设置为0比特,停止位设置为2比特,空闲位设置为1比特。

因为在设计中只需要关注RS232_TXD和RS232_RXD这两个信号,既然只有两条线,所以只需要关注其数据收发时序即可,时序图如下:



设计架构


设计总架构图如下:


uart_pll模块是一个锁相环,通过50M的外部时钟(ref_clk),倍频得到100M的上游接口的100M系统时钟(sys_clk);divider模块为UART的分频模块,通过用100M的sys_clk作为输入,分频得到波特率为9600的uart_clk时钟。

transmitter模块为串口发送模块,并配合与其对应的trans_fifo发送数据缓存FIFO进行使用,将储存在FIFO中的数据通过RS232-C协议发送出去;

receiver模块为串口接收模块,并配合与其对应的rec_fifo接收数据缓存FIFO进行使用,将储存在FIFO中的数据通过RS232-C协议接收进来;


UART发送器(transmitter)设计

UART发送器的时序如下图:


UART接收器(receiver)设计

根据对UART时序的分析可以得到如下的状态转移表(SMF):



设计代码



顶层uart_lsm模块代码:

`include "uart_lsm_head.v"
module uart_lsm(ref_clk, global_reset,tdata, twrreq, tfull, rdata, rrdreq, rempty, uart_txd, uart_rxd);
input ref_clk, global_reset; //全局时钟复位 input [7:0] tdata; //发送fifo输入数据 input twrreq; //发送fifo写请求 output tfull; //发送fifo输出写满 output [7:0] rdata; //接收fifo输出数据 input rrdreq; //接收fifo的输入读请求 output rempty; //接收fifo的输出入空 output uart_txd; //输出发送线信号 input uart_rxd; //输入接收线信号
wire trxd;
wire [7:0] tf_data, rf_data; wire tf_rdreq, tf_empty, rf_wrreq; wire sys_clk, uart_clk, rst_n;

assign rst_n = ~global_reset;
trans_fifo t_fifo( //发送fifo .data(tdata), .rdclk(uart_clk), .rdreq(tf_rdreq), .wrclk(sys_clk), .wrreq(twrreq), .q(tf_data), .rdempty(tf_empty), .wrfull(tfull) );
transmitter trans( //发送模块 .clk(uart_clk), .rst_n(rst_n), .empty(tf_empty), .data(tf_data), .rdreq(tf_rdreq), .txd(trxd) );
rec_fifo r_fifo( //接收fifo .data(rf_data), .rdclk(sys_clk), .rdreq(rrdreq), .wrclk(uart_clk), .wrreq(rf_wrreq), .q(rdata), .rdempty(rempty) );
receiver rece( //接收模块 .clk(uart_clk), .rst_n(rst_n), .data(rf_data), .wrreq(rfwrreq), .rxd(trxd) );
uart_pll u_pll( //锁相环产生系统时钟,作用于fifo、divider .areset(global_reset), .inclk0(ref_clk), .c0(sys_clk) );
divider_ebd_1s_mealy //分频模块分频uart_clk,作用于receiver transmitter #(.HW(`DW), .LW(`DW)) div( .clk_in(sys_clk), .rst_n(rst_n), .clk_out(uart_clk) );
endmodule


transmitter模块代码:

//uart发送模块LSM(线性序列机)module transmitter(clk, rst_n, empty, data, rdreq, txd);
input clk, rst_n; //输入时钟复位 input empty; //来自fifo的输入空标志信号 input [7:0] data; //来自fifo的输入数据 output reg rdreq; //输出到fifo的读请求 output reg txd; //输出发送线信号
reg [7:0] temp; //中间寄存器 reg [7:0] count; //8位计数
`define EP 192 //终止符
always @ (posedge clk or negedge rst_n) begin : lsm_2s1 //线性序列机一段闭节点 if (!rst_n) //复位 count <= `EP; else if ((count >= `EP) && !empty) //计数大于终止符和非空(empty=0) count <= 0; else if (count < `EP) //计数小于终止符 count <= count + 1; end
always @ (posedge clk or negedge rst_n) begin : lsm_2s2 //线性序列机一段闭节点 if (!rst_n) //复位 begin txd <= 1; //发送线为高 rdreq <= 0; //读请求为0 temp <= 0; //中间寄存器为0 end else if ((count >= `EP) && !empty) //计数大于终止符fifo为非空,读请求拉高 rdreq <= 1; else case (count) 0 : begin rdreq <= 0; //读请求拉低 txd <= 0; end 1 : temp[7:0] <= data[7:0]; //输入数据给中间寄存器 1*16 : txd <= temp[0]; //中间寄存器按位给发送线发送 2*16 : txd <= temp[1]; 3*16 : txd <= temp[2]; 4*16 : txd <= temp[3]; 5*16 : txd <= temp[4]; 6*16 : txd <= temp[5]; 7*16 : txd <= temp[6]; 8*16 : txd <= temp[7]; 9*16 : txd <= 1; //拉高 endcase end
endmodule


接收模块receiver代码:

`include "uart_lsm_head.v"
module receiver(clk, rst_n, data, wrreq, rxd); //uart接收模块LSM(线性序列机)
input clk, rst_n; //输入时钟复位 output reg [7:0] data; //输出数据 output reg wrreq; //输出写请求 input rxd; //输入接收线信号
reg [7:0] count; //宏定义 `define EP 184 //终止符 `define GET0 24 `define GET1 `GET0+16 `define GET2 `GET1+16 `define GET3 `GET2+16 `define GET4 `GET3+16 `define GET5 `GET4+16 `define GET6 `GET5+16 `define GET7 `GET6+16 `define GETW `GET7+16 //wrreq=1 `define GLRW `GETW+1 //wrreq=0
always @ (posedge clk or negedge rst_n) begin : lsm_2s1 //线性序列机一段闭节点 if(!rst_n) count <= `EP; else if((count >= `EP) && !rxd) //rxd=0 count <= 0; else if (count < `EP) count <= count + 1; end
always @ (posedge clk or negedge rst_n) begin : lsm_2s2 //线性序列机二段闭节点 if(!rst_n) begin data <= 0; wrreq <= 0; //写请求为0 end else case(count) `GET0 : data[0] <= rxd; //将接收的数据通过data输出 `GET1 : data[1] <= rxd; `GET2 : data[2] <= rxd; `GET3 : data[3] <= rxd; `GET4 : data[4] <= rxd; `GET5 : data[5] <= rxd; `GET6 : data[6] <= rxd; `GET7 : data[7] <= rxd; `GETW : wrreq <= 1; //写请求拉高一拍,写进fifo `GLRW : wrreq <= 0; //一拍后写请求为0 endcase end
endmodule


参数宏的头文件代码
/////uart_lsm_head.v
//////////定义时标////////////`timescale 1us/1ns
/////////定义设计参数/////////`define BAUD_RATE 9600 //波特率=9600`define SYS_CLK 100000000 //系统时钟sys_clk 频率=100M`define REF_CLK 50000000 //系统时钟ref_clk频率=50M
//////////使用宏自动计算的诸参数////////////`define TBAUD_RATE (1000000.0/`BAUD_RATE)//波特率周期`define UART_CLK (16*`BAUD_RATE) //uart_clk 等于16倍波特率`define TUART_CLK (1000000.0/`UART_CLK) //uart_clk周期`define TEN_TUART_CLK (10.0*`TUART_CLK) //10倍uart_clk周期`define TUART_CLK100 (100.0*`TUART_CLK) //100倍uart_clk周期
`define TUART_CLK_HALF (`TUART_CLK/2.0) //uart_clk半周期`define TREF_CLK (1000000.0/`REF_CLK) //参考时钟周期`define TREF_CLK_HALF (`TREF_CLK/2.0) //参考时钟半周期
//////////使用宏自动计算的分频数(占空比50%)////////////`define DW (`SYS_CLK/(2*`UART_CLK))



仿真测试


transmitter(发送)模块的测试代码:

`include "uart_lsm_head.v"
module transmitter_tb;
reg clk, rst_n; reg empty; reg [7:0] data; wire rdreq; wire txd; reg [7:0] temp;
transmitter transmitter_dut( .clk(clk), .rst_n(rst_n), .empty(empty), .data(data), .rdreq(rdreq), .txd(txd) );
initial begin clk = 1; rst_n = 0; data = 0; empty = 1; temp = 0; #200.1 rst_n = 1; #200.1 empty=1;temp=8'h55; #`TBAUD_RATE data[0] = temp[0]; //发送第一个信息位(LSB) #`TBAUD_RATE data[1] = temp[1]; #`TBAUD_RATE data[2] = temp[2]; #`TBAUD_RATE data[3] = temp[3]; #`TBAUD_RATE data[4] = temp[4]; #`TBAUD_RATE data[5] = temp[5]; #`TBAUD_RATE data[6] = temp[6]; #`TBAUD_RATE data[7] = temp[7]; #`TBAUD_RATE empty = 0; #2000 $stop; end always #`TUART_CLK_HALF clk = ~clk; endmodule


receiver(接收)模块的测试代码:

`include "uart_lsm_head.v"
module receiver_tb;
reg clk, rst_n; reg rxd; wire [7:0] data; wire wrreq; reg [7:0] temp; //8位的中间寄存器,产生激励 receiver receiver_dut( .clk(clk), .rst_n(rst_n), .data(data), .wrreq(wrreq), .rxd(rxd) ); initial begin clk = 1; rst_n = 0; temp = 0; rxd = 1; #`TEN_TUART_CLK //*代表异步 //10倍uart_clk周期 rst_n = 1; #`TEN_TUART_CLK //启动一个停止位 rxd = 0; temp = 8'h55; #`TBAUD_RATE //数据使用波特率的周期 rxd = temp[0]; //发送一个信息位(LSB) #`TBAUD_RATE rxd = temp[1]; #`TBAUD_RATE rxd = temp[2]; #`TBAUD_RATE rxd = temp[3]; #`TBAUD_RATE rxd = temp[4]; #`TBAUD_RATE rxd = temp[5]; #`TBAUD_RATE rxd = temp[6]; #`TBAUD_RATE rxd = temp[7]; //发送最后一个信息位(HSB) #`TBAUD_RATE rxd = 1; #`TUART_CLK100 $stop; //100倍uart_clk周期 end always #`TUART_CLK_HALF clk = ~clk; // uart_clk 的时钟,使用uart_clk的半周期
endmodule


仿真图:分别为送和接收做仿真测试

发送的仿真波形如下:


接收的仿真波形如下:


根据以上两个仿真波形,可以发现设计是正确的,之后则可利用串口猎人的上位机软件,实现自发自收。

END

福利】:QQ交流群173560979,进群备注名字+学校/企业。
淘宝店铺:https://shop588964188.taobao.com
论坛网址:www.sxznfpga.com
叁芯智能FPGA课程

往期精选 

 
 

【免费】FPGA工程师人才招聘平台

FPGA人才招聘,企业HR,看过来!

系统设计精选 | 基于FPGA的实时图像边缘检测系统设计(附代码)

基于原语的千兆以太网RGMII接口设计

时序分析理论和timequest使用_中文电子版

求职面试 | FPGA或IC面试题最新汇总篇

特惠 | FPGA图像处理专题课,Quartus、ISE、Vivado全涉及

特惠 | FPGA时序分析及约束专题课,Quartus、ISE、Vivado全涉及

资料汇总|FPGA软件安装包、书籍、源码、技术文档…(2024.11.14更新)

FPGA技术江湖广发江湖帖

无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有,QQ微信双选,FPGA技术江湖打造最纯净最专业的技术交流学习平台。


FPGA技术江湖微信交流群

加群主微信,备注姓名+学校/公司+专业/岗位进群


FPGA技术江湖QQ交流群

备注姓名+学校/公司+专业/岗位进群

FPGA技术江湖 任何技术的学习就好比一个江湖,对于每一位侠客都需要不断的历练,从初入江湖的小白到归隐山林的隐世高人,需要不断的自我感悟自己修炼,让我们一起仗剑闯FPGA乃至更大的江湖。
评论
  •  近年来,消费电子行业难言景气,长期处于萎靡不振的状态。其中,作为明星品类的智能手机同样被寒意所笼罩,出货量持续下跌。据IDC发布的报告显示,2023年全年,中国智能手机市场出货量约2.71亿台,同比下降5.0%,创近10年以来最低出货量。不过,在智能手机行业整体低迷之际,折叠屏手机却表现亮眼,成为智能手机市场唯一实现增长的品类。据IDC发布的跟踪报告显示,2023年,中国折叠屏手机市场出货量约700.7万台,同比增长114.5%。而这也是自2019年首款产品上市以来,出货量连续4年同
    刘旷 2025-01-02 11:27 37浏览
  • 在科技飞速发展的今天,机器人已经逐渐深入到我们生活和工作的各个领域。从工业生产线上不知疲倦的机械臂,到探索未知环境的智能探测机器人,再到贴心陪伴的家用服务机器人,它们的身影无处不在。而在这些机器人的背后,C 语言作为一种强大且高效的编程语言,发挥着至关重要的作用。C 语言为何适合机器人编程C 语言诞生于 20 世纪 70 年代,凭借其简洁高效、可移植性强以及对硬件的直接操控能力,成为机器人编程领域的宠儿。机器人的运行环境往往对资源有着严格的限制,需要程序占用较少的内存和运行空间。C 语言具有出色
    Jeffreyzhang123 2025-01-02 16:26 83浏览
  • 2层PCB设计时候回路的寄生电感计算方式。由两个平面构成电流路径的回路电感,取决于每个平面路径的局部自感和它们之间的局部互感。平面越宽,电流分布就越扩散开,平面的局部自感就越小,从而回路电感也就越小。平面越长,局部自感就越大,从而回路电感也就越大。平面间距越小,平面之间的互感就越大,从而回路电感也就越小。当该区域为正方形,即长度等于宽度时,无论边长是多少,长和宽之比始终等于1。令人惊奇的是,一对平面上的边长为100mil的正方形区域和边长为1in的正方形区域的回路电感相同。平面对上的任一正方形区
    tao180539_524066311 2025-01-02 13:51 41浏览
  • 在科技飞速发展的今天,5G 通信技术无疑是最耀眼的明星之一。它如同一场数字革命的风暴,以其前所未有的速度、极低的延迟和强大的连接能力,为我们的生活、经济和社会带来了翻天覆地的变化,开启了一个万物互联的崭新时代。5G 技术的卓越特性5G,即第五代移动通信技术,相比其前辈们,有着诸多令人瞩目的特性。首先是超高速率。5G 网络的理论峰值下载速度可达 10Gbps,这意味着下载一部高清电影只需短短几秒钟,而 4G 网络可能需要几分钟甚至更长时间。这种高速率让高清视频流、云游戏等对带宽要求极高的应用变得流
    Jeffreyzhang123 2025-01-02 14:18 60浏览
  • 常见通信标准无线通信标准蜂窝移动通信标准:如 2G(GSM)、3G(WCDMA、CDMA2000、TD - SCDMA)、4G(LTE)以及 5G 等。以 5G 为例,其具有高速率、低时延、大容量等特点,为智能交通、工业互联网和物联网等领域提供支持。无线局域网标准:主要是 IEEE802.11 标准,也就是我们常说的 Wi - Fi。例如 IEEE802.11ac 和 IEEE802.11ax(Wi-Fi 6)等标准,不断提升无线局域网的传输速度和稳定性。短距离无线通信标准:包括蓝牙(Bluet
    Jeffreyzhang123 2025-01-02 14:33 43浏览
  • 前言近年来,随着汽车工业的快速发展,尤其是新能源汽车与智能汽车领域的崛起,汽车安全标准和认证要求日益严格,应用范围愈加广泛。ISO 26262和ISO 21448作为两个重要的汽车安全标准,它们在“系统安全”中扮演的角色各自不同,但又有一定交集。在智能网联汽车的高级辅助驾驶系统(ADAS)应用中,理解这两个标准的区别及其相互关系,对于保障车辆的安全性至关重要。ISO 26262:汽车功能安全的基石如图2.1所示,ISO 26262对“功能安全”的定义解释为:不存在由于电子/电气系统失效引起的危害
    广电计量 2025-01-02 17:18 94浏览
  • 从无到有:智能手机的早期探索无线电话装置的诞生:1902 年,美国人内森・斯塔布菲尔德在肯塔基州制成了第一个无线电话装置,这是人类对 “手机” 技术最早的探索。第一部移动手机问世:1938 年,美国贝尔实验室为美国军方制成了世界上第一部 “移动” 手机。民用手机的出现:1973 年 4 月 3 日,摩托罗拉工程师马丁・库珀在纽约曼哈顿街头手持世界上第一台民用手机摩托罗拉 DynaTAC 8000X 的原型机,给竞争对手 AT&T 公司的朋友打了一个电话。这款手机重 2 磅,通话时间仅能支持半小时
    Jeffreyzhang123 2025-01-02 16:41 87浏览
  • 早期概念与探索阶段(19 世纪以前):在古代,人类就对自动机械充满了想象,如古希腊时期的希罗发明的自动门、水钟等自动装置,中国古代的指南车、木牛流马等,虽然这些装置不能称之为真正的机器人,但为后来机器人的发展奠定了思想基础。从概念走向实践阶段(19 世纪~20 世纪初):随着工业革命的到来,自动机概念开始与实际机械设计结合,出现了具有实际功能的自动机械,例如雅卡尔提花机等,可通过穿孔卡片控制编织图案,为后续可编程控制的机器人发展提供了灵感。现代机器人产业萌芽期(1920 年代~1950 年代):
    Jeffreyzhang123 2025-01-02 14:53 81浏览
  • 国际标准IPC 标准:IPC-A-600:规定了印刷电路板制造过程中的质量要求和验收标准,涵盖材料、外观、尺寸、焊接、表面处理等方面。IPC-2221/2222:IPC-2221 提供了用于设计印刷电路板的一般原则和要求,IPC-2222 则针对高可靠性电子产品的设计提供了进一步的指导。IPC-6012:详细定义了刚性基板和柔性基板的要求,包括材料、工艺、尺寸、层次结构、特征等。IPC-4101:定义了印刷电路板的基板材料的物理和电气特性。IPC-7351:提供了元件封装的设计规范,包括封装尺寸
    Jeffreyzhang123 2025-01-02 16:50 97浏览
  •  在这个日新月异的科技时代,智能家居正以前所未有的速度融入我们的日常生活,从智能灯光到温控系统,从安防监控到语音助手,每一处细节都透露着科技的温度与智慧。而在这场智能化浪潮中,一个看似不起眼却至关重要的组件——晶体管光耦,正扮演着连接物理世界与数字世界的隐形桥梁角色,默默推动着智能家居行业的发展与革新。 晶体管光耦——智能家居的“神经递质”晶体管光耦,作为一种能够将电信号转换为光信号,再通过光信号控制另一侧电路开关的电子元器件,其独特的工作原理使得它在隔离传输、抗干扰及保护电
    晶台光耦 2025-01-02 16:19 62浏览
  • 【工程师故事】+半年的经历依然忧伤,带着焦虑和绝望  对于一个企业来说,赚钱才是第一位的,对于一个人来说,赚钱也是第一位的。因为企业要活下去,因为个人也要活下去。企业打不了倒闭。个人还是要吃饭的。企业倒闭了,打不了从头再来。个人失业了,面对的不仅是房贷车贷和教育,还有找工作的焦虑。企业说,一个公司倒闭了,说明不了什么,这是正常的一个现象。个人说,一个中年男人失业了,面对的压力太大了,焦虑会摧毁你的一切。企业说,是个公司倒闭了,也不是什么大的问题,只不过是这些公司经营有问题吧。
    curton 2025-01-02 23:08 72浏览
  • 起源与诞生:AI 技术的起源可以追溯到 20 世纪 40 年代,随着计算机技术的兴起,科学家们开始思考如何让机器具备类似人类的智能。1950 年,英国数学家艾伦・图灵提出了著名的 “图灵测试”,为 AI 技术的发展奠定了理论基础。1956 年,美国达特茅斯学院举行了一次人工智能研讨会,标志着 AI 作为一门独立学科的诞生。符号主义阶段(20 世纪 50 年代 - 70 年代):研究人员主要关注如何使用符号逻辑和推理规则来模拟人类思维,试图通过构建复杂的逻辑系统来解决各种问题。然而,由于这种方法的
    Jeffreyzhang123 2025-01-02 15:15 81浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦