单片机第二季:温度传感器DS18B20

这篇具有很好参考价值的文章主要介绍了单片机第二季:温度传感器DS18B20。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1,DS18B20介绍

2,DS18B20数据手册 

2.1,初始化时序 

2.2,读写时序 

3,DS18B20工作流程

4,代码


 

1,DS18B20介绍

DS18B20的基本特征:
(1)内置集成ADC,外部数字接口,也就是可以直接与单片机的数字接口连接,DS18B20 在使用中不需要任何外围元件,全部传感元件及转换电路集成在形如一只三极管的集成电路内;
(2)单总线数字接口,布线成本低,独特的单线接口方式,DS18B20 在与微处理器连接时仅需要一条线即可实现微处理器与DS18B20 的双向通讯;
(3)温范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃;
(4)数字值温度分辨率位数可软件设置,可根据需要设置分辨率位数,可编程的分辨率为9~12 位,对应的可分辨温度分别为0.5℃、0.25℃、0.125℃ 和0.0625℃,可实现高精度测温;
(5)温度阈值报警功能,且阈值可内置存储掉电不丢失;
(6)在9 位分辨率时最多在93.75ms 内把温度转换为数字,12 位分辨率时最多在750ms 内把温度值转换为数字,速度更快,DS18B20温度采集是由主CPU控制,需要采集温度时才工作;
(7)内置唯一64位序列码,CPU可以单线串联无限多个DS18B20,CPU通过序列码识别与哪个DS18B20通信,DS18B20 支持多点组网功能,多个DS18B20 可以并联在唯一的三线上,实现组网多点测温;
(8)支持VDD供电,或通过数据总线及内部电容实现寄生电源供电,也就是可以通过数据线(DQ)来供电,如果通过数据线供电,数据线在不传输数据时,需要拉高,否则如果内部电容没电时DS18B20就不能工作了;

(9)测量结果直接输出数字温度信号,以"一根总线"串行传送给CPU,同时可传送CRC 校验码,具有极强的抗干扰纠错能力 

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

使用到的三根线是GND(接地)、DQ(数据线)、VCC(电源线),当然也可以只使用GND和DQ。 

综合评价:
(1)DS18B20是很多年前的东西了;
(2)现在趋向于温度+湿度的综合传感器;
(3)现实应用一般低端用热敏电阻、热电偶,高端用精密传感器;
(4)学习重点和难点是单总线协议的时序编程实现;

2,DS18B20数据手册 

DS18B20数据手册

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

上图为DS18B20的内部框图。内部的64位的ROM存储其独一无二的序列号。暂存存储器(The scratchpad memory)包含了存储有数字温度结果的2个字节宽度的温度寄存器。另外,暂存存储器还提供了一个字节的过温和低温(TH和TL)温度报警寄存器和一个字节的配置寄存器。配置寄存器允许用户自定义温度转换为9、10、11、12位精度。过温和低温(TH和TL)温度报警寄存器是非易失性的(EEPROM),所以其可以在设备断电的情况下保存。

DS18B20的另外一个特性就是可以无需外部电源供电。当数据线DQ为高的时候由其为设备供电。总线拉高的时候为内部电容(Spp)充电,当总线拉低是由该电容向设备供电。这种由1-Wire总线为设备供电的方式称为“寄生电源”。此外,DS18B20也可以由外部电源通过VDD供电。

DS18B20的核心功能是直接温度-数字测量。其温度转换可由用户自定义为9、10、11、12位精度分别为0.5℃、0.25℃、0.125℃、0.0625℃分辨率。值得注意的是,上电默认为12位转换精度。DS18B20上电后工作在低功耗闲置状态下。主设备必须向DS18B20发送温度转换命令[44h]才能开始温度转换。温度转换后,温度转换的值将会保存在暂存存储器的温度寄存器中,并且DS18B20将会恢复到闲置状态。如果DS18B20是由外部供电,当发送完温度转换命令[44h]后,主设备可以执行“读数据时序”,若此时温度转换正在进行DS18B20将会响应“0”,若温度转换完成则会响应“1”。如果DS18B20是由“寄生电源”供电,该响应的技术将不能使用,因为在整个温度转换期间,总线必须强制拉高。  

