【USART】串口收发HEX数据包

【基于串口发送+接收】的【串口发送HEX数据包】
一、在Serial.c文件中添加收发HEX数据包部分
  • HEX数据包格式:此处为【固定包长】、【含包头包尾】、【包头FF】、【载荷数据4字节】、【包尾FE】
1、在Serial.c中初始化函数 Serial_Init
//为了收发数据包定义两个缓存区的数组
//只存储发送或接收的载荷数据
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxPacket[4];
//如果收到一个数据包就置RxFlag
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
//第一步:RCC开启USART和GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
//第二步:GPIO初始化,把TX配置成复用输出,RX配置成输入
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    //目前配置:PA9复用推挽输出供USART1的TX使用
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    //目前配置:PA10上拉输入供USART1的RX使用
    
    
//第三步:配置USART
    USART_InitTypeDef USART_InitSturucture;
    USART_InitSturucture.USART_BaudRate = 9600;//波特率(Init函数内部自动算出波特率对应分配系数)
    USART_InitSturucture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制
    USART_InitSturucture.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//选择发送(接收)模式,若都需要则用‘|’并起来
    USART_InitSturucture.USART_Parity = USART_Parity_No;//校验位
    USART_InitSturucture.USART_StopBits = USART_StopBits_1;//停止位
    USART_InitSturucture.USART_WordLength = USART_WordLength_8b;//字长
    USART_Init(USART1,&USART_InitSturucture);
    //目前配置:9600波特率、8位字长、无校验、1位停止位、无流控、只有发送模式
    
    
//第四步:开启中断
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
    //开启RXNE标志位到NVIC的输出
//第五步:配置NVIC
//RXNE标志位一但置1,就会向NVIC申请中断
//之后可用在中断函数里接收数据
//中断函数名称查找启动文件【startup_stm32f10x_md.s】
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组
    NVIC_InitTypeDef NVIC_InitStructure;//初始化NVIC的USART1通道
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
    
