linux移植1.3寸oled屏幕,芯片SH1106

之前移植过MPU6050(I2C协议)和0.96寸oled(SPI协议),这次移植一个I2C协议的oled。

I2C的介绍

可以参考上一篇I2C的文章:
linux移植MPU6050的I2C驱动 —— AURORA1997

注意:从机地址不是0x78,而是0x3c

驱动的编写

其实这个1.3寸的oled屏在MPU6050之前就买了,店家只有另一款SSD1306的demo,不过在我上个买0.96寸oled的店铺给的资料里翻到了SH1106的demo。但是上手测试发现花屏,并且最好的时候是出现严重错位的情况,不过终于能显示点东西了。

调试了好久,换了很多次初始化reset代码,还是无济于事。后来上GitHub找代码,发现是列地址的设置问题,最早用的是反的,导致后面一直不行。。。

/*后来修改后的*/
static void Column_set(unsigned char column)
{
	column+=2;
	OLED_send_cmd(0x00);    //设置列地址高位
	OLED_send_cmd(0x10);   //设置列地址低位  
}
/*之前最早用的demo的*/
void Column_set(unsigned char column)
{
	column+=OLED_COLUMN_OFFSET;
	OLED_send_cmd(0x10|(column>>4));    //设置列地址高位
	OLED_send_cmd(0x00|(column&0x0f));   //设置列地址低位  
}

这里直接贴代码:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/***************************************************************
文件名	: oled1p3i2c.c
作者	  	: 1997AURORA
版本	   	: V1.0
描述	   	: oled 1.3寸 SH1106 I2C驱动程序
其他	   	: 无
日志	   	: 初版V1.0 2021/8/14 1997AURORA创建
***************************************************************/
#define OLED1P3_CNT	1
#define OLED1P3_NAME	"oled1p3i2c"

const unsigned char BMP2[] =
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x84,0xC4,0x66,0x36,0x3E,0x1C,0x3C,0x7C,0xE6,0x06,0x06,0x03,0x03,0x03,
	0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x06,0x06,0x06,0xFC,0x3C,0x1C,0x3E,
	0x3E,0x66,0xC6,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x40,0x60,0xE0,0x00,0x00,0xE0,0x20,0xE0,0xC0,0xC0,0x60,0x20,0xE0,0x00,
	0x20,0x20,0xE0,0x60,0x00,0x80,0xE0,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0xE0,0x00,
	0xE0,0x20,0xE0,0x40,0xC0,0xE0,0x20,0x20,0xE0,0xC0,0xC0,0xE0,0x20,0xE0,0x00,0x00,
	0xC0,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xF8,0xF8,
	0xFE,0x77,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xF8,0xF8,0xF8,0x70,0x00,0x00,0x00,
	0x00,0x00,0x00,0x01,0x07,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x0C,0x0F,0x0C,0x00,0x0D,0x0D,0x07,0x03,0x00,0x0D,0x0D,0x07,0x00,
	0x00,0x06,0x03,0x00,0x04,0x07,0x02,0x03,0x07,0x00,0x07,0x0C,0x0C,0x07,0x03,0x00,
	0x07,0x01,0x07,0x04,0x03,0x06,0x0C,0x0C,0x07,0x03,0x07,0x07,0x01,0x07,0x04,0x0E,
	0x03,0x02,0x03,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFE,0x07,0x03,0x01,
	0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x01,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
	0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x06,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x20,0xE8,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x28,0xDC,0x68,0x98,
	0x78,0xE8,0x38,0x00,0x00,0xF0,0x1C,0xF0,0x20,0xDC,0x10,0xF0,0x00,0x00,0x00,0x00,
	0x00,0x08,0xF8,0x08,0x20,0x10,0xF0,0x00,0xF0,0x18,0x08,0x30,0x00,0x20,0x10,0xD0,
	0x30,0xFC,0x10,0x10,0x10,0x00,0x40,0x78,0x78,0xC0,0x30,0xCC,0x30,0xA0,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,
	0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x07,0x04,0x04,0x04,0x07,0x04,0x04,0x00,0x00,0x00,0x07,0x06,0x03,
	0x00,0x07,0x04,0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x04,0x07,0x00,0x00,0x00,0x00,
	0x00,0x04,0x07,0x04,0x04,0x06,0x05,0x04,0x03,0x04,0x06,0x02,0x01,0x00,0x01,0x05,
	0x07,0x03,0x03,0x07,0x05,0x00,0x01,0x05,0x07,0x01,0x07,0x05,0x07,0x04,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0F,0x3E,0xF0,0x80,
	0x03,0x0E,0x38,0x70,0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
	0x80,0xC0,0x60,0x30,0x1C,0x07,0x80,0xF0,0x7E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
	0x07,0x1C,0x38,0x70,0x60,0xC1,0xC3,0x87,0x06,0x0E,0x0C,0x1C,0x1C,0x18,0x38,0x38,
	0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x1C,0x1C,0x0C,0x0E,0x06,0x87,0xC3,
	0xC1,0xE0,0x70,0x38,0x1C,0x0F,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x07,0x06,0x06,0x0E,0x0C,0x0C,0x0C,
	0x1C,0x1C,0x18,0x1C,0x1C,0x1C,0x0C,0x0C,0x0C,0x0E,0x06,0x06,0x07,0x03,0x03,0x01,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\zjh46\Desktop\2.BMP",0*/
	/* (128 X 64 )*/

};

