STM32F103C8T6驱动DHT22温湿度传感器,通过OLED显示

学校课设,记录一下.

效果:

 

 DHT温湿度传感器部分代码

//dht22.h

#ifndef __DHT22_H
#define __DHT22_H
#include "sys.h"

//IO方向设置
#define DHT22_IO_IN()  {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=4<<4;}
#define DHT22_IO_OUT() {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=3<<4;}
IO操作函数											   
#define	DHT22_DQ_OUT PBout(9) //数据端口	PB9
#define	DHT22_DQ_IN  PBin(9)  //数据端口	PB9


u8 DHT22_Init(void);
u8 DHT22_Read_Data(u16 *temp,u16 *humi);
u8 DHT22_Read_Byte(void);
u8 DHT22_Read_Bit(void);
u8 DHT22_Check(void);
void DHT22_Rst(void);	
	
#endif


//dht22.c

#include "dht22.h"
#include "delay.h"


//如果使用ucosII,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//ucosII 使用	  
#endif

//复位DHT22
//主机信号
void DHT22_Rst(void)	   
{
	DHT22_IO_OUT();//SET OUTPUT
	DHT22_DQ_OUT=0;//拉低DQ
	delay_ms(1);//主机知道拉低500us
	DHT22_DQ_OUT=1;//DQ=1
	delay_us(30);//主机拉高20~40us
}

//等待DHT22的回应
//返回1:未检测到DHT22的存在
//返回0:DHT22已连接
//数据维持电平固定时间为80us左右,故等待时间为其2倍,即200us,观察200us之内
//检查电平状态是否会改变,先变低再变高
u8 DHT22_Check(void) 	   
{   
	u8 retry=0;
	DHT22_IO_IN();//SET INPUT	 
    while (DHT22_DQ_IN&&retry<200)//等待低电平
	{
		retry++;
		delay_us(1);
	}	 
	if(retry>=200)return 1;//如果retry大于200直接返回1
	else retry=0;
    while (!DHT22_DQ_IN&&retry<200)//DHT22拉低后会再次拉高80us左右
	{
		retry++;
		delay_us(1);
	}
	if(retry>=200)return 1;	    
	else return 0;
}

//从DHT22读取一个位
//返回值:1/0
u8 DHT22_Read_Bit(void) 			 
{
 	u8 retry=0;
	while(DHT22_DQ_IN&&retry<200)//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT22_DQ_IN&&retry<200)//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(DHT22_DQ_IN)return 1;
	return 0;		   
}
//从DHT22读取一个字节
//返回值:读到的数据
u8 DHT22_Read_Byte(void)    
{        
    u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT22_Read_Bit();
    }						    
    return dat;
}
//从DHT22读取一次数据
//temp:温度值(范围:-40~80°)
//humi:湿度值(范围:20%~100%)
//返回值:0,正常;1,读取失败DHT22连接断开
u8 DHT22_Read_Data(u16 *temp,u16 *humi)    
{        
 	u8 buf[5];
	u8 i,sum;
	DHT22_Rst();//等待响应
	if(DHT22_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT22_Read_Byte();
		}
//		*humi=buf[0]*256+buf[1];
//		*temp=buf[2]*256+buf[3];
		sum =((buf[0]+buf[1]+buf[2]+buf[3])&0xFF);
		if(sum==buf[4])//校验
		{
            
			*humi=buf[0]*256+buf[1];
			*temp=buf[2]*256+buf[3];
		}
	}else return 1;
	return 0;	    
}
//初始化DHT22的IO口 DQ 同时检测DHT22的存在
//返回1:不存在
//返回0:存在    	 
u8 DHT22_Init(void)
{	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PB端口时钟
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;				 //PB9端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);				 //初始化IO口
 	GPIO_SetBits(GPIOB,GPIO_Pin_9);						 //PB9 输出高
			    
	DHT22_Rst();  //复位DHT22
	return DHT22_Check();//等待DHT22的回应
} 


OLED

0.96'  四脚       GND VCC SCL SDA

//oled.h