//第六步:开启USART,初始化完成
    USART_Cmd(USART1,ENABLE);
}
//对Serial_RxFlag封装Get函数
//实现读取后自动清除功能
uint8_t Serial_GetRxFlag(void)
{
    if(Serial_RxFlag == 1)
    {
        Serial_RxFlag = 0;
        return 1;
    }
    return 0;
}
//暂时不需要中断
//中断函数接收数据
void USART1_IRQHandler(void)
{
    //判断标志位,如果置1说明收到数据,进入if
    if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)
    {
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    }
}
//发送数据函数
//调用这个函数可以从TX引脚发送一个字节数据
void Serial_SendByte(uint8_t Byte)
{    
    //Byte变量写入发送数据寄存器TDR,TDR再传递给发送移位寄存器
    //最后一位一位地把数据移出到TX引脚,完成数据的发送
    USART_SendData(USART1,Byte);
    
    //等待TDR的数据全部转移到移位寄存器
    //数据还在TDR时仍写入数据会产生数据覆盖
    //【USART_FLAG_TXE】发送数据寄存器空标志位
    while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
    //数据寄存器不空则一直循环,数据寄存器空则跳出循环
}
//发送数组
/*
第一个参数:数组首地址(数组名)
第二个参数:指定传输多少字节
*/
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
    uint16_t i;
    for(i = 0; i < Length; i ++)//for循环执行Length次,可以对Array数据进行遍历
    {
        Serial_SendByte(Array[i]);
        //依次取出数组Array的每一项通过SendByte发送
    }
}
//发送字符串
//字符串自带一个结束标志位(数据0),因此不需要传递长度参数
void Serial_SendString(char *String)
{
    uint8_t i;
    for(i = 0; i < String[i] != 0; i ++)//循环条件用结束标志位判断
    {
        Serial_SendByte(String[i]);
        //依次取出字符串String的每一项通过SendByte发送
    }
}
/*
以十进制拆分数据
函数的返回值=X^Y
*/
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
    uint32_t Result = 1;
    while( Y -- )//循环Y次
    {
        Result *= X;//Result累乘Y次X(X的Y次方)
    }
    return Result;
}
//发送数字(显示十进制字符串形式的数字)
//不同进制的转换参考【OLED.h】
void Serial_SendNumber(uint32_t Number,uint8_t Length)
{
    //把Number的个、十、百位以十进制拆分开
    //转换成字符数字对应的数据并依次发送
    uint8_t i;
    for(i = 0; i < Length ; i ++)//循环Length次
    {
        Serial_SendByte(Number / Serial_Pow(10 , Length - i - 1) % 10 + '0' );
    }
    //i的遍历从0开始,10^0是个位;10^1是十位;10^2是百位,以此类推……
    /*假设Length为2——第一次循环【2-0-1】=1,10^1是十位
                   ——第二次循环【2-1-1】=0,10^0是个位    
    */
    //要以字符的形式显示需要加【偏移】(查ASCII码表)——0x30或'0"
    //参数会以十进制从高位到低位依次发送
}
/*
【fputc】是【printf】函数的底层
printf函数在打印的时候,就是不断调用fputc函数一个个打印的
把fputc重定向到串口,那printf自然就输出到串口了
*/
//移植printf函数
int fputc(int ch , FILE *f)
{
    //把fputc重定向到串口
    Serial_SendByte( ch );
    return ch;
}
2、在Serial.c中编写发送数据包函数 Serial_SendPacket
//调用函数,TxPacket数组的4个数据就会自动加上包头包尾发送
void Serial_SendPacket(void)
{
    //发送包头0xFF
    Serial_SendByte(0xFF);
    //依次发送4个载荷数据
    Serial_SendArray(Serial_TxPacket,4);
    //发送包尾0xFE
    Serial_SendByte(0xFE);
}
3、在Serial.h中声明初始化函数 Serial_Init和发送数据包函数 Serial_SendPacket发送/缓存数组
extern uint8_t Serial_TxPacket[];//声明数组外部可调用(数组声明可以不用数量)
void Serial_SendPacket(void);
//声明数组外部可调用(数组声明可以不用数量)
extern uint8_t Serial_TxPacket[];//发送缓存数组
extern uint8_t Serial_RxPacket[];//接收缓存数组
4、在主循环中编写程序主体
int main(void)
{
    OLED_Init();
    
    Serial_Init();
    
    //初始化之后先填充缓存区数组
    Serial_TxPacket[0] = 0x01;
    Serial_TxPacket[1] = 0x02;
    Serial_TxPacket[2] = 0x03;
    Serial_TxPacket[3] = 0x04;
    
    //SendPacker取出数组内容加上包头包尾一起发送
    Serial_SendPacket();
    
    while(1)
    {
        
    }
}
实现功能:上电后初始化串口,填充缓存区数组,通过SendPacket函数取出数组内容加上包头包尾发送
串口调试软件显示: FF 01 02 03 04 FE

【基于串口发送HEX数据包】的【串口收发HEX数据包】
1、在Serial.c中初始化函数 Serial_Init
#include "stm32f10x.h"                  // Device header
#include <stdio.h>
//为了收发数据包定义两个缓存区的数组
//只存储发送或接收的载荷数据
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxPacket[4];
//如果收到一个数据包就置RxFlag
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
//第一步:RCC开启USART和GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
//第二步:GPIO初始化,把TX配置成复用输出,RX配置成输入
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    //目前配置:PA9复用推挽输出供USART1的TX使用
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    //目前配置:PA10上拉输入供USART1的RX使用
    
    
//第三步:配置USART
    USART_InitTypeDef USART_InitSturucture;
    USART_InitSturucture.USART_BaudRate = 9600;//波特率(Init函数内部自动算出波特率对应分配系数)
    USART_InitSturucture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制
    USART_InitSturucture.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//选择发送(接收)模式,若都需要则用‘|’并起来
    USART_InitSturucture.USART_Parity = USART_Parity_No;//校验位
    USART_InitSturucture.USART_StopBits = USART_StopBits_1;//停止位
    USART_InitSturucture.USART_WordLength = USART_WordLength_8b;//字长
    USART_Init(USART1,&USART_InitSturucture);
    //目前配置:9600波特率、8位字长、无校验、1位停止位、无流控、只有发送模式
    
    
//第四步:开启中断
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
    //开启RXNE标志位到NVIC的输出
