FPGA驱动SPI接口的LCD(三)——LCD的初始化

这篇具有很好参考价值的文章主要介绍了FPGA驱动SPI接口的LCD(三)——LCD的初始化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、跟据参考的STM32代码了解初始化流程 

LCD初始化函数

void LCD_Init(void);

 首先是LCD的复位

void LCD_RESET(void)
{
    LCD_RST_CLR;        //拉低复位引脚
    Delay_Ms(100);        //延时100ms    
    LCD_RST_SET;        //拉高复位引脚
    Delay_Ms(50);        //延时50ms
}

向LCD屏幕写入一个8位命令

void LCD_WR_REG(u8 data)

   LCD_CS_CLR;     //拉低片选引脚
     LCD_RS_CLR;      //拉低dc引脚
   SPI_WriteByte(SPI1,data);        //使用硬件SPI写入一个字节的数据  
   LCD_CS_SET;        //拉高片选引脚
}

将8位数据写入LCD屏幕

void LCD_WR_DATA(u8 data)
{
   LCD_CS_CLR;     //拉低片选引脚
     LCD_RS_SET;     //拉高dc引脚
   SPI_WriteByte(SPI1,data);        //使用硬件SPI写入一个字节的数据
   LCD_CS_SET;        //拉高片选引脚
}

设置液晶显示屏的显示方向

void LCD_direction(u8 direction);

清屏,也就是整个屏幕的点都为白色

void LCD_Clear(u16 Color);

LCD显示窗口设置

void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd);

二、模块框图

FPGA驱动SPI接口的LCD(三)——LCD的初始化

 文章来源地址https://www.toymoban.com/news/detail-427685.html

三、设计状态机

FPGA驱动SPI接口的LCD(三)——LCD的初始化

1、初始化命令

初始化命令是厂家已经配置好的,直接调用这部分就行了。 

    LCD_WR_REG(0xCF);  
    LCD_WR_DATA(0x00); 
   (省略~)
    LCD_WR_DATA(0xef);     
    LCD_WR_REG(0x11); //Exit Sleep
    Delay_Ms(120);
    LCD_WR_REG(0x29); //display on

2、设置LCD显示方向

为了方便省事,只考虑参考代码中液晶屏顺时针旋转方向为0的情况。

#define USE_HORIZONTAL       0//定义液晶屏顺时针旋转方向     0-0度旋转,1-90度旋转,2-180度旋转,3-270度旋转

void LCD_direction(u8 direction)函数只需要知道LCD_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));

传输到lcd_write模块的数据(最高位决定命令/数据,0为命令,1为数据)为9'h036和9'h108。

3、清屏

lcd的清屏步骤是先设置LCD的填充窗口大小(320x240)