#ifndef __OLED_H
#define	__OLED_H
 
#include "stm32f10x.h"
#include "sys.h"
 
#define I2C_SPEED           400000	
#define OWN_ADDRESS          0X77
#define OLED_ADDRESS         0X78 
#define OLED_I2C             I2C1

#define I2CT_FLAG_TIMEOUT         		((uint32_t)300)
#define I2CT_LONG_TIMEOUT         		((uint32_t)(10 * I2CT_FLAG_TIMEOUT))				
#define EEPROM_ERROR(fmt,arg...)       printf("<<-OLED-ERROR->> "fmt"\n",##arg)
 
 
void OLED_Init(void);
void WriteCmd(unsigned char I2C_Command);
void WriteDat(unsigned char I2C_Data);
 
void  Oled_WriteByte(u8 reg_add,u8 reg_dat);
void OLED_GRAM_FILL(unsigned char fill_Data);
void OLED_Refresh_Gram(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char fill_Data);
void OLED_CLS(void);// -- ??
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);
void OLED_ShowStr(u8 x,u8 y,const u8 *p,u8 size,u8 mode);
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char* BMP);
void OLED_draw_line(const u8 x0,const u8 y0,const float k,u8 mode);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
 
 
#endif




//oled.c

#include "oled.h"
#include  "oledfont.h"
/**
  ******************************************************************************
  * @file    
  * @author  
  * @version 
  * @date    
  * @brief   i2c OLED???
  ******************************************************************************
  * Function List:
  
	void OLED_Init(void);// -- OLED???? ?????PB6->SCL
                         //                         PB7->SDA
    uint32_t Write_Byte_to_OLED(u8 Cmd_or_Data,u8 Data)//??I2C?Cmd_or_Data??Data
	void WriteCmd(unsigned char I2C_Command);// -- ???
	void WriteDat(unsigned char I2C_Data);// -- ???
	void OLED_Refresh_Gram(void);//??
	void OLED_ON(void);// -- ??
	void OLED_OFF(void);//) -- ??
	void OLED_SetPos(unsigned char x, unsigned char y);// -- ???????
	void OLED_Fill(unsigned char fill_Data);// -- ????
	void OLED_CLS(void);// -- ??
	void OLED_DrawPoint(u8 x,u8 y,u8 t);// --??
	void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);// --??????
	void OLED_ShowStr(u8 x,u8 y,const u8 *p,u8 size);
	void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);// -- ????(???????,????oledfont.h?)
	void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);// -- BMP??
    *
**/ 
 
u8 OLED_GRAM[128][8];
static __IO uint32_t  I2CTimeout = I2CT_LONG_TIMEOUT;
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);
 
/************************************
  * @brief  Write_Byte_to_OLED,HARDWARE I2C 
  * @param  ?
  * @retval ?
  ***********************************/
uint32_t Write_Byte_to_OLED(u8 Cmd_or_Data,u8 Data)
{
  I2C_GenerateSTART(OLED_I2C, ENABLE);																					                
     //????
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  while(!I2C_CheckEvent(OLED_I2C, I2C_EVENT_MASTER_MODE_SELECT))								        
     //EV5
  {
    if((I2CTimeout--) == 0)
		return I2C_TIMEOUT_UserCallback(0);
  }
	
  I2C_Send7bitAddress(OLED_I2C, OLED_ADDRESS, I2C_Direction_Transmitter);			
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  while(!I2C_CheckEvent(OLED_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))	//EV6
  {
    if((I2CTimeout--) == 0)
		return I2C_TIMEOUT_UserCallback(1);
  }    
      
  I2C_SendData(OLED_I2C, Cmd_or_Data);																					     
     //??????????,??0x00,??0x40
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  while(!I2C_CheckEvent(OLED_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))  					        
     //EV8 and clear it */
  {
    if((I2CTimeout--) == 0)
		return I2C_TIMEOUT_UserCallback(2);
  }
	
  I2C_SendData(OLED_I2C, Data);																									//???????? 
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  while(!I2C_CheckEvent(OLED_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))						//EV8 and clear it */
  {
    if((I2CTimeout--) == 0)
		return I2C_TIMEOUT_UserCallback(3);
  } 
  
  I2C_GenerateSTOP(OLED_I2C, ENABLE);																						//????
  
  return 1;
}
/************************************
  * @brief  OLED_Init,???OLED
  * @param  ?
  * @retval ?
  ***********************************/