ROM 中的64 位序列号是出厂前被光刻好的,它可以看作是该DS18B20 的地址序列号。64 位光刻ROM 的排列是:开始8 位(28H)是产品类型标号,接着的48 位是该DS18B20 自身的序列号,最后8 位是前面56 位的循环冗余校验码。光刻ROM 的作用是使每一个DS18B20 都各不相同,这样就可以实现一根总线上挂接多个DS18B20 的目的。 

DS18B20 温度传感器的内部存储器包括一个高速的暂存器RAM 和一个非易失性的可电擦除的EEPROM,后者存放高温度和低温度触发器TH、TL 和配置寄存器。 

配置寄存器是配置不同的位数来确定温度和数字的转化,配置寄存器结构如下: 

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

低五位一直都是"1",TM 是测试模式位,用于设置DS18B20 在工作模式还是在测试模式。在DS18B20 出厂时该位被设置为0,用户不需要去改动。R1 和R0 用来设置DS18B20 的精度(分辨率),可设置为9,10,11 或12 位,对应的分辨率温度是0.5℃,0.25℃,0.125℃和0.0625℃。R0 和R1 配置如下图: 

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

在初始状态下默认的精度是12 位,即R0=1、R1=1。高速暂存存储器由9 个字节组成,其分配如下: 

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

当温度转换命令(44H)发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0 和第1 个字节。存储的两个字节,高字节的前5 位是符号位S,单片机可通过单线接口读到该数据,读取时低位在前,高位在后,数据格式如下: 

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

如果测得的温度大于0,这5 位为‘ 0’,只要将测到的数值乘以0.0625(默认精度是12 位)即可得到实际温度;如果温度小于0,这5 位为‘ 1’,测到的数值需要取反加1 再乘以-0.0625 即可得到实际温度。温度与数据对应关系如下: 

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

比如我们要计算+85 度,数据输出十六进制是0X0550,因为高字节的高5位为0,表明检测的温度是正温度,0X0550 对应的十进制为1360,将这个值乘以12 位精度0.0625,所以可以得到+85 度。 

知道了怎么计算温度,接下来我们就来看看如何读取温度数据,由于DS18B20是单总线器件,所有的单总线器件都要求采用严格的信号时序,以保证数据的完整性。DS18B20 时序包括如下几种:初始化时序、写(0 和1)时序、读(0和1)时序。DS18B20 发送所有的命令和数据都是字节的低位在前。这里我们简单介绍这几个信号的时序: 

2.1,初始化时序 

单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us(该时间的范围可以从480 到960 微妙),以产生复位脉冲。接着主机释放总线,外部的上拉电阻将单总线拉高,延时15~60 us,并进入接收模式。接着DS18B20 拉低总线60~240 us,以产生低电平应答脉冲,若为低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要
480 微妙。初始化时序图如下:

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

注意:主机释放总线是指主机将这个port置1,因为port置1后可以被从设备拉低,但如果port被置0,就不能被从设备拉高,因此释放总线是将这个port置1。

由上述初始化时序,编写初始化函数代码:

//DS18B20初始化
unsigned char ds18b20_init()
{
	DSPORT = 0; //主设备拉低总线,发送复位脉冲,持续时间超过480us

	void delay500us(void)   //误差 -0.859028845284us
	{
	    unsigned char a,b;
	    for(b=1;b>0;b--)
	        for(a=227;a>0;a--);
	}

	DSPORT = 1;   //释放总线

    unsigned char i = 0;
	while(DSPORT)	  //检测DS18B20是否在一定时间内拉低总线,
				      //根据时序图判断最长时间为300us
	{
	   if(i>20)
	   {
	   		return 0; //超过一定时间总线未被拉低,说明DS18B20没有发送存在脉冲
	   }

	   void delay20us(void)   //误差 -0.468396780902us
		{
		    unsigned char a,b;
		    for(b=3;b>0;b--)
		        for(a=1;a>0;a--);
		}

		i++;
	}

	return 1;   //DS18B20在一定时间内响应了		

}