//第五步:配置NVIC
//RXNE标志位一但置1,就会向NVIC申请中断
//之后可用在中断函数里接收数据
//中断函数名称查找启动文件【startup_stm32f10x_md.s】
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组
    NVIC_InitTypeDef NVIC_InitStructure;//初始化NVIC的USART1通道
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
    
//第六步:开启USART,初始化完成
    USART_Cmd(USART1,ENABLE);
}
//获取接收标志位RxFlag
//实现读取后自动清除功能
uint8_t Serial_GetRxFlag(void)
{
    if(Serial_RxFlag == 1)
    {
        Serial_RxFlag = 0;
        return 1;
    }
    return 0;
}
//发送数据函数
//调用这个函数可以从TX引脚发送一个字节数据
void Serial_SendByte(uint8_t Byte)
{    
    //Byte变量写入发送数据寄存器TDR,TDR再传递给发送移位寄存器
    //最后一位一位地把数据移出到TX引脚,完成数据的发送
    USART_SendData(USART1,Byte);
    
    //等待TDR的数据全部转移到移位寄存器
    //数据还在TDR时仍写入数据会产生数据覆盖
    //【USART_FLAG_TXE】发送数据寄存器空标志位
    while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
    //数据寄存器不空则一直循环,数据寄存器空则跳出循环
}
//发送数组
/*
第一个参数:数组首地址(数组名)
第二个参数:指定传输多少字节
*/
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
    uint16_t i;
    for(i = 0; i < Length; i ++)//for循环执行Length次,可以对Array数据进行遍历
    {
        Serial_SendByte(Array[i]);
        //依次取出数组Array的每一项通过SendByte发送
    }
}
//发送字符串
//字符串自带一个结束标志位(数据0),因此不需要传递长度参数
void Serial_SendString(char *String)
{
    uint8_t i;
    for(i = 0; i < String[i] != 0; i ++)//循环条件用结束标志位判断
    {
        Serial_SendByte(String[i]);
        //依次取出字符串String的每一项通过SendByte发送
    }
}
/*
以十进制拆分数据
函数的返回值=X^Y
*/
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
    uint32_t Result = 1;
    while( Y -- )//循环Y次
    {
        Result *= X;//Result累乘Y次X(X的Y次方)
    }
    return Result;
}
//发送数字(显示十进制字符串形式的数字)
//不同进制的转换参考【OLED.h】
void Serial_SendNumber(uint32_t Number,uint8_t Length)
{
    //把Number的个、十、百位以十进制拆分开
    //转换成字符数字对应的数据并依次发送
    uint8_t i;
    for(i = 0; i < Length ; i ++)//循环Length次
    {
        Serial_SendByte(Number / Serial_Pow(10 , Length - i - 1) % 10 + '0' );
    }
    //i的遍历从0开始,10^0是个位;10^1是十位;10^2是百位,以此类推……
    /*假设Length为2——第一次循环【2-0-1】=1,10^1是十位
                   ——第二次循环【2-1-1】=0,10^0是个位    
    */
    //要以字符的形式显示需要加【偏移】(查ASCII码表)——0x30或'0"
    //参数会以十进制从高位到低位依次发送
}
/*
【fputc】是【printf】函数的底层
printf函数在打印的时候,就是不断调用fputc函数一个个打印的
把fputc重定向到串口,那printf自然就输出到串口了
*/
//移植printf函数
int fputc(int ch , FILE *f)
{
    //把fputc重定向到串口
    Serial_SendByte( ch );
    return ch;
}
//调用函数,TxPacket数组的4个数据就会自动加上包头包尾发送
void Serial_SendPacket(void)
{
    //发送包头0xFF
    Serial_SendByte(0xFF);
    //依次发送4个载荷数据
    Serial_SendArray(Serial_TxPacket,4);
    //发送包尾0xFE
    Serial_SendByte(0xFE);
}
2、在Serial.c中编写发送中断函数 USART1_IRQHandler
//中断函数
//用状态机执行接收逻辑(根据状态机顺序图)
//接收数据包然后把载荷数据存在【RxPacket】数组
void USART1_IRQHandler(void)
{    
    //定义一个标志当前状态的静态变量RxState(只在本函数使用)
    static uint8_t RxState = 0;
    
    //指示数据接收到哪一个了
    static uint8_t pRxPacket = 0;
    
    //判断标志位,如果置1说明收到数据,进入if
    if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)
    {
        //获取RxData
        uint8_t RxData = USART_ReceiveData(USART1);
        //根据RxState的不同进入不同的处理程序
        if(RxState == 0)//状态0:进入等待包头程序
        {
            if(RxData == 0xFF)//收到包头
            {
                RxState = 1;//转移到状态1
                //未收到包头,RxState仍为0
                pRxPacket = 0;//提前清零为状态1做准备
            }
        }
        else if(RxState == 1)//状态1:进入接收数据程序
        {
            //每进一次状态,数据转存一次缓存数组,同时存的位置++
            //依次接收4个数据存在RxPacket数组
            //第pRxPacket个数据等于RxData,将RxData存在接收数组里
            Serial_RxPacket[pRxPacket] = RxData;
            pRxPacket ++;//移动到下一位置
            if(pRxPacket >= 4)//4个载荷数据已经收完了
            {
                RxState = 2;//转移到状态2
            }
        }
        else if(RxState == 2)//状态2:进入等待包尾程序
        {
            if(RxData == 0xFE)//收到包尾
            {
                RxState = 0;//转移到状态0
                //未收到包头,RxState仍为2
                
                //此时代表一个数据包已经接收到,置一个接收标志位
                Serial_RxFlag =1;
            }
        }
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    }
}
3、在Serial.h中声明初始化函数 Serial_Init发送/接收数组
//声明数组外部可调用(数组声明可以不用数量)
extern uint8_t Serial_TxPacket[];//发送缓存数组
extern uint8_t Serial_RxPacket[];//接收缓存数组
4、在主循环中编写程序主体
int main(void)
{
    
    OLED_Init();
    
    Serial_Init();
    
    //初始化之后先填充缓存区数组
    Serial_TxPacket[0] = 0x01;
    Serial_TxPacket[1] = 0x02;
    Serial_TxPacket[2] = 0x03;
    Serial_TxPacket[3] = 0x04;
    
    //SendPacker取出数组内容加上包头包尾一起发送
    Serial_SendPacket();
    
    while(1)
    {
        //不断读取RxFlag
        if(Serial_GetRxFlag() == 1)//收到了数据包
        {
            OLED_ShowHexNum(1,1,Serial_RxPacket[0],2);
            OLED_ShowHexNum(1,4,Serial_RxPacket[1],2);
            OLED_ShowHexNum(1,7,Serial_RxPacket[2],2);
            OLED_ShowHexNum(1,10,Serial_RxPacket[3],2);
        }
        
    }
}
实现功能:上电后初始化串口,填充缓存区数组,通过串口调试软件发送 FF xx xx xx xx FE
串口调试软件显示: FF xx xx xx xx FE

