5.4 综合案例-oled屏幕显示gps数据

项目采用ATGM336H-5N GPS模块获取定位信息,并通过Haas506板载TTL串口传送至OLED屏幕显示。代码实现筛选$GNRMC数据包,解析经纬度、UTC时间等关键信息,确保即使数据包不完整也能正确显示。

5.4 综合案例-oled屏幕显示gps数据

1.简介

 本案例使用gps模块获取gps数据,同时将数据显示在oled屏幕上。gps模块每一秒会通过串口发送数据包,通过haas506上的串口接收并处理该数据,获得经纬度、UTC时间等信息。
 注意:由于haas506只有一个TTL串口,而TTL又被作为下载口和默认的repl口,所以在board.json中需要重定向repl口以及在下载程序的时候不能将gps模块pin脚接入到串口上。本案例将repl口重定向到RS232。

串口接收到的数据,若是完整的包如下所示:
bytearray(b'
$GNGGA,052538.119,,,,,0,00,25.5,,,,,,*7A\r\n
$GNGLL,,,,,052538.119,V,N*64\r\n
$GNGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5,1*01\r\n
$GNGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5,4*04\r\n
$GPGSV,3,1,09,07,,,23,08,,,31,10,,,20,14,,,21,0*67\r\n
$GPGSV,3,2,09,21,,,25,27,,,26,30,,,24,34,,,24,0*6C\r\n
$GPGSV,3,3,09,35,,,24,0*6C\r\n
$BDGSV,1,1,00,0*74\r\n
$GNRMC,075622.000,A,3116.56922,N,12044.12475,E,0.00,0.00,020422,,,A,V*01\r\n
$GNVTG,,,,,,,,,N*2E\r\n
$GNZDA,052538.119,,,,,*48\r\n
$GPTXT,01,01,01,ANTENNA OPEN*25\r\n')

然而无法获得完整的数据包,所以在代码中针对该情况修改了一下代码,即判断$GNRMC是否存在,
若存在就将$GNRMC所在的一行数据去除","变为列表。变为列表后,判断该列表的长度是否为14,
若是,则从该列表中取出经纬度、utc时间等信息。
----------------------------------------------------------------------
#gps相关信息可以从$GNRMC中获取,例如:
$GNRMC,075622.000,A,3116.56922,N,12044.12475,E,0.00,0.00,020422,,,A,V*01
# 字段0---语句的id:$GPRMC :,推荐最小定位信息
# 字段1---UTC时间: 格式为hhmmss.ssss(时分秒.毫秒)
# 字段2---状态:A=定位  ,V=未定位
# 字段3---纬度: 格式ddmm.mmmmm若前导数不足,则用0填充
# 字段4---纬度: N(北纬)/S(南纬)
# 字段5---经度 :格式dddmm.mmmmm 若前导数不足,则用0填充
# 字段6---经度: E(东经)/W(西经)
# 字段7---速度,节,knots  1.852KM/h
# 字段8---方位角,度   (二位方向,等效于二位罗盘)
# 字段9---UTC日期,DDMMYY格式(天月年)
# 字段10---磁偏角(000-180)度  若前导数不足,则用0填充
# 字段11---磁偏角方向 E=东,W=西
# 字段12---模式:A=自动,D=差分,E=估计,AND=无效数据
# 字段13---校验值  ,"*"是校验和识别符,后面的两位数为校验和

# 十进制北纬度数 = dd + mm.mmmmm/60;
# 十进制南纬度数 = -(dd + mm.mmmmm/60);
# 十进制东经度数 = ddd + mm.mmmmm/60;
# 十进制西经度数 = -(ddd + mm.mmmmm/60);

2.硬件

  • 硬件模块
    gps模块:中科微-ATGM336H-5N系列模块
    oled模块:尺寸为128x64

在这里插入图片描述
在这里插入图片描述

  • 硬件接线图

在这里插入图片描述

3.测试代码

  • main.py
from driver import UART
import utime as time
from ssd1306 import SSD1306_128_64


#数据显示
def disInfo(msg1,msg2):
#显示字符串 6*8(宽x高)点阵
#两行数据,分别为latitude,longitude
    disp.oled_showStr(0,0,msg1,1)
    disp.oled_showStr(0,1,msg2,1)
        
#时间       
def utcDateTime(dateStr, timeStr, timeZone=8):
    if dateStr == '' or timeStr == '':
        return None
    day = dateStr[0:2]
    month = dateStr[2:4]
    year = dateStr[4:6]
    hr = int(timeStr[0:2])+timeZone
    if hr>=24:
        hr=str(hr-24)
    else:
        hr=str(hr)    
    min = timeStr[2:4]
    sec = timeStr[4:6]
    t ="20"+year+"-"+month+"-"+day+" "+hr+":"+min+":"+sec
    return t

#纬度
def latitude(d,h):
    if d=="":
        return 0
    hemi="" if h=="N" else "-"
    #度
    deg=int(d[0:2])
    #分
    min=str(float(d[2:])/60)[1:]

    return hemi +str(deg)+min


#经度
def  longitude(d,h):
    if d=="":
        return 0
    hemi="" if h=="E" else "-"
    #度
    deg=int(d[0:3])
    #分
    min=str(float(d[3:])/60)[1:]

    return hemi +str(deg)+min


def main():
    while True:
        #串口读
        size=gps_module.read(readBuf)
        data=readBuf
        #将字节数据转化成字符串数据
        data_str=data.decode()
        # 判断是否有数据 且数据中是否包含"$GNRMC"
        if size!=0 and "$GNRMC" in data_str  and "$GNVTG" in data_str:
            print(readBuf)
            print("------------0-----------------------")
            #删除"\r\n"后,字符串变为列表
            data_list=data_str.split('\r\n')
            print(data_list)     
            print("------------------1------------------")
            for i in range(len(data_list)):   
                if "$GNRMC" in data_list[i]:
                    print(data_list[i])
                    #删除","
                    result=data_list[i].split(',')
                    #$GNRMC,075622.000,A,3116.56922,N,12044.12475,E,0.00,0.00,020422,,,A,V*01
                    #['$GNRMC', '075622.000', 'A', '3116.56922', 'N', '12044.12475', 'E', '0.00', '0.00', '020422', '', '', 'A', 'V*01']
                    # 在GNRMC中取数据
                    if len(result)==14:
                        lat=latitude(result[3],result[4])
                        long=longitude(result[5],result[6])
                        tim=utcDateTime(result[9],result[1][:6],8)
                        print("lat:",lat)
                        print("long:",long)
                        print(tim)
                        #显示屏显示数据
                        disInfo("lat:"+str(lat)[:9],"lon:"+str(long)[:10])
            print("---------------------2-------------------")
        time.sleep(1)    

if __name__=="__main__":
    #创建一个串口实例
    gps_module=UART()
    #打开
    gps_module.open("serial1")
    #波特率可以在board.json中设置,也可以在代码中设置
    #gps模块的波特率是9600
    gps_module.setBaudRate(9600)
    # 创建一个字节数组,用于接受串口数据
    readBuf=bytearray(512)
    #创建一个oled实例
    disp=SSD1306_128_64()
    # 初始化
    disp.begin()
    #清屏    
    disp.clear()
    #主函数
    main()

  • ssd1306.py

import utime as time
import codetab

# Constants
SSD1306_I2C_ADDRESS = 0x3C    # 011110+SA0+RW - 0x3C or 0x3D
SSD1306_SETCONTRAST = 0x81
SSD1306_DISPLAYALLON_RESUME = 0xA4
SSD1306_DISPLAYALLON = 0xA5
SSD1306_NORMALDISPLAY = 0xA6
SSD1306_INVERTDISPLAY = 0xA7
SSD1306_DISPLAYOFF = 0xAE
SSD1306_DISPLAYON = 0xAF
SSD1306_SETDISPLAYOFFSET = 0xD3
SSD1306_SETCOMPINS = 0xDA
SSD1306_SETVCOMDETECT = 0xDB
SSD1306_SETDISPLAYCLOCKDIV = 0xD5
SSD1306_SETPRECHARGE = 0xD9
SSD1306_SETMULTIPLEX = 0xA8
SSD1306_SETLOWCOLUMN = 0x00
SSD1306_SETHIGHCOLUMN = 0x10
SSD1306_SETSTARTLINE = 0x40
SSD1306_MEMORYMODE = 0x20
SSD1306_COLUMNADDR = 0x21
SSD1306_PAGEADDR = 0x22
SSD1306_COMSCANINC = 0xC0
SSD1306_COMSCANDEC = 0xC8
SSD1306_SEGREMAP = 0xA0
SSD1306_CHARGEPUMP = 0x8D
SSD1306_EXTERNALVCC = 0x1
SSD1306_SWITCHCAPVCC = 0x2

# Scrolling constants
SSD1306_ACTIVATE_SCROLL = 0x2F
SSD1306_DEACTIVATE_SCROLL = 0x2E
SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3
SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26
SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27
SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29
SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A


class SSD1306Base(object):
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self._pages = height//8
        self._buffer = [0]*(width*self._pages)
        # Handle hardware I2C
        from driver import I2C
        self._i2c=I2C()
        self._i2c.open('OLED')


    def _initialize(self):
        raise NotImplementedError

    def writeCmd(self, command):
        """Send command byte to display."""
        # I2C write.
        control = 0x00   # Co = 0, DC = 0
        writeBuf=bytearray(2)
        writeBuf[0]=control
        writeBuf[1]=command
        self._i2c.write(writeBuf,2)

    def writeDat(self, data):
        """Send byte of data to display."""
        # I2C write.
        control = 0x40   # Co = 0, DC = 0
        writeBuf=bytearray(2)
        writeBuf[0]=control
        writeBuf[1]=data
        self._i2c.write(writeBuf,2)

    def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
        """Initialize display."""
        # Save vcc state.
        self._vccstate = vccstate
        # Reset and initialize display.
        # self.reset()
        self._initialize()
        # Turn on the display.
        self.writeCmd(SSD1306_DISPLAYON)

# --------------------------------------------------------------
#  Prototype      : oled_fill(fill_data)
#  Parameters     : fill_data,范围0x00-0xff
#  Description    : 全屏填充,例如 0x00-全黑,0xff全亮
# --------------------------------------------------------------
    def oled_fill(self,fill_data):
        for i in range(8):
            #page0-page1
            self.writeCmd(0xb0+i)
            # low colum start address
            self.writeCmd(0x00)
            #high colum start address
            self.writeCmd(0x10)
        for i in range(128*64):
            self.writeDat(fill_data)  
      
# --------------------------------------------------------------
#  Prototype      : clear()
#  Parameters     : none
#  Description    : 全黑
# --------------------------------------------------------------
    def clear(self):
        self.oled_fill(0x00)



# --------------------------------------------------------------
#  Prototype      : oled_setPos(x,y)
#  Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7)
#  Description    : 设置起始坐标
# --------------------------------------------------------------
    def oled_setPos(self,x,y):
        self.writeCmd(0xb0+y)
        self.writeCmd(((x&0xf0)>>4)|0x10)
        self.writeCmd((x&0x0f)|0x01)

# --------------------------------------------------------------
#  Prototype      : oled_showCN(x,y,n)
#  Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引
#  Description    : 显示codetab.py中的汉字,16*16点阵
# --------------------------------------------------------------
    def oled_showCN(self,x,y,n):
        self.oled_setPos(x,y)
        adder=32*n
        for i in range(16):
            self.writeDat(codetab.F1[adder])
            adder+=1
        self.oled_setPos(x,y+1)
        for i in range(16):
            self.writeDat(codetab.F1[adder])
            adder+=1

# --------------------------------------------------------------
#  Prototype      : oled_showStr(x,y,ch,TextSize)
#  Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16)
#  Description    : 显示codetab.py中的ASCII字符,有6*8和8*16可选择
# --------------------------------------------------------------    

    def oled_showStr(self,x,y,ch,TextSize):
        c=0
        j=0
        if TextSize==1:
            while ch[j]!='\0':
                #ord()将字符转换成十进制,如'a'->97
                c=ord(ch[j])-32
                if x>126:
                    x=0
                    y+=1
                self.oled_setPos(x,y)
                for i in range(6):
                    self.writeDat(codetab.F6x8[c][i]) 
                x+=6
                j+=1
                #防止index out of range 
                if j==len(ch):
                    break
        if TextSize==2:
             while ch[j]!='\0':
                #ord()将字符转换成十进制,如'a'->97
                c=ord(ch[j])-32
                if x>120:
                    x=0
                    y+=1
                self.oled_setPos(x,y)
                for i in range(8):
                    self.writeDat(codetab.F8X16[c*16+i]) 
                self.oled_setPos(x,y+1)
                for i in range(8):
                    self.writeDat(codetab.F8X16[c*16+i+8])    
                x+=8
                j+=1    
                #防止index out of range                                    
                if j==len(ch):
                    break
# --------------------------------------------------------------
# Prototype      : oled_showPicture(x0,y0,x1,y1,BMP)
# Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:128)
# Description    : 显示BMP位图
# --------------------------------------------------------------
    def oled_showPicture(self,x0,y0,x1,y1,BMP):
        i=0
        if y1%8==0:
            y=y1/8
        else:
            y=y1/8+1
        for y in range(y0,y1):
            self.oled_setPos(x0,y)   
            for x in range(x0,x1):
                self.writeDat(BMP[i])  
                i+=1    
            if i==len(BMP) :
                break

# --------------------------------------------------------------
# Prototype      : set_contrast(contrast)
# Parameters     : coontrast,取值范围为0-255
# Description    : 对比度/亮度调节
# --------------------------------------------------------------    
    def set_contrast(self, contrast):
        if contrast < 0 or contrast > 255:
            raise ValueError('Contrast must be a value from 0 to 255 (inclusive).')
        self.writeCmd(SSD1306_SETCONTRAST)
        self.writeCmd(contrast)


class SSD1306_128_64(SSD1306Base):
    def __init__(self):
        super(SSD1306_128_64, self).__init__(128, 64)

    def _initialize(self):
        # 128x64 pixel specific initialization.
        self.writeCmd(SSD1306_DISPLAYOFF)                    # 0xAE
        self.writeCmd(SSD1306_SETDISPLAYCLOCKDIV)            # 0xD5
        self.writeCmd(0x80)                                  # the suggested ratio 0x80
        self.writeCmd(SSD1306_SETMULTIPLEX)                  # 0xA8
        self.writeCmd(0x3F)
        self.writeCmd(SSD1306_SETDISPLAYOFFSET)              # 0xD3
        self.writeCmd(0x0)                                   # no offset
        self.writeCmd(SSD1306_SETSTARTLINE | 0x0)            # line #0
        self.writeCmd(SSD1306_CHARGEPUMP)                    # 0x8D
        if self._vccstate == SSD1306_EXTERNALVCC:
            self.writeCmd(0x10)
        else:
            self.writeCmd(0x14)
        self.writeCmd(SSD1306_MEMORYMODE)                    # 0x20
        self.writeCmd(0x00)                                  # 0x0 act like ks0108
        self.writeCmd(SSD1306_SEGREMAP | 0x1)
        self.writeCmd(SSD1306_COMSCANDEC)
        self.writeCmd(SSD1306_SETCOMPINS)                    # 0xDA
        self.writeCmd(0x12)
        self.writeCmd(SSD1306_SETCONTRAST)                   # 0x81
        if self._vccstate == SSD1306_EXTERNALVCC:
            self.writeCmd(0x9F)
        else:
            self.writeCmd(0xCF)
        self.writeCmd(SSD1306_SETPRECHARGE)                  # 0xd9
        if self._vccstate == SSD1306_EXTERNALVCC:
            self.writeCmd(0x22)
        else:
            self.writeCmd(0xF1)
        self.writeCmd(SSD1306_SETVCOMDETECT)                 # 0xDB
        self.writeCmd(0x40)
        self.writeCmd(SSD1306_DISPLAYALLON_RESUME)           # 0xA4
        self.writeCmd(SSD1306_NORMALDISPLAY)                 # 0xA6


class SSD1306_128_32(SSD1306Base):
    def __init__(self):
        super(SSD1306_128_32, self).__init__(128, 32)

    def _initialize(self):
        self.command(SSD1306_DISPLAYOFF)                    # 0xAE
        self.command(SSD1306_SETDISPLAYCLOCKDIV)            # 0xD5
        self.command(0x80)                                  # the suggested ratio 0x80
        self.command(SSD1306_SETMULTIPLEX)                  # 0xA8
        self.command(0x1F)
        self.command(SSD1306_SETDISPLAYOFFSET)              # 0xD3
        self.command(0x0)                                   # no offset
        self.command(SSD1306_SETSTARTLINE | 0x0)            # line #0
        self.command(SSD1306_CHARGEPUMP)                    # 0x8D
        if self._vccstate == SSD1306_EXTERNALVCC:
            self.command(0x10)
        else:
            self.command(0x14)
        self.command(SSD1306_MEMORYMODE)                    # 0x20
        self.command(0x00)                                  # 0x0 act like ks0108
        self.command(SSD1306_SEGREMAP | 0x1)
        self.command(SSD1306_COMSCANDEC)
        self.command(SSD1306_SETCOMPINS)                    # 0xDA
        self.command(0x02)
        self.command(SSD1306_SETCONTRAST)                   # 0x81
        self.command(0x8F)
        self.command(SSD1306_SETPRECHARGE)                  # 0xd9
        if self._vccstate == SSD1306_EXTERNALVCC:
            self.command(0x22)
        else:
            self.command(0xF1)
        self.command(SSD1306_SETVCOMDETECT)                 # 0xDB
        self.command(0x40)
        self.command(SSD1306_DISPLAYALLON_RESUME)           # 0xA4
        self.command(SSD1306_NORMALDISPLAY)                 # 0xA6


class SSD1306_96_16(SSD1306Base):
    def __init__(self):
        super(SSD1306_96_16, self).__init__(96, 16)

    def _initialize(self):
        self.command(SSD1306_DISPLAYOFF)                    # 0xAE
        self.command(SSD1306_SETDISPLAYCLOCKDIV)            # 0xD5
        self.command(0x60)                                  # the suggested ratio 0x60
        self.command(SSD1306_SETMULTIPLEX)                  # 0xA8
        self.command(0x0F)
        self.command(SSD1306_SETDISPLAYOFFSET)              # 0xD3
        self.command(0x0)                                   # no offset
        self.command(SSD1306_SETSTARTLINE | 0x0)            # line #0
        self.command(SSD1306_CHARGEPUMP)                    # 0x8D
        if self._vccstate == SSD1306_EXTERNALVCC:
            self.command(0x10)
        else:
            self.command(0x14)
        self.command(SSD1306_MEMORYMODE)                    # 0x20
        self.command(0x00)                                  # 0x0 act like ks0108
        self.command(SSD1306_SEGREMAP | 0x1)
        self.command(SSD1306_COMSCANDEC)
        self.command(SSD1306_SETCOMPINS)                    # 0xDA
        self.command(0x02)
        self.command(SSD1306_SETCONTRAST)                   # 0x81
        self.command(0x8F)
        self.command(SSD1306_SETPRECHARGE)                  # 0xd9
        if self._vccstate == SSD1306_EXTERNALVCC:
            self.command(
<think>好的,我需要帮助用户解决如何将银河麒麟桌面操作系统的内核从5.4.18-85-generic升级到5.4.18-110-generic的问题。首先,我需要回顾用户提供的引用内容,看看有没有相关的信息。引用[1]提到系统使用的是5.4.18-85的内核,并且安装了对应的内核开发包。引用[3]和[4]涉及到系统安装后的配置和内核启动问题,特别是引用[4]讨论了如何设置GRUB默认启动老版本内核,这可能和升级后的启动选项有关。引用[2]虽然主要是关于编译内核模块和USB网络共享,但提到了手动安装内核模块的步骤,这可能对升级内核后的模块处理有帮助。用户的需求是升级内核版本,所以需要找到银河麒麟官方提供的内核升级包或者源码编译的方法。根据引用[1]和[2],用户之前可能通过源码编译过spice-gtk和内核模块,因此可能对编译过程有一定了解。但官方是否有直接可用的升级包呢?查看引用[3]中的问题处理,用户更换硬盘后遇到启动问题,涉及到/data分区的挂载和用户目录的配置,这可能提示在升级内核后需要检查分区挂载是否正确,避免类似问题。引用[4]中的GRUB配置问题,升级内核后可能需要调整默认启动项,确保新内核被正确加载。可能的步骤包括:1.检查官方源是否有新内核包;2.下载安装新内核的deb包;3.编译新内核源码;4.更新GRUB配置;5.处理可能出现的模块或驱动问题。需要确认用户是否有权限访问官方仓库,或者是否需要手动下载安装包。如果官方提供了5.4.18-110-generic的内核包,可以直接通过apt安装。否则可能需要从源码编译,但这样风险较高。另外,升级内核后可能需要安装对应的头文件和开发包,如引用[1]中的linux-headers。还需要注意,升级内核后,原有的内核模块可能需要重新编译或安装,如引用[2]中的usbnet.ko等模块,可能需要针对新内核重新编译,否则设备驱动可能无法使用。此外,GRUB的默认启动项设置可能需要调整,如引用[4]中的GRUB_DEFAULT设置,确保系统启动时选择新内核。 最后,用户可能需要备份数据,防止升级过程中出现意外导致系统无法启动。同时,在升级完成后,检查所有硬件驱动和网络配置是否正常,如引用[2]中的USB网络共享是否仍然有效。综上,步骤可能包括:更新软件源、安装新内核包、更新GRUB、处理内核模块、验证启动和功能正常。需要逐步指导用户完成,并提醒注意事项。</think>根据银河麒麟系统特性及引用内容,内核升级需通过官方源或手动安装内核包实现。以下是详细步骤: --- ### **一、检查当前内核版本与可用升级包** 1. 确认当前内核版本: ```bash uname -r ``` 输出应为`5.4.18-85-generic`[^1] 2. 检查官方仓库是否有新内核包: ```bash sudo apt update apt list --upgradable | grep linux-image-5.4.18-110-generic ``` 若存在该包,直接通过`sudo apt install`安装;若无,需手动下载。 --- ### **二、手动安装新内核包** 1. **下载内核包** 从[麒麟软件仓库](https://update.kylinos.cn/)或可信源获取以下文件: - `linux-image-5.4.18-110-generic_5.4.18-110.xxx_arm64.deb` - `linux-headers-5.4.18-110-generic_5.4.18-110.xxx_arm64.deb` 2. **安装内核** ```bash sudo dpkg -i linux-image-5.4.18-110-generic_*.deb linux-headers-5.4.18-110-generic_*.deb ``` --- ### **三、更新GRUB引导配置** 1. 更新GRUB菜单: ```bash sudo update-grub ``` 2. **设置默认启动项** 若新内核位于子菜单中(如引用[4]描述),需修改`/etc/default/grub`: ```bash GRUB_DEFAULT="1>2" # 示例:选择第二个主菜单的第三个子项 sudo update-grub ``` --- ### **四、验证与故障处理** 1. **重启并选择新内核** ```bash sudo reboot ``` 2. **检查内核版本** ```bash uname -r # 应显示5.4.18-110-generic ``` 3. **驱动兼容性处理** 若USB网络共享等驱动失效(如引用[2]),需重新编译内核模块: ```bash cd /usr/src/linux-headers-5.4.18-110-generic make modules_prepare insmod /path/to/module.ko ``` --- ### **注意事项** 1. **备份数据**:升级前建议备份重要数据。 2. **回滚方案**:旧内核仍会保留在GRUB菜单中,可手动选择启动[^4]。 3. **分区挂载**:若遇到家目录挂载问题,参考引用[3]修改`/etc/fstab`。 ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值