初始化就是,主机发送复位脉冲,从机发送存在脉冲,双方都收到后,初始化完成。

2.2,读写时序 

下图为写时序图:

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

写时序有两种情况:“写1”时段和“写0”时段。主设备通过写1时段来向DS18B20中写入逻辑1以及通过写0时段来向DS18B20中写入逻辑0。每个写时段最小必须有60us的持续时间且独立的写时段间至少有1us的恢复时间。

为了形成写1时段,在将1-Wire总线拉低后,主设备必须在15us之内释放总线。当总线释放后,5kΩ的上拉电阻将总线拉至高。为了形成写0时段,在将1-Wire总线拉低后,在整个时段期间主设备必须一直拉低总线(至少60us)。

在主设备初始化写时段后,DS18B20将会在15us至60us的时间窗口内对总线进行采样。如果总线在采样窗口期间是高电平,则逻辑1被写入DS18B20;若总线是低电平,则逻辑0被写入DS18B20。

写时序对应代码:

//DS18B20写命令函数

void ds18b20_write(unsigned char data)
{
	unsigned char i,j;

	for(j = 0;j<8;j++)
	{
	 	DSPORT = 0;  //拉低总线,开始写时序,至少1us
		i++;
		DSPORT = data & 0x01; //从低字节开始
		
		void delay65us(void)   //持续至少60us
		{
		    unsigned char a;
		    for(a=28;a>0;a--);
		}

		DSPORT = 1;   //一个写周期后,至少间隔1us给总线恢复时间
		data >>= 1;   //数据左移1位
	}
}

下图为读时序图: 

单片机第二季:温度传感器DS18B20,单片机,嵌入式硬件

仅在读时段期间DS18B20才能向主设备传送数据。因此,主设备在执行完读暂存寄存器[BEh]或读取供电模式[B4h]后,必须及时地生成读时段,这样DS18B20才能提供所需的数据。此外,主设备可以在执行完转换温度[44h]或拷贝EEPROM[B8h]命令后生成读时段,以便获得在“DS18B20功能命令”章节中提到的操作信息。

每个读时段最小必须有60us的持续时间且独立的写时段间至少有1us的恢复时间。读时段通过主设备将总线拉低超过1us再释放总线来实现初始化。当主设备初始化完读时段后,DS18B20将会向总线发送0或者1。DS18B20通过将总线拉至高来发送逻辑1,将总线拉至低来发送逻辑0。当发送完0后,DS18B20将会释放总线,则通过上拉电阻该总线将会恢复到高电平的闲置状态。从DS18B20中输出的数据在初始化读时序后仅有15us的有效时间。因此,主设备在开始改读时段后的15us之内必须释放总线,并且对总线进行采样。

//DS18B20 读命令函数

unsigned char DS18B20_read()
{
   unsigned char byte,bi;
   unsigned char i,j;

   for(j=0; j<8; j++)
   {
   	 DSPORT = 0;  //拉低总线,开始时序
	 i++;
	 DSPORT = 1;  //释放总线

	 void delay6us(void)   //延时6us等待总线上数据稳定
	{
	    unsigned char a;
	    for(a=1;a>0;a--);
	}

	bi = DSPORT;		  //要在15us内读取
	byte = (byte>>1)|(bi<<7);

	void delay45us(void)   //延时至少45us
	{
	    unsigned char a;
	    for(a=19;a>0;a--);
	}
   }
   return byte;
}

3,DS18B20工作流程

温度获取流程: 