void OLED_Init(void)
{   
	
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef I2C_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
	I2C_DeInit(I2C1);
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = OWN_ADDRESS;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
	I2C_Init(I2C1, &I2C_InitStructure);
	I2C_Cmd(I2C1, ENABLE);
 
 
	
	delay_ms(1000);     // 1s,????????,?????,?????????
	WriteCmd(0xAE);//--display off
	WriteCmd(0x00);//---set low column address
	WriteCmd(0x10);//---set high column address
	WriteCmd(0x40);//--set start line address  
	WriteCmd(0xB0);//--set page address
	WriteCmd(0x81); // contract control
	WriteCmd(0xFF);//--128   
	WriteCmd(0xA1);//set segment remap 
	WriteCmd(0xA6);//--normal / reverse
	WriteCmd(0xA8);//--set multiplex ratio(1 to 64)
	WriteCmd(0x3F);//--1/32 duty
	WriteCmd(0xC8);//Com scan direction
	WriteCmd(0xD3);//-set display offset
	WriteCmd(0x00);//
	
	WriteCmd(0xD5);//set osc division
	WriteCmd(0x80);//
	
	WriteCmd(0xD8);//set area color mode off
	WriteCmd(0x05);//
	
	WriteCmd(0xD9);//Set Pre-Charge Period
	WriteCmd(0xF1);//
	
	WriteCmd(0xDA);//set com pin configuartion
	WriteCmd(0x12);//
	
	WriteCmd(0xDB);//set Vcomh
	WriteCmd(0x30);//
	
	WriteCmd(0x8D);//set charge pump enable
	WriteCmd(0x14);//
	
	WriteCmd(0xAF);//--turn on OLED panel
	
	
}
 
 
 
 
/**********************************************************************
  * @brief  WriteCmd,?OLED????
  * @param  I2C_Command:????
  * @retval ?
  *********************************************************************/
void WriteCmd(unsigned char I2C_Command)//???
{
   Write_Byte_to_OLED(0x00, I2C_Command);
}
 
 
 /**********************************************************************
  * @brief  OLED_WriteDat
  * @param  I2C_Data:??
  * @retval ?
  *********************************************************************/
void WriteDat(unsigned char I2C_Data)//???
{
   Write_Byte_to_OLED(0x40, I2C_Data);
}
 
 
 
/*****************************************************Draw********************************************/
//?????OLED	 
void OLED_Refresh_Gram(void)
{
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		WriteCmd(0xb0+i);    //?????(0~7)
		WriteCmd(0x00);      //??????????
		WriteCmd(0x10);      //??????????   
		for(n=0;n<128;n++)WriteDat(OLED_GRAM[n][i]); 
	}   
}
 /*************************************************************************
  * @brief  OLED_ON,?OLED??????
  * @param  ?
    * @retval ?
  ************************************************************************/
void OLED_ON(void)
{
    WriteCmd(0X8D);  //?????
    WriteCmd(0X14);  //?????
    WriteCmd(0XAF);  //OLED??
}
 /*************************************************************************
  * @brief  OLED_OFF,?OLED?? -- ?????,OLED????10uA
  * @param  ?
    * @retval ?
  ************************************************************************/
void OLED_OFF(void)
{
    WriteCmd(0X8D);  //?????
    WriteCmd(0X10);  //?????
    WriteCmd(0XAE);  //OLED??
}
/*************************************************************************
  * @brief  OLED_SetPos,????
  * @param  x,??x??
    *                   y,??y??
  * @retval ?
  ************************************************************************/