const unsigned char  OLED_init_cmd[22]=			//SH1106
{
    0xAE,
    0xA4,

    /* Multiplex Ratio Data Set: 64 (POR = 0x3f, 64) */
    0xA8,0x3f,

    /* Display OffsetData Set: 0 (POR = 0x00) */
    0xD3,0x00,

    0x40,

    0xA0 + 1,

    0xC8,

    /* DC-DC ON/OFF Mode Set: Built-in DC-DC is used, Normal Display (POR = 0x8b) */
    0xAD,0x8B,

    /* Dis-charge/Pre-charge PeriodData Set: pre-charge 2 DCLKs,
     * dis-charge 2 DCLKs (POR = 0x22, pre-charge 2 DCLKs, dis-charge 2 DCLKs)
     * */
    0xD5,0xf0,

    /* VCOM Deselect LevelData Set: 0,770V (POR = 0x35, 0,770 V) */
    0xDB,0x20,

    /* Set Pump voltage value: 8,0 V (POR = 0x32, 8,0 V) */
    0x30 | 0x0,

    /* Contrast Data Register Set: 255 (large) (POR = 0x80) */
    0x81,0x7f,

    0xA6,

    /* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) */
    0xDA, 0x12,
    0xAF


};

struct oled1p3_dev {
	dev_t devid;			/* 设备号 	 */
	struct cdev cdev;		/* cdev 	*/
	struct class *class;	/* 类 		*/
	struct device *device;	/* 设备 	 */
	struct device_node	*nd; /* 设备节点 */
	int major;			/* 主设备号 */
	void *private_data;	/* 私有数据 */
};

static struct oled1p3_dev oled1p3dev;

/*
 * @description	: 从oled1p3读取多个寄存器数据
 * @param - dev:  oled1p3设备
 * @param - reg:  要读取的寄存器首地址
 * @param - val:  读取到的数据
 * @param - len:  要读取的数据长度
 * @return 		: 操作结果
 */
static int oled1p3_read_regs(struct oled1p3_dev *dev, u8 reg, void *val, int len)
{
	return 0;
}

/*
 * @description	: 向oled1p3多个寄存器写入数据
 * @param - dev:  oled1p3设备
 * @param - reg:  要写入的寄存器首地址
 * @param - val:  要写入的数据缓冲区
 * @param - len:  要写入的数据长度
 * @return 	  :   操作结果
 */