DS18B20不会主动进行温度测量, 需要主控主动发起温度转换命令,这是因为温度转换本身需要耗电的,所以设计为平时待机,收到温度转换命令后才会进行温度AD转换;

主控和DS18B20之间通讯是分周期的,让DS18B20进行温度转换就是一个周期。周期包含初始化和N个命令(每个周期的开始都有初始化);

初始化主要探测目标DS18B20是否存在,若存在将芯片初始化;

命令很重要,DS18B20是一个典型的“命令-响应”型外设;这种外设的关键是命令集;

ROM操作指令:

DS18B20支持多个芯片串联在一个总线上,就是所谓的单总线协议,需要主控区分总线上多个DS18B20,因此需要ROM操作指令来完成这个任务;

ROM操作指令和温度采集一点关系都没有,所以当总线上只有一个DS18B20时,不需要管ROM操作指令;

系统中总线上有多个DS18B20,需要借助ROM操作指令来区分多个DS18B20,可能需要多条ROM操作指令来完成;

只有一个DS18B20时,使用SKIP ROM (0xCC)忽略;

功能指令:

ROM操作指令是为了在单总线上多个DS18B20中挑选那个我们要操作的DS18B20;

功能指令是为了和选定的DS18B20进行温度采样,常用温度转换指令和温度读取指令;

4,代码

时序代码: 

#include "timesires.h"
#include "uart.h"

void delay500us()   //误差 -0.859028845284us
{
    unsigned char a,b;
    for(b=1;b>0;b--)
        for(a=227;a>0;a--);
}

void delay20us(void)   //误差 -0.468396780902us
{
    unsigned char a,b;
    for(b=3;b>0;b--)
        for(a=1;a>0;a--);
}

void delay65us()   //持续至少60us
{
    unsigned char a;
    for(a=28;a>0;a--);
}

 void delay6us(void)   //延时6us等待总线上数据稳定
{
    unsigned char a;
    for(a=1;a>0;a--);
}

void delay45us(void)   //延时至少45us
{
    unsigned char a;
    for(a=19;a>0;a--);
}

void delay1ms(void)   //误差 -0.651041666667us
{
    unsigned char a,b;
    for(b=102;b>0;b--)
        for(a=3;a>0;a--);
}

void delay750ms(void)   //误差 -0.000000000171us
{
    unsigned char a,b,c;
    for(c=37;c>0;c--)
        for(b=66;b>0;b--)
            for(a=140;a>0;a--);
}


//DS18B20初始化
unsigned char ds18b20_init()
{
	unsigned char i = 0;
	DSPORT = 0; //主设备拉低总线,发送复位脉冲,持续时间超过480us

	delay500us();

	DSPORT = 1;   //释放总线

    
	while(DSPORT)	  //检测DS18B20是否在一定时间内拉低总线,
				      //根据时序图判断最长时间为300us
	{
	   if(i>20)
	   {
	   		return 0; //超过一定时间总线未被拉低,说明DS18B20没有发送存在脉冲
	   }

	   delay20us();

		i++;
	}

	return 1;   //DS18B20在一定时间内响应了		

}

//DS18B20写命令函数

void ds18b20_write(unsigned char cmd)
{
	unsigned char i = 0,j = 0;

	for(j = 0;j<8;j++)
	{
	 	DSPORT = 0;  //拉低总线,开始写时序,至少1us
		i++;
		DSPORT = cmd & 0x01; //从低字节开始
		
		delay65us();

		DSPORT = 1;   //一个写周期后,至少间隔1us给总线恢复时间
		cmd >>= 1;   //数据左移1位
	}
}

//DS18B20 读命令函数

unsigned char DS18B20_read()
{
   unsigned char byte = 0,bi = 0;
   unsigned char i = 0,j = 0;

   for(j=0; j<8; j++)
   {
   	 DSPORT = 0;  //拉低总线,开始时序
	 i++;
	 DSPORT = 1;  //释放总线

	delay6us();

	bi = DSPORT;		  //要在15us内读取
	byte = (byte>>1)|(bi<<7);

	delay45us();
   }
   return byte;
}