void OLED_SetPos(unsigned char x, unsigned char y) //???????
{ 
    WriteCmd(0xb0+y);
    WriteCmd(((x&0xf0)>>4)|0x10);
    WriteCmd((x&0x0f)|0x01);
}
 /*************************************************************************
  * @brief  OLED_Fill,??????
  * @param  fill_Data:??????
    * @retval ?
  ************************************************************************/
void OLED_Fill(unsigned char fill_Data)//????
{
    unsigned char m,n;
    for(m=0;m<8;m++)
    {
        WriteCmd(0xb0+m);    //page0-page1
        WriteCmd(0x00);     //low column start address
        WriteCmd(0x10);     //high column start address
        for(n=0;n<128;n++)
            {
                WriteDat(fill_Data);
				OLED_GRAM[n][m] = fill_Data;
            }
    }
}
 /*************************************************************************
  * @brief  OLED_Fill,??????
  * @param  fill_Data:??????
    * @retval ?
  ************************************************************************/
void OLED_GRAM_FILL(unsigned char fill_Data)//????
{
    unsigned char m,n;
    for(m=0;m<8;m++)
    {
        WriteCmd(0xb0+m);    //page0-page1
        WriteCmd(0x00);     //low column start address
        WriteCmd(0x10);     //high column start address
        for(n=0;n<128;n++)
            {
				OLED_GRAM[n][m] = fill_Data;
            }
    }
}
 /*************************************************************************
  * @brief  OLED_CLS,??
  * @param  ?
    * @retval ?
  ************************************************************************/
void OLED_CLS(void)//??
{
    OLED_Fill(0x00);
}
 /*************************************************************************
  * @brief  OLED_DrawPoint ?? 
  * @param  x:0~127
  *         y:0~63
  *        t:1 ?? 0,??		
  * @retval ?
  ************************************************************************/   
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
	u8 pos,bx,temp=0;
	if(x>127||y>63)return;//?????.
	pos=y/8;
	bx=y%8;
	temp=1<<(bx);
	if(t)OLED_GRAM[x][pos]|=temp;
	else OLED_GRAM[x][pos]&=~temp;	    
}
 /*************************************************************************
  * @brief  OLED_char,??????,?6*8?16*16 24*24???
  * @param  x,y : ?????(x:0~127, y:0~63);
    *       chr :- ??????; 
    *       Size : ????(12/16/24)
    *       mode:0,????;1,????
    * @retval ?
  ************************************************************************/
  void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
{      			    
	u8 temp,t,t1;
	u8 y0=y;
	u8 csize=(size/8+((size%8)?1:0))*(size/2);		//???????????????????
	chr=chr-' ';//???????		 
    for(t=0;t<csize;t++)
    {   
		if(size==12)temp=asc2_1206[chr][t]; 	 	//??1206??
		else if(size==16)temp=asc2_1608[chr][t];	//??1608??
		else if(size==24)temp=asc2_2412[chr][t];	//??2412??
		else return;								//?????
    for(t1=0;t1<8;t1++)
		{
			if(temp&0x80)OLED_DrawPoint(x,y,mode);
			else OLED_DrawPoint(x,y,!mode);
			temp<<=1;
			y++;
			if((y-y0)==size)
			{
				y=y0;
				x++;
				break;
			}
		}  	 
    }          
}
 
 /*************************************************************************
  * @brief  OLED_ShowStr,??oledfont.h??ASCII??,?6*8?16*16 24*24???
  * @param  x,y : ?????(x:0~127, y:0~63);
    *       ch[] :- ???????; 
    *       TextSize :????(12/16/24)
    * @retval ?
  ************************************************************************/