static s32 oled1p3_write_regs(struct oled1p3_dev *dev,u8 *buf, u8 len)
{
	struct i2c_msg msg;
	struct i2c_client *client = (struct i2c_client *)dev->private_data;
	
	msg.addr = client->addr;	/* oled1p3地址 */
	msg.flags = 0;				/* 标记为写数据 */

	msg.buf = buf;				/* 要写入的数据缓冲区 */
	msg.len = len;			/* 要写入的数据长度 */

	return i2c_transfer(client->adapter, &msg, 1);
}

/*
 * @description	: 读取oled1p3指定寄存器值,读取一个寄存器
 * @param - dev:  oled1p3设备
 * @param - reg:  要读取的寄存器
 * @return 	  :   读取到的寄存器值
 */
static unsigned char oled1p3_read_reg(struct oled1p3_dev *dev, u8 reg)
{
	u8 data = 0;

	oled1p3_read_regs(dev, reg, &data, 1);
	return data;

#if 0
	struct i2c_client *client = (struct i2c_client *)dev->private_data;
	return i2c_smbus_read_byte_data(client, reg);
#endif
}

/*
 * @description	: 向oled1p3指定寄存器写入指定的值,写一个寄存器
 * @param - dev:  oled1p3设备
 * @param - reg:  要写的寄存器
 * @param - data: 要写入的值
 * @return   :    无
 */
static void oled1p3_write_reg(u8* data)
{
	oled1p3_write_regs(&oled1p3dev, data, 2);
}

static void OLED_send_cmd(unsigned char o_command)
{
	u8 b[2];
	b[0] = 0x00;
	b[1] = o_command;

	oled1p3_write_reg(b);
}
static void OLED_send_data(unsigned char o_data)
{ 
	u8 b[2];
	b[0] = 0x40;
	b[1] = o_data;
	oled1p3_write_reg(b);
}

static void OLED_init(void)
{
	unsigned char i;

	for(i=0;i<22;i++)
	{
		OLED_send_cmd(OLED_init_cmd[i]);
	}
}

static void Page_set(unsigned char page)
{
	OLED_send_cmd(0xb0+page);
}

static void Column_set(unsigned char column)
{
	column+=2;
	OLED_send_cmd(0x00);    //设置列地址高位
	OLED_send_cmd(0x10);   //设置列地址低位  
}

static void OLED_clear(void)
{
	unsigned char page,column;
	for(page=0;page<8;page++)             //page loop
	{ 
		Page_set(page);
		Column_set(0);	  
		for(column=0;column<132;column++)	//column loop
		{
			OLED_send_data(0x00);
		}
	}
}

static void OLED_full(void)
{
	unsigned char page,column;
	for(page=0;page<8;page++)             //page loop
	{ 
		Page_set(page);
		Column_set(0);	  
		for(column=0;column<132;column++)	//column loop
		{
			OLED_send_data(0xff);
		}
	}
}