void DS18B20_changeTempCmd()
{
	ds18b20_init();
	delay1ms();		      //如果没有这个延时,读取的温度会有问题,用手捏着时在串口助手中看到的值不变
	ds18b20_write(0xcc);  //跳过ROM操作指令
	ds18b20_write(0x44);  //温度转换命令
	delay750ms();
	//delay750ms();
}

void DS18B20_readTempCmd()
{
   	ds18b20_init();
	delay1ms();
	ds18b20_write(0xcc);  //跳过ROM操作指令
	ds18b20_write(0xbe);  //温度读取命令
}

unsigned int DS18B20_Temp_Read()
{
   unsigned int temp = 0;
   unsigned char tmh = 0, tml = 0;
   DS18B20_changeTempCmd();
   DS18B20_readTempCmd();
   tml = DS18B20_read();
   tmh = DS18B20_read();

   temp = tmh;
   temp <<=8;
   temp |= tml;

   return temp;

}

串口代码:

#include "uart.h"


// 串口设置为: 波特率9600、数据位8、停止位1、奇偶校验无
// 使用的晶振是11.0592MHz的,注意12MHz和24MHz的不行
void uart_init(void)
{
	// 波特率9600
	SCON = 0x50;   	// 串口工作在模式1(8位串口)、允许接收
	PCON = 0x00;	// 波特率不加倍

	// 通信波特率相关的设置
	TMOD = 0x20;	// 设置T1为模式2
	TH1 = 253;
	TL1 = 253;	   	// 8位自动重装,意思就是TH1用完了之后下一个周期TL1会
					// 自动重装到TH1去

	TR1 = 1;		// 开启T1让它开始工作
//	ES = 1;
//	EA = 1;
}

// 通过串口发送1个字节出去
void uart_send_byte(unsigned char c)
{
   // 第1步,发送一个字节
   SBUF = c;

   // 第2步,先确认串口发送部分没有在忙
   while (!TI);

   // 第3步,软件复位TI标志位
   TI = 0;
}

void uart_send_adVal(unsigned int val)
{
	
	 uart_send_byte(val>>8);   //AD采样的数据为12位的,首先左移8位串口输出高4位
	 uart_send_byte(val);	   //再输出低8位
}

main.c

 

#include "timesires.h"
#include "uart.h"
#include <intrins.h>

void delay1s(void)   //误差 -0.000000000227us
{
    unsigned char a,b,c;
    for(c=13;c>0;c--)
        for(b=247;b>0;b--)
            for(a=142;a>0;a--);
    _nop_();  //if Keil,require use intrins.h
}

void main()
{
  unsigned int ret = 0;
  uart_init();
 
	while(1)
	{
		ret = DS18B20_Temp_Read();
		uart_send_adVal(ret);
		delay1s();
	}

}

代码完成后遇到一个问题:用手捏着DS18B20发现在串口调试助手中看到的值不变化,

原因:DS18B20_changeTempCmd()函数中,初始化后没有进行时间延迟,直接发送ROM操作命令ds18b20_write(0xcc),增加延迟函数后串口助手中显示值当用手捏着DS18B20会有变化。文章来源地址https://www.toymoban.com/news/detail-693857.html