void OLED_ShowStr(u8 x,u8 y,const u8 *p,u8 size,u8 mode)
{
    while((*p<='~')&&(*p>=' '))//?????????!
    {       
        if(x>(128-(size/2))){x=0;y+=size;}
        if(y>(64-size)){y=x=0;OLED_CLS();}
        OLED_ShowChar(x,y,*p,size,mode);	 
        x+=size/2;
        p++;
    }  
}
 
 /*************************************************************************
  * @brief  OLED_ShowCN,??codetab.h????,16*16??
  * @param  x,y: ?????(x:0~127, y:0~7); 
    *                   N:???codetab.h????
    * @retval ?
  ************************************************************************/
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
    unsigned char wm=0;
    unsigned int  adder=32*N;
    OLED_SetPos(x , y);
    for(wm = 0;wm < 16;wm++)
    {
        WriteDat(CN16x16[adder]);
        adder += 1;
    }
    OLED_SetPos(x,y + 1);
    for(wm = 0;wm < 16;wm++)
    {
        WriteDat(CN16x16[adder]);
        adder += 1;
    }
}
 
 /************************************************************************
  * @brief  OLED_DrawBMP,??BMP[]???
  * @param  x0,y0 :?????(x0:0~127, y0:0~7);
  *         x1,y1 : ?????(???)???(x1:1~128,y1:1~8)
  * @retval ?
  ************************************************************************/
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char* BMP)
{
    unsigned int j=0;
    unsigned char x,y;
 
  if(y1%8==0)
        y = y1/8;
  else
        y = y1/8 + 1;
    for(y=y0;y<y1;y++)
    {
        //OLED_SetPos(x0,y);
        for(x=x0;x<x1;x++)
        {
            WriteDat(*(BMP+j++));
			//OLED_GRAM[x][y]= *(BMP+j++);
        }
    }
}
 /************************************************************************
  * @brief  OLED_draw_line,?(x0,y0)????k???
  * @param  
  *         
  * @retval ?
  ************************************************************************/
void OLED_draw_line(const u8 x0,const u8 y0,const float k,u8 mode) //????(x0,y0),??k   mode:0,??;1,??	  
{
	u8 x=x0,y=y0;
    while((x>0 &&x <128 )&& (y<64&&y>0))
	{
		OLED_DrawPoint(x,y,mode);
		x++;
		y+=k;
	}
	x=x0,y=y0;
	while(x>0 && y>0)
	{
		OLED_DrawPoint(x,y,mode);
		x--;
		y-=k;
	}
}

//m^n函数
u32 mypow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}		

//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/mypow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size/2)*t,y,' ',size,1);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1); 
	}
} 

 /************************************************************************
  * @brief  I2c ???? 
  * @param  
  *        
  * @retval ?
  ************************************************************************/
static  uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{
  /* Block communication and all processes */
 // EEPROM_ERROR("I2C ????!errorCode = %d",errorCode);
  return 0;
}
/*********************************************END OF FILE**********************/

main函数部分:


//DHT22 温湿度传感器  
//+ 	接 3.3V或5V
//-		接 GND
//out 接 PB9



#include "led.h"
#include "oled.h"
#include "delay.h"
#include "sys.h"
#include "dht22.h"
#include "usart.h"

int main(void){
	u16 temperature,humidity;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
	uart_init(115200);
	delay_init();
	LED_Init();
	OLED_Init();
	OLED_ShowStr(0,0,"Temperature:   .  C",12,1);
	OLED_ShowStr(0,12,"Humidity:      .  %",12,1);
	DHT22_Init();
	delay_ms(1000);
	while(1){
		
		OLED_Refresh_Gram();

		

		DHT22_Read_Data(&temperature,&humidity);			
		OLED_ShowNum(93,0,temperature%10,2,12);		
		OLED_ShowNum(73,0,temperature/10,2,12);		
		
		OLED_ShowNum(93,12,humidity%10,2,12);		
		OLED_ShowNum(73,12,humidity/10,2,12);		
		
		delay_ms(10);
		
		LED=!LED;
		delay_ms(1000);
	}
}

参考文章:STM32寄存器操作端口模式CRL/CRH详解_weixin_45164090的博客-CSDN博客_crl和crh

stm32f103c8t6模拟IIC驱动0.96'oled_贾晓籽的博客-CSDN博客STM32F103驱动DHT22温湿度传感器程序讲解(附加程序下载)_帅奎奎的博客-CSDN博客_dht22 stm32

  • 7
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值