9'h02A;        //列地址设置
{1'b1,7'b0000_000,start_x[8]};        //x的开始坐标高8位
{1'b1,start_x[7:0]};                           //x的开始坐标低8位
{1'b1,7'b0000_000,end_x[8]};         //x的结束坐标高8位                
{1'b1,end_x[7:0]};                            //x的结束坐标低8位
9'h02B;        //页面地址设置
{1'b1,7'b0000_000,start_y[8]};        //y的开始坐标高8位
{1'b1,start_y[7:0]};                           //y的开始坐标低8位
{1'b1,7'b0000_000,end_y[8]};         //y的结束坐标高8位
{1'b1,end_y[7:0]};                            //y的结束坐标低8位
9'h02C;        //存储器写入

清屏的时候设置的窗口大小(320x240)和start_x、start_y、end_x、end_y已经确定,可以直接用以下部分。

9'h02A
9'h100
9'h100
9'h100
9'h1ef
9'h02B
9'h100
9'h100
9'h101
9'h13f
9'h02C

然后在需要填充的点进行对应颜色(白色)的填充。颜色填充为16位,先传高8位,再传低8位。

一共传输320*240*2-1=153,599次。

四、波形图绘制

FPGA驱动SPI接口的LCD(三)——LCD的初始化

 FPGA驱动SPI接口的LCD(三)——LCD的初始化

 FPGA驱动SPI接口的LCD(三)——LCD的初始化

 五、代码编写

module lcd_init
// #(//仿真时调用
    // parameter   TIME100MS    = 23'd100,  //23'd5000_000  
                // TIME150MS    = 23'd150,  //23'd7500_000  
                // TIME120MS    = 23'd120,  //23'd6000_000  
                // TIMES4MAX    = 18'd51 ,  //320*240*2+13(设置窗口大小)=153_613 
                // DATA_IDLE    = 9'b0_0000_0000
// )
#(//驱动lcd时调用
    parameter   TIME100MS    = 23'd5000_000,  //23'd5000_000  
                TIME150MS    = 23'd7500_000,  //23'd7500_000  
                TIME120MS    = 23'd6000_000,  //23'd6000_000  
                TIMES4MAX    = 18'd153_613 ,  //320*240*2+13(设置窗口大小)=153_613   
                DATA_IDLE    = 9'b0_0000_0000
)
(
    input   wire            sys_clk_50MHz ,
    input   wire            sys_rst_n     ,
    input   wire            wr_done       ,
    
    
    output  reg             lcd_rst       ,
    output  reg     [8:0]   init_data     ,
    output  wire            en_write      ,
    output  wire            init_done
);
//****************** Parameter and Internal Signal *******************//
//画笔颜色
parameter   WHITE   = 16'hFFFF,
            BLACK   = 16'h0000,	  
            BLUE    = 16'h001F,  
            BRED    = 16'hF81F,
            GRED 	= 16'hFFE0,
            GBLUE	= 16'h07FF,
            RED     = 16'hF800,
            MAGENTA = 16'hF81F,
            GREEN   = 16'h07E0,
            CYAN    = 16'h7FFF,
            YELLOW  = 16'hFFE0,
            BROWN 	= 16'hBC40, //棕色
            BRRED 	= 16'hFC07, //棕红色
            GRAY  	= 16'h8430; //灰色

//----------------------------------------------------------------- 
reg [5:0]   state;
parameter   S0_DELAY100MS         = 6'b000_001, 
            S1_DELAY50MS          = 6'b000_010,
            S2_WR_90              = 6'b000_100,
            S3_DELAY120MS         = 6'b001_000,
            S4_WR_DIRECTION_CLEAR = 6'b010_000,
            DONE                  = 6'b100_000;
            
reg [22:0]  cnt_150ms;
reg         lcd_rst_high_flag;
reg [6:0]   cnt_s2_num;
reg         cnt_s2_num_done; 
reg [17:0]  cnt_s4_num;
reg         cnt_s4_num_done;   

//----------------------------------------------------------------- 
//状态跳转            
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        state <= S0_DELAY100MS;
    else
        case(state)
            S0_DELAY100MS:
                state <= (cnt_150ms == TIME100MS) ? S1_DELAY50MS : S0_DELAY100MS;
            S1_DELAY50MS:
                state <= (cnt_150ms == TIME150MS) ? S2_WR_90 : S1_DELAY50MS;
            S2_WR_90:
                state <= (cnt_s2_num_done) ? S3_DELAY120MS : S2_WR_90;
            S3_DELAY120MS:
                state <= (cnt_150ms == TIME120MS) ? S4_WR_DIRECTION_CLEAR : S3_DELAY120MS; 
            S4_WR_DIRECTION_CLEAR:
                state <= (cnt_s4_num_done) ? DONE : S4_WR_DIRECTION_CLEAR;
            DONE:
                state <= DONE;
            default:
                state <= S0_DELAY100MS;
        endcase

//cnt_150ms
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_150ms <= 23'd0;
    else if(state == S0_DELAY100MS || state == S1_DELAY50MS || state == S3_DELAY120MS )
        cnt_150ms <= cnt_150ms + 1'b1;
    else
        cnt_150ms <= 23'd0;
        
//lcd_rst_high_flag
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        lcd_rst_high_flag <= 1'b0;
    else if(state == S0_DELAY100MS && (cnt_150ms == TIME100MS - 1'b1))
        lcd_rst_high_flag <= 1'b1;
    else
        lcd_rst_high_flag <= 1'b0;

//lcd_rst
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        lcd_rst <= 1'b0;
    else if(lcd_rst_high_flag)
        lcd_rst <= 1'b1;
    else
        lcd_rst <= lcd_rst;
//----------------------------------------------------------------- 
//cnt_s2_num决定要传的命令/数据
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_s2_num <= 7'd0;
    else if(state != S2_WR_90)
        cnt_s2_num <= 7'd0;
    else if(wr_done && state == S2_WR_90)
        cnt_s2_num <= cnt_s2_num + 1'b1;
    else
        cnt_s2_num <= cnt_s2_num;

//cnt_s2_num_done == 1'b1则S2_WR_90完成
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_s2_num_done <= 1'b0;
    else if(cnt_s2_num == 7'd89 && wr_done == 1'b1)
        cnt_s2_num_done <= 1'b1;
    else
        cnt_s2_num_done <= 1'b0;
        
//init_data[8:0]
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        init_data <= DATA_IDLE;
    else if(state == S2_WR_90)
        //初始化命令/数据,直接借用厂家的
        case(cnt_s2_num)    //init_data[8] == 1'b1写数据; == 1'b0写命令
                                        7'd0 :  init_data <= 9'h0CF ; 
            7'd1 :  init_data <= 9'h100 ;                        
            7'd2 :  init_data <= 9'h1C9 ;                        
            7'd3 :  init_data <= 9'h130 ;                        
                                        7'd4 :  init_data <= 9'h0ED ;  
            7'd5 :  init_data <= 9'h164 ;                        
            7'd6 :  init_data <= 9'h103 ;                        
            7'd7 :  init_data <= 9'h112 ;                        
            7'd8 :  init_data <= 9'h181 ;                        
                                        7'd9 :  init_data <= 9'h0E8 ;  
            7'd10:  init_data <= 9'h185 ;                        
            7'd11:  init_data <= 9'h110 ;                        
            7'd12:  init_data <= 9'h17A ;                        
                                        7'd13:  init_data <= 9'h0CB ;  
            7'd14:  init_data <= 9'h139 ;                        
            7'd15:  init_data <= 9'h12C ;                        
            7'd16:  init_data <= 9'h100 ;                        
            7'd17:  init_data <= 9'h134 ;                        
            7'd18:  init_data <= 9'h102 ;                        
                                        7'd19:  init_data <= 9'h0F7 ;  
            7'd20:  init_data <= 9'h120 ;                        
                                        7'd21:  init_data <= 9'h0EA ;  
            7'd22:  init_data <= 9'h100 ;                        
            7'd23:  init_data <= 9'h100 ;                        
                                        7'd24:  init_data <= 9'h0C0 ;  
            7'd25:  init_data <= 9'h11B ;                        
                                        7'd26:  init_data <= 9'h0C1 ;  
            7'd27:  init_data <= 9'h100 ;                        
                                        7'd28:  init_data <= 9'h0C5 ;  
            7'd29:  init_data <= 9'h130 ;                        
            7'd30:  init_data <= 9'h130 ;                        
                                        7'd31:  init_data <= 9'h0C7 ;  
            7'd32:  init_data <= 9'h1B7 ;                        
                                        7'd33:  init_data <= 9'h036 ;  
            7'd34:  init_data <= 9'h108 ;                        
                                        7'd35:  init_data <= 9'h03A ;  
            7'd36:  init_data <= 9'h155 ;                        
                                        7'd37:  init_data <= 9'h0B1 ;  
            7'd38:  init_data <= 9'h100 ;                        
            7'd39:  init_data <= 9'h11A ;                        
                                        7'd40:  init_data <= 9'h0B6 ;  
            7'd41:  init_data <= 9'h10A ;                        
            7'd42:  init_data <= 9'h1A2 ;                        
                                        7'd43:  init_data <= 9'h0F2 ;  
            7'd44:  init_data <= 9'h100 ;                        
                                        7'd45:  init_data <= 9'h026 ;  
            7'd46:  init_data <= 9'h101 ;                        
                                        7'd47:  init_data <= 9'h0E0 ;  
            7'd48:  init_data <= 9'h10F ;                        
            7'd49:  init_data <= 9'h12A ;                        
            7'd50:  init_data <= 9'h128 ;                        
            7'd51:  init_data <= 9'h108 ;                        
            7'd52:  init_data <= 9'h10E ;                        
            7'd53:  init_data <= 9'h108 ;                        
            7'd54:  init_data <= 9'h154 ;                        
            7'd55:  init_data <= 9'h1A9 ;                        
            7'd56:  init_data <= 9'h143 ;                        
            7'd57:  init_data <= 9'h10A ;                        
            7'd58:  init_data <= 9'h10F ;                        
            7'd59:  init_data <= 9'h100 ;                        
            7'd60:  init_data <= 9'h100 ;                        
            7'd61:  init_data <= 9'h100 ;                        
            7'd62:  init_data <= 9'h100 ;                        
                                        7'd63:  init_data <= 9'h0E1 ;  
            7'd64:  init_data <= 9'h100 ;                        
            7'd65:  init_data <= 9'h115 ;                        
            7'd66:  init_data <= 9'h117 ;                        
            7'd67:  init_data <= 9'h107 ;                        
            7'd68:  init_data <= 9'h111 ;                        
            7'd69:  init_data <= 9'h106 ;                        
            7'd70:  init_data <= 9'h12B ;                        
            7'd71:  init_data <= 9'h156 ;                        
            7'd72:  init_data <= 9'h13C ;                        
            7'd73:  init_data <= 9'h105 ;                        
            7'd74:  init_data <= 9'h110 ;                        
            7'd75:  init_data <= 9'h10F ;                        
            7'd76:  init_data <= 9'h13F ;                        
            7'd77:  init_data <= 9'h13F ;                        
            7'd78:  init_data <= 9'h10F ;                        
                                        7'd79:  init_data <= 9'h02B ;  
            7'd80:  init_data <= 9'h100 ;                        
            7'd81:  init_data <= 9'h100 ;                        
            7'd82:  init_data <= 9'h101 ;                        
            7'd83:  init_data <= 9'h13f ;                        
                                        7'd84:  init_data <= 9'h02A ;  
            7'd85:  init_data <= 9'h100 ;                        
            7'd86:  init_data <= 9'h100 ;                        
            7'd87:  init_data <= 9'h100 ;                        
            7'd88:  init_data <= 9'h1ef ;                        
                                        7'd89:  init_data <= 9'h011 ;  
            default: init_data <= DATA_IDLE;
        endcase
        
    else if(state == S4_WR_DIRECTION_CLEAR)
        case(cnt_s4_num)
            'd0 :  init_data <= 9'h029;
            //设置LCD显示方向
            'd1 :  init_data <= 9'h036;
            'd2 :  init_data <= 9'h108;
            
            //LCD显示窗口设置
            'd3 :  init_data <= 9'h02a;
                             
            'd4 :  init_data <= 9'h100;
            'd5 :  init_data <= 9'h100;
            'd6 :  init_data <= 9'h100;
            'd7 :  init_data <= 9'h1ef;
                             
            'd8 :  init_data <= 9'h02b;
                             
            'd9 :  init_data <= 9'h100;
            'd10:  init_data <= 9'h100;
            'd11:  init_data <= 9'h101;
            'd12:  init_data <= 9'h13f;
                             
            'd13:  init_data <= 9'h02c;
            
            //填充对应点的颜色,可以换用比较明显的红色,便于观察现象
            default : 
                //当cnt_s4_num大于14且为偶数时,传输颜色数据的高8位
                if(cnt_s4_num >= 'd14 && cnt_s4_num[0] == 0)
                    init_data <= {1'b1,WHITE[15:8]};
                //当cnt_s4_num大于14且为奇数时,传输颜色数据的低8位
                else if(cnt_s4_num >= 'd14 && cnt_s4_num[0] == 1)
                    init_data <= {1'b1,WHITE[7:0]};
                else
                    init_data <= DATA_IDLE;
        endcase
    else
        init_data <= DATA_IDLE;

//cnt_s4_num决定要传的命令/数据
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_s4_num <= 18'd0;
    else if(state != S4_WR_DIRECTION_CLEAR)
        cnt_s4_num <= 18'd0;
    else if(wr_done && state == S4_WR_DIRECTION_CLEAR)
        cnt_s4_num <= cnt_s4_num + 1'b1;
    else                   
        cnt_s4_num <= cnt_s4_num;

//cnt_s4_num_done
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_s4_num_done <= 1'b0;
    else if(cnt_s4_num == TIMES4MAX && wr_done == 1'b1)
        cnt_s4_num_done <= 1'b1;
    else
        cnt_s4_num_done <= 1'b0;  
        
assign en_write = (state == S2_WR_90 || state == S4_WR_DIRECTION_CLEAR) ? 1'b1 : 1'b0;      

assign init_done = (state == DONE) ? 1'b1 : 1'b0;        
        
endmodule

六、仿真代码

`timescale 1ns/1ns

module tb_lcd_init();

reg             sys_clk_50MHz;
reg             sys_rst_n    ;
reg             wr_done      ;

wire            lcd_rst      ;
wire    [8:0]   init_data    ;
wire            en_write     ;
wire            init_done    ;

reg     [1:0]   cnt1;

initial
begin
    sys_clk_50MHz <= 1'b1;
    sys_rst_n     <= 1'b0;
    wr_done       <= 1'b0;
    #100
    sys_rst_n     <= 1'b1;
end

always #10 sys_clk_50MHz <= ~sys_clk_50MHz;

always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt1 <= 'd0;
    else if(en_write)
        cnt1 <= cnt1 + 1'b1;

always@(posedge sys_clk_50MHz or negedge sys_rst_n)
    if(!sys_rst_n)
        wr_done <= 1'b0;
    else if(cnt1 == 'd3)
        wr_done <= 1'b1;
    else
        wr_done <= 1'b0;

lcd_init    lcd_init_inst
(
    .sys_clk_50MHz (sys_clk_50MHz),
    .sys_rst_n     (sys_rst_n    ),
    .wr_done       (wr_done      ),
    
    .lcd_rst       (lcd_rst      ),
    .init_data     (init_data    ),
    .en_write      (en_write     ),
    .init_done     (init_done    )
);

endmodule

七、仿真波形图

FPGA驱动SPI接口的LCD(三)——LCD的初始化

 

到了这里,关于FPGA驱动SPI接口的LCD(三)——LCD的初始化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 1.3寸OLED模块初始化,驱动芯片为SH1106,i2c通讯

    之前使用过0.96寸的OLED,驱动芯片SSD1306,看了下两个芯片数据手册,差异不是很大,买了一个1.3寸的,花了一个下午点亮了,在过程中遇到了些问题,网上的资料不多,于是做个总结。 主要遇到的问题有, 1.显示不正常,出现花屏等现象。 从我遇到的情况来说,出现花屏可

    2024年02月12日
    浏览(34)
  • 【开篇】STM32F103C8T6 含义、命名规则、GPIO原理以及初始化(参考男神江科协,学习交流用)

    目录 目录 一,STM系列命名规则 二.引脚功能 三.电路以及寄存器 1.产品系列:         STM32代表意法半导体的Cortex-Mx系列内核(ARM)32位的MCU 2.产品类型: F-通用型,S-简单型,L-低功耗,H-高性能,AL-汽车应用低功耗型,AF-汽车应用通用型。 3.产品子系列: 103:ARM Cortex-M3内核

    2024年01月17日
    浏览(74)
  • Hive初始化异常:org.apache.hadoop.hive.metastore.HiveMetaException: 加载驱动程序大数据失败

    近年来,随着大数据技术的快速发展,越来越多的企业开始关注和运用大数据处理和分析。然而,在使用Hive进行大数据处理时,有时会遇到一些问题,比如在初始化过程中出现了加载驱动程序大数据失败的异常。本文将介绍这个异常的原因和解决方法,并提供相应的源代码示

    2024年02月04日
    浏览(33)
  • Hive初始化遇到的问题:org.apache.hadoop.hive.metastore.HiveMetaException: 失败加载驱动程序

    Hive初始化遇到的问题:org.apache.hadoop.hive.metastore.HiveMetaException: 失败加载驱动程序 在大数据领域,Hive是一个常用的数据仓库工具,它构建在Hadoop之上,提供了一种类似于SQL的查询语言,用于处理大规模的数据集。然而,有时在Hive的初始化过程中,可能会遇到一些错误。其中

    2024年02月08日
    浏览(42)
  • ZedBoard+AD9361_FPGA的PL端纯逻辑(verilog)配置控制9361(一)_初始化寄存器脚本文件生成

    由于9361的寄存器较多,首先利用AD936X Evaluation Software 软件,根据我们的项目需求,配置相应的功能参数,生成寄存器参数配置文件。 我建议大家选择安装AD936X Evaluation Software 2.1.3版本,下载安装软件,一路点击下一步即可完成安装。软件安装包:百度网盘  提取码:mww7 安装

    2024年02月13日
    浏览(35)
  • Pytorch权重初始化/参数初始化

    refer: 【Pytorch】各网络层的默认初始化方法 https://blog.csdn.net/guofei_fly/article/details/105109883 其实Pytorch初始化方法就在各自的层的 def reset_parameters(self) - None: 方法中。 有人可能会问 为什么这个方法和Pytorch直接出来的权重初始值不一样 ?单步调试会发现其实这个方法运行了至少两

    2024年02月11日
    浏览(53)
  • Linux内存初始化-启动阶段的内存初始化

    本文代码基于ARM64平台, Linux kernel 5.15 在加载kernel 之前, kernel对于系统是有一定要求的,明确规定了boot阶段必须要把MMU关闭: 那么在进入kernel之后, 就必须有一个使能MMU, 建立映射的过程, 本文描述kernel启动阶段进行内存初始化相关的操作。 在初始化阶段,我们mapping二段

    2024年02月08日
    浏览(71)
  • 深度学习参数初始化(二)Kaiming初始化 含代码

    目录 一、介绍 二、基础知识 三、Kaiming初始化的假设条件  四、Kaiming初始化的简单的公式推导 1.前向传播 2.反向传播 五、Pytorch实现 深度学习参数初始化系列: (一)Xavier初始化 含代码 (二)Kaiming初始化 含代码         Kaiming初始化论文地址:https://arxiv.org/abs/1502.01

    2024年02月04日
    浏览(66)
  • 【温故而知新】JavaScript初始化/初始化加载

    在JavaScript中,对象、数组、函数、类等都可以通过不同的方式进行初始化。以下是几种常见的初始化方式: 对象初始化: 使用字面量方式: 使用构造函数方式: 数组初始化: 使用字面量方式: 使用构造函数方式: 函数初始化: 类初始化: 使用Array的of和from方法进行数组

    2024年01月24日
    浏览(59)
  • 【随机种子初始化】一个神经网络模型初始化的大坑

    半年前写了一个模型,取得了不错的效果(简称项目文件1),于是整理了一番代码,保存为了一个新的项目(简称项目文件2)。半年后的今天,我重新训练这个整理过的模型,即项目文件2,没有修改任何的超参数,并且保持完全一致的随机种子,但是始终无法完全复现出半

    2024年02月09日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包