【最终功能】串口收发HEX数据包

在主循环中编写程序主体
uint8_t KeyNum;
int main(void)
{
    
    OLED_Init();
    Key_Init();
    Serial_Init();
    
    OLED_ShowString(1,1,"TxPacket");
    OLED_ShowString(3,1,"RxPacket");
    //初始化之后先填充缓存区数组
    Serial_TxPacket[0] = 0x01;
    Serial_TxPacket[1] = 0x02;
    Serial_TxPacket[2] = 0x03;
    Serial_TxPacket[3] = 0x04;
    
    while(1)
    {
        //按下按键变换数据,发送到串口助手上
        KeyNum = Key_GetNum();
        if(KeyNum == 1)//按键按下执行发送
        {
            //变换之前填充的缓存区数据
            Serial_TxPacket[0] ++;
            Serial_TxPacket[1] ++;
            Serial_TxPacket[2] ++;
            Serial_TxPacket[3] ++;
            
            //SendPacker取出数组内容加上包头包尾一起发送
            Serial_SendPacket();
            
            OLED_ShowHexNum(2,1,Serial_TxPacket[0],2);
            OLED_ShowHexNum(2,4,Serial_TxPacket[1],2);
            OLED_ShowHexNum(2,7,Serial_TxPacket[2],2);
            OLED_ShowHexNum(2,10,Serial_TxPacket[3],2);
        }
        
        
        //不断读取RxFlag
        if(Serial_GetRxFlag() == 1)//收到了数据包
        {
            OLED_ShowHexNum(4,1,Serial_RxPacket[0],2);
            OLED_ShowHexNum(4,4,Serial_RxPacket[1],2);
            OLED_ShowHexNum(4,7,Serial_RxPacket[2],2);
            OLED_ShowHexNum(4,10,Serial_RxPacket[3],2);
        }
    }
}
实现功能:上电后初始化串口,填充缓存区数组,按下按键缓存区数组数据++,发送到串口助手上;
并且通过串口调试软件发送 FF xx xx xx xx FE, 串口调试软件显示: FF xx xx xx xx FE

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32F103C8T6是一款基于ARM Cortex-M3内核的微控制器,其中包含一个串口接口(USART),可用于串口通信。通过使用STM32CubeMX软件和STM32库来配置和控制USART接口,可以实现收发数据。 ### 回答2: STM32F103C8T6是一款常见的ARM Cortex-M3微控制器,具有强大的功能和灵活的输入输出能力,尤其是在串口通信方面。本文将介绍如何使用STM32F103C8T6的USART模块实现串口收发功能。 首先,需要在STM32F103C8T6的引脚分配中,确定USART使用的引脚。USART有两个引脚分配方式:使用PA9和PA10引脚或者使用PB6和PB7引脚,需要根据具体情况进行选择。同时,在程序编写时,也需要引入相关的库文件。 在代码编写方面,为了方便管理,通常会将串口收发的相关操作封装到一个函数中。下面是一个实现串口接收方式的函数: ```c void USART1_IRQHandler(void) { uint8_t ucData; if (USART1->SR & USART_SR_RXNE) { ucData = USART1->DR; USART1->DR = ucData; } } ``` 首先,定义了一个变量ucData,用于存储收到的数据。在中断服务函数中,首先需要判断是否接收到数据,通过检查USART_SR_RXNE标志位可以实现。如果接收到数据,则将数据存储到ucData变量中,并将数据发送回去,这可以通过将ucData赋值给USART1->DR进行实现。 接下来是串口发送方式的函数: ```c void USART1_SendData(uint8_t ucData) { while ((USART1->SR & USART_SR_TC) == 0) {}; USART1->DR = ucData; } ``` 通过使用while循环,检查USART_SR_TC标志位,等待发送完成。然后,通过将数据写入USART1->DR实现数据发送。在Main函数中调用这些函数,即可实现串口收发功能。 总之,通过相应的引脚分配、库文件引入以及编写串口发送和接收函数,我们可以轻松实现STM32F103C8T6的USART串口收发功能,实现与其他设备的数据传输。 ### 回答3: stm32f103c8t6是一款非常流行的微控制器,并且它有内置的USART串口模块,可以方便地进行串口通信。USART串口有许多不同的配置参数,包括波特率、数据位、停止位、奇偶校验位等等。在本文中,我们将通过stm32f103c8t6的USART串口收发实现一个简单的通信程序。 首先,我们需要在stm32f103c8t6的引脚中选择USART串口对应的引脚进行连接。USART串口可以选择两个不同的引脚组进行连接,分别是PA9和PA10,以及PB6和PB7。在本示例中,我们将使用PA9和PA10进行串口通信。其中,PA9对应USART1_TX引脚,PA10对应USART1_RX引脚。 接下来,我们需要进行USART串口的初始化配置。具体的配置参数包括波特率、数据位、停止位、奇偶校验位等等。在本示例中,我们将选择9600波特率、8位数据位、1位停止位、无奇偶校验位。至于为什么选择这些参数,主要是因为它们是常用的配置,应用广泛,同时也非常稳定可靠。 USART串口初始化之后,我们就可以进行数据的收发了。在本示例中,我们将设置单片机发送端,使用USART串口发送一段字符串数据。同时,我们也将设置单片机为接收端,接收来自计算机或其他串口设备发送过来的数据。为了简化操作,我们将使用stm32f103c8t6的内置的USART中断机制。这样就可以让单片机在接收和发送数据时,能够及时地响应并处理数据。 总之,stm32f103c8t6内置的USART串口模块是非常强大和灵活的,可以满足各种不同的串口通讯需求。通过合理地配置串口参数和使用中断机制,我们可以轻松地实现高效、可靠的数据收发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值