到了这里,关于单片机第二季:温度传感器DS18B20的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 51单片机读取DS18B20温度传感器

    1 .首先我们知道DS18B20是 单总线协议 ,只有一根数据线。所以Data数据线即使发送端又是接收端,同时DS18B20内部接了弱上拉电阻(如图一所示),数据线默认为高电平。有了这些概念,我们就能进行下一步。                                                图一 (截取

    2024年02月08日
    浏览(41)
  • STC51单片机学习9--DS18B20温度传感器

    DS18B20是Dallas半导体公司的一款数字温度传感器芯片; DS18B20是一款支持 1-wire总线接口的温度传感器; DS18B20能测量的温度范围-55℃--125℃,精度是±0.5℃; DS18B20可以将分辨率设定为9到12位; DS18B20的工作电压范围3--5.5V 单片机的P4.1引脚用来接DS18B20的数据引脚 以下是友台半导体

    2024年02月12日
    浏览(54)
  • 【蓝桥杯-单片机学习笔记(十三)】DS18B20温度传感器

    一、温度传感器-DS18B20介绍 DS18B20是单总线数字化温度传感器,测量温度范围是-55℃~+125℃,在-10℃~+85℃范围内,精度为±0.5℃。支持3V~5.5V的供电电压范围。DS18B20可以程序设定9~12位的分辨率,精度为±0.5℃。 1.DS18B20内部结构 DS18B20内部结构主要由四部分组成:64位光刻ROM、温度

    2023年04月09日
    浏览(64)
  • 51单片机DS18B20温度传感器使用及数码管温度计、LCD1602温度显示代码详解

    温馨提示:读者若要彻底理解并会灵活使用DS18B20温度传感器,请详细阅读中文手册,并且对照代码注释充分分析代码。请不要觉得中文手册内容繁多!如能静心分析,定能深有体会,获益匪浅! 主函数操作顺序(执行序列) 功能指令 最后希望我的分享对你有所帮助!敬请关

    2024年02月12日
    浏览(53)
  • STM32单片机(五)第二节:EXTI外部中断练习(对射式红外传感器计次和旋转编码器计次)

    ❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋

    2024年02月09日
    浏览(47)
  • 单片机传感器类型一览

    一、单片机: c51、attiny85    arduino、stm8/stm32    esp8266、esp32、raspiberry pico 功能简单型:C51、Attiny85等 功能可以较复杂型:Arduino STM32 联网、人工智能等高级复杂型:esp8266 esp32、pico 二、基础元件(分为贴片式(SMT)和非贴片式): 晶振、电阻、电容、电感、led、开关、蜂鸣、

    2024年02月14日
    浏览(38)
  • 基于51单片机温湿度传感器

    DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通 空调;汽车;消费品;气象站;湿度调节器;除湿器;家电;医疗;自动控制 相对湿度和温度测量 全部校准,数字输出 长期稳定性 超长的信号传输距离:20米 超低能耗:休眠 4 引脚

    2023年04月10日
    浏览(91)
  • 51单片机 DHT11温湿度传感器 MQ2传感器

    目录 前言 程序思路 DHT11 一、DHT11基础储备  二、接口说明 三、协议及数据格式 ​编辑 四、DHT11代码 MQ-2烟雾传感器 一、MQ-2烟雾传感器介绍 二、工作原理 三、时序配置 四、指令配置 ​编辑 五、代码 LCD1602 一、LCD1602介绍 二、LCD1602指令介绍 ​编辑 三、LCD1602代码  HC-05 一

    2024年02月04日
    浏览(56)
  • 51单片机(DHT11温湿度传感器)

    DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通 空调;汽车;消费品;气象站;湿度调节器;除湿器;家电;医疗;自动控制 相对湿度和温度测量 全部校准,数字输出 长期稳定性 超长的信号传输距离:20米 超低能耗:休眠 4 引脚

    2024年02月02日
    浏览(72)
  • 51单片机驱动TCS3200颜色识别传感器

    TCS3200颜色传感器是一款全彩的颜色检测器,包括了一块TAOS TCS3200RGB感应芯片和4个白色LED灯,TCS3200能在一定的范围内检测和测量几乎所有的可见光。TCS3200有大量的光检测器,每个都有红绿蓝和清除4种滤光器。每种颜色滤光器均匀地按数组分布来清除颜色中偏移位置的颜色分

    2023年04月14日
    浏览(54)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包