static void Picture_display(const unsigned char *ptr_pic)
{
	unsigned char page,column;
	for(page=0;page<8;page++)        //page loop
	{ 
		Page_set(page);
		Column_set(0);	  
		for(column=0;column<128;column++)	//column loop
		{
			OLED_send_data(*ptr_pic++);
		}
	}
}

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int oled1p3_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &oled1p3dev;
	return 0;
}

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t oled1p3_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
	return 0;
}
/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t oled1p3_write(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
	unsigned char databuf[1];
	unsigned char oledstat;
	long err = 0;
	struct oled96_dev *dev = (struct oled96_dev *)filp->private_data;

	err = copy_from_user(databuf, buf, sizeof(cnt));
	if(err < 0) {
		printk("kernel write failed!\r\n");
		return -EFAULT;
	}
	oledstat = databuf[0];		/* 获取状态值 */
	if(oledstat == 0) {	
		OLED_full();
		printk("draw full screen\r\n");
	} else if(oledstat == 1) {
		OLED_clear();
		Picture_display(&BMP2);
		printk("draw BMP2\r\n");
	}
	
	return 0;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int oled1p3_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* OLED1P3操作函数 */
static const struct file_operations oled1p3_ops = {
	.owner = THIS_MODULE,
	.open = oled1p3_open,
	.read = oled1p3_read,
	.write = oled1p3_write,
	.release = oled1p3_release,
};

 /*
  * @description     : i2c驱动的probe函数
  * @param - client  : i2c设备
  * @param - id      : i2c设备ID
  * @return          : 0,成功;其他负值,失败
  */
static int oled1p3_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	/* 1、构建设备号 */
	if (oled1p3dev.major) {
		oled1p3dev.devid = MKDEV(oled1p3dev.major, 0);
		register_chrdev_region(oled1p3dev.devid, OLED1P3_CNT, OLED1P3_NAME);
	} else {
		alloc_chrdev_region(&oled1p3dev.devid, 0, OLED1P3_CNT, OLED1P3_NAME);
		oled1p3dev.major = MAJOR(oled1p3dev.devid);
	}

	/* 2、注册设备 */
	cdev_init(&oled1p3dev.cdev, &oled1p3_ops);
	cdev_add(&oled1p3dev.cdev, oled1p3dev.devid, OLED1P3_CNT);

	/* 3、创建类 */
	oled1p3dev.class = class_create(THIS_MODULE, OLED1P3_NAME);
	if (IS_ERR(oled1p3dev.class)) {
		return PTR_ERR(oled1p3dev.class);
	}

	/* 4、创建设备 */
	oled1p3dev.device = device_create(oled1p3dev.class, NULL, oled1p3dev.devid, NULL, OLED1P3_NAME);
	if (IS_ERR(oled1p3dev.device)) {
		return PTR_ERR(oled1p3dev.device);
	}

	oled1p3dev.private_data = client;

	OLED_init();

	return 0;
}

/*
 * @description     : i2c驱动的remove函数,移除i2c驱动的时候此函数会执行
 * @param - client 	: i2c设备
 * @return          : 0,成功;其他负值,失败
 */
static int oled1p3_remove(struct i2c_client *client)
{
	/* 删除设备 */
	cdev_del(&oled1p3dev.cdev);
	unregister_chrdev_region(oled1p3dev.devid, OLED1P3_CNT);

	/* 注销掉类和设备 */
	device_destroy(oled1p3dev.class, oled1p3dev.devid);
	class_destroy(oled1p3dev.class);
	return 0;
}

/* 传统匹配方式ID列表 */
static const struct i2c_device_id oled1p3_id[] = {
	{"alientek,oled1p3i2c", 0},  
	{}
};

/* 设备树匹配列表 */
static const struct of_device_id oled1p3_of_match[] = {
	{ .compatible = "alientek,oled1p3i2c" },
	{ /* Sentinel */ }
};

/* i2c驱动结构体 */	
static struct i2c_driver oled1p3_driver = {
	.probe = oled1p3_probe,
	.remove = oled1p3_remove,
	.driver = {
			.owner = THIS_MODULE,
		   	.name = "oled1p3i2c",
		   	.of_match_table = oled1p3_of_match, 
		   },
	.id_table = oled1p3_id,
};
		   
/*
 * @description	: 驱动入口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init oled1p3_init(void)
{
	int ret = 0;

	ret = i2c_add_driver(&oled1p3_driver);
	return ret;
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit oled1p3_exit(void)
{
	i2c_del_driver(&oled1p3_driver);
}

/* module_i2c_driver(oled1p3_driver) */

module_init(oled1p3_init);
module_exit(oled1p3_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("1997AURORA");

应用程序

应用程序同这个实验的应用程序,改个名即可。
0.96寸OLED屏移植到搭载mx6ull的linux系统

图片是显示的效果,是取图片的模取的。
显示效果

谢谢观看

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值