STM32F103ZET6+USART+串口通信

STM32F103ZET6+USART+串口通信

一、 通信概述

通信就是数据交换、信息交换。嵌入式系统中,微控制器与其他外围设备相互连接,系统各部件之间进行数字信号/数据的传输就是通信,无论是大型嵌入式系统还是小型嵌入式系统,都需要用到通信。

通信的方式有很多种,按数据传送方式可分为串行通信和并行通信;按通信数据同步方式可分为同步通信和异步通信;在串行通信中按数据传输方向及与时间的关系可分为单工通信、半双工通信和全双工通信。

在这里插入图片描述

二、 串行通信与并行通信

串行通信(Serial Transmission),是指通过一根数据线或少量数据线(少于8根)将数据一位一位地按顺序依次传送。

并行通信(Parallel Transmission),是指用多条数据线同时传送多位数据,通常以8位、16位、32位等数据位传送。并行通信一次可传输多个数据位的数据,并行通信传输数据量是串行传输的数倍,如早期的并行接口的硬盘、打印机,采用PCI(Peripheral Component Interconnect,外设部件互连标准)并行接口的显卡等。

并行传输的缺点:长距离传输成本较高;信号线之间的干扰大,传输速率很难达到很高;体积大,占用空间大,不利于设备的小型化。

三、 同步通信与异步通信

同步通信是连续串行传送数据的通信方式,要求收发双方的时钟必须保持严格的同步。特点:输速率较高

异步通信在发送的有效数据中增加一些用于同步的控制位,比如开始位和停止位等,数据以字符为单位组成数据帧进行传送,收发双方需约定数据的传输速率。特点:传输效率较低;通信设备实现简单、成本低。

四、单工、半双工、全双工通信

根据数据传输方向以及与时间的关系,串行通信可以分为单工、半双工和全双工三种通信方式。

在这里插入图片描述
波特率:每秒传输的二进制位数,单位为比特每秒(bit/s,bps),是衡量串行数据传输速度快慢的指标。

字符速率:每秒所传输的字符数:波特率=字符速率×每个字符包含的位数

五、 异步串行通信协议

异步串行通信标准的数据帧由起始位、数据位、校验位、停止位四部分组成。数据传输速率为50、75、100、150、300、600、1200、2400、4800、9600、19200和38400波特。

起始位:占一位,位于数据帧的开头,以逻辑“0”表示传输数据的开始。

数据位:要发送的数据,数据长度可以是5~8位。

校验位:占一位,用于检测数据是否有效。

停止位:一帧传送结束的标志,根据实际情况定,可以是1、1.5或2位。

空闲位:数据传输完毕,用“1”表示当前线路上没有数据传输。

UART(Universal Asynchronous Receiver Transmitter,通用异步收发传输器)是一个全双工通用异步串行收/发模块,主要用于打印程序调试信息、上位机和下位机的通信以及ISP程序下载等场合。
UART至少需要两根数据线用于通信双方进行数据双向同时传输,最简单的UART接口由TxD、RxD、GND共3根线组成。其中,TxD用于发送数据,RxD用于接收数据,GND为信号地线,通过交叉连接实现两个芯片间的串口通信。

在这里插入图片描述

六、STM32 USART编程模式

1、轮询模式

CPU不断地查询I/O设备是否准备就绪,如果准备就绪就发送,否则提示超时错误;会占用CPU的大量时间,效率低。

2、 中断方式

通过中断请求线,在I/O设备准备就绪时向CPU发出中断请求,CPU中止正在进行的工作转向处理I/O设备的中断事件;中断方式相比轮询方式效率较高。

3、DMA方式

直接存储器传送,不经过CPU直接在内存和外设之间进行批量数据交换,适用于高速大批量成组数据的传输;满足高速I/O设备的传输要求,有利于提高CPU的利用率。

USART串口应用编程步骤
在这里插入图片描述
1、声明GPIO和USART初始化结构体

USART_InitTypeDef  USART_InitStructure;

2、串口所用的GPIO时钟使能,串口时钟使能

开启外设时钟RCC_APB2PeriphClockCmd()。例如:使能USART1、GPIOA的时钟,所用的函数为

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);

3、 设置I/O引脚功能为复用推挽输出、浮空输入

串口使用的是I/O的复用功能。USART1的发送引脚为PA9,需将PA9配置为复用推挽输出;USART1的输入引脚为PA10,需将PA10配置为浮空输入。

//USART1_TX,PA9,配置为复用推挽输出,并初始化PA9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); 
//USART1_RX,PA10,配置为浮空输入,并初始化PA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10

4、 设置波特率,设置数据格式:数据位、停止位、校验位

USART_InitStructure.USART_BaudRate = 115200;                                   //串口波特率
USART_InitStructure.USART_WordLength= USART_WordLength_8b;                     //设置数据位占8位
USART_InitStructure.USART_StopBits = USART_StopBits_1;                         //设置停止位占1位
USART_InitStructure.USART_Parity = USART_Parity_No;                            //无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  //不采用硬件数据流控制
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;                    //设置为收发模式

5、使用串口初始化函数USART_Init()初始化相应串口

USART_Init(USART1, &USART_InitStructure);//初始化串口1

6、利用串口使能函数USART_Cmd()使能相应串口

USART_Cmd(USART1, ENABLE);//使能串口

7、应用程序编写
若使用中断,则编写串口中断函数void USART1_IRQHandler(void)

接下来,设计通过串口1利用查询方式实现发送字符命令"Y"点亮LED灯,发送字符命令"N"熄灭LED灯。并且重定向printf()函数和scanf()函数,即重写fput()函数和fget()函数

采用查询方式进行数据通信

在之前的LED工程上,新建两个文件,一个是myusart.h文件,另一个是myusart.c文件

myusart.h文件的代码如下:

#ifndef __MYUSART_H
#define __MYUSART_H

#include "stm32f10x.h"
#include <stdio.h>


void USART_Init_Config(void);

#endif

myusart.c文件的代码如下:

#include "myusart.h"


void USART_Init_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);  //开始USSART1和GPIOA的时钟
	USART_DeInit(USART1);                                                        //¸复位USART1
    
    //USART1_TX   PA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         //选择要使用的I/O引脚,此处选择PA9引脚
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的输出速度为50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	  //设置引脚输出模式为复用推挽输出模式
    GPIO_Init(GPIOA, &GPIO_InitStructure); 
   
    //USART1_RX	  PA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;            //选择要使用的I/O引脚,此处选择PA10引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置引脚输入模式为浮空输入模式
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    //USART1 配置
	USART_InitStructure.USART_BaudRate = 115200;                                   //设置波特率为115200
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    //数据位占8位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;                         //设置1位停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;                            //设置无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//设置不采用硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                //设置为收/发模式
	USART_Init(USART1, &USART_InitStructure);                                      //初始化串口1
    USART_Cmd(USART1, ENABLE);                                                     //使能串口1
}


//重定向printf函数
int fputc(int ch, FILE *f)
{
		USART_SendData(USART1, (uint8_t) ch);
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

//重定向scanf函数
int fgetc(FILE *f)
{
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(USART1);
}

main.c文件的代码如下:

#include "stm32f10x.h"
#include "led.h"	
#include "myusart.h"


int main(void)
{
		char ch;
		LED_Init();
		USART_Init_Config();

		while(1)
		{
			ch = getchar();
			printf("接收到的指令º%c \n",ch);
			switch(ch)
			{
				 case 'N':
					 GPIO_SetBits(GPIOB,GPIO_Pin_5);     //熄灭LED灯
					 printf("熄灭LED灯\n");
					 break;
				 case 'Y':
					 GPIO_ResetBits(GPIOB,GPIO_Pin_5);   //点亮LED灯
					 printf("点亮LED灯\n");
					 break;
				 default:
					 printf("请输入正确的指今,N熄灭灯,Y点亮灯!\n");
					 break;
			 }
		}
		
}

运行效果

打开串口调试助手
在这里插入图片描述

接下来,设计通过串口1利用中断方式实现发送字符命令"1"点亮LED灯,发送字符命令"0"熄灭LED灯。并且重定向printf()函数和scanf()函数,即重写fput()函数和fget()函数

采用中断方式进行数据通信

myusart.h文件的代码如下:

#ifndef __MYUSART_H
#define __MYUSART_H

#include "stm32f10x.h"
#include <stdio.h>


void USART_Init_Config(void);

#endif

myusart.c文件的代码如下:

#include "myusart.h"


void USART_Init_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   //定义一个GPIO_InitTypeDef类型的结构体变量,用于配置GPIo引脚
	USART_InitTypeDef USART_InitStructure; //定义一个USART_InitTypeDer类型的结构体变量,用于配置串口
    NVIC_InitTypeDef NVIC_InitStructure;   //定义一个NVIC_InitTypeDef类型的结构体变量,用于配置中断优先级
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //开始USART1和GPIOA的时钟
	USART_DeInit(USART1);                                                       //复位USART1
    
    //USART1_TX   PA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         //选择要使用的I/O引脚,此处选择PA9引脚
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的输出速度为50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	  //设置引脚输出模式为复用推挽输出模式
    GPIO_Init(GPIOA, &GPIO_InitStructure); 
   
    //USART1_RX	  PA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;            //选择要使用的I/O引脚,此处选择PA10引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置引脚输入模式为浮空输入模式
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    //USART1 配置
	USART_InitStructure.USART_BaudRate = 115200;                                   //设置波特率为115200
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    //数据位占8位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;                         //设置1位停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;                            //设置无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//设置不采用硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;;               //设置为收/发模式
    
    USART_ClearFlag(USART1,USART_FLAG_TC);       //清除发送完成标准
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //打开串口1的接收中断
    USART_ITConfig(USART1,USART_IT_TC,ENABLE);   //开始串口1的发送中断
	USART_Init(USART1, &USART_InitStructure);    //初始化串口1
    USART_Cmd(USART1, ENABLE);                   //使能串口1
    
    //  NVIC USART1 中断配置
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);           //选择中断优先级分组2
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;         //外部USART1中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级为0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //设置响应优先级为0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道
    NVIC_Init(&NVIC_InitStructure); 
}


//重定向printf函数
int fputc(int ch, FILE *f)
{
		USART_SendData(USART1, (uint8_t) ch);
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

//重定向scanf函数
int fgetc(FILE *f)
{
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(USART1);
}


//中断处理函数
void USART1_IRQHandler(void)
{
    uint8_t Rx_Data;
    if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)
    {
        Rx_Data = (uint8_t)USART_ReceiveData(USART1);
        
        printf("输出的命令是 %c \n",Rx_Data);
        switch(Rx_Data)
        {
            case '0':
                GPIO_SetBits(GPIOB,GPIO_Pin_5);
                printf("熄灭LED灯\n");
            break;
            case '1':
                GPIO_ResetBits(GPIOB,GPIO_Pin_5);
                printf("点亮LED灯 \n");
            break;
            default:
                printf("输入了错误的指令,请重新输入! \n");
            break;
        }
    }
		
}

main.c文件的代码如下:

#include "stm32f10x.h"
#include "led.h"	
#include "myusart.h"


int main(void)
{
		LED_Init();
		USART_Init_Config();

		while(1)
		{

		}
		
}

运行效果

打开串口调试助手
在这里插入图片描述

接下来,设计通过串口1利用DMA方式实现循环发送字符。

采用DNA方式进行数据通信

myusart.h文件的代码如下:

#ifndef __MYUSART_H
#define __MYUSART_H

#include "stm32f10x.h"
#include <stdio.h>

#define  SENDBUFF_SIZE    100


void USARTx_Init_Config(void);
void USARTx_DMA_Config(void);


#endif

myusart.c文件的代码如下:

#include "myusart.h"


uint8_t SendBuff[SENDBUFF_SIZE];

void USARTx_Init_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);  //开启USART1和GPIOA的时钟
	USART_DeInit(USART1);                                                        //¸复位USART1
    
    //USART1_TX   PA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         //选择要使用的I/O引脚,此处选择PA9引脚
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的输出速度为50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	  //设置引脚输出模式为复用推挽输出模式
    GPIO_Init(GPIOA, &GPIO_InitStructure); 
   
    //USART1_RX	  PA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;            //选择要使用的I/O引脚,此处选择PA10引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置引脚输入模式为浮空输入模式
    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    //USART1 
	USART_InitStructure.USART_BaudRate = 115200;                                   //设置波特率为115200
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    //数据位占8位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;                         //设置1位停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;                            //设置无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//设置不采用硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                //设置为收/发模式
	USART_Init(USART1, &USART_InitStructure);                                      //初始化串口1
    USART_Cmd(USART1, ENABLE);                                                     //使能串口1
	USART_ClearFlag(USART1, USART_FLAG_TC|USART_FLAG_TXE|USART_FLAG_RXNE);         //清除发送完成标志
}


void USARTx_DMA_Config(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  /* 开启DNA时钟 */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  /*设置DNA源:串口数据寄存器地址*/  
  DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(&(USART1->DR));	
  /*内存地址(要传输的变量指针)*/
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff;
  /*方向:从内存到外设*/		
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;	
  /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/	
  DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
  /*外设地址不增*/	    
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
  /*内存地址自增*/
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	
  /*外设数据单位*/	
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  /*内存数据单位 8bit*/
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;	 
  /*DMA模式:不断循环*/
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	 
  /*优先级:中*/	
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
  /*禁止内存到内存的传输*/
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  /*配置DMA1的4通道*/		   
  DMA_Init(DMA1_Channel4, &DMA_InitStructure);
  /*使能DMA*/
  DMA_Cmd (DMA1_Channel4,ENABLE);			
  /* 配置DMA发送完成后产生中断 */
  DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);  
}


//重定向printf函数
int fputc(int ch, FILE *f)
{
		USART_SendData(USART1, (uint8_t) ch);
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}


//重定向scanf函数
int fgetc(FILE *f)
{
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(USART1);
}

main.c文件的代码如下:

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"	
#include "myusart.h"


extern uint8_t SendBuff[SENDBUFF_SIZE];

int main(void)
{
    uint16_t i;
    
	delay_init();
	LED_Init();           //LED初始化
    USARTx_Init_Config(); //USART1初始化
    USARTx_DMA_Config();  //DMA初始化

    printf("使用DMA方式传输串口数据\n");
  
    /*输入要发送的数据,这里选用A作用A作为DMA传送的数据源*/
    for(i=0;i<SENDBUFF_SIZE;i++)
    {
        SendBuff[i]	 = 'A';
    }
    /* USART1 向DMA发出TX请求 */
    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); 

		while(1)
		{
			GPIO_SetBits(GPIOB,GPIO_Pin_5);
			delay_ms(1000);
			GPIO_ResetBits(GPIOB,GPIO_Pin_5);
			delay_ms(1000);
		}
		
}

运行效果

打开串口调试助手
在这里插入图片描述

  • 10
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32F103ZET6是一款基于ARM Cortex-M3内核的单片机,具有丰富的外设,包括串口模块。而串口Modbus RTU是一种常用的工业通信协议,用于实现不同设备间的通信。 在STM32F103ZET6上实现串口Modbus RTU,需要进行以下步骤: 1. 硬件连接:将STM32F103ZET6的串口模块连接到Modbus RTU网络中的设备上,可以通过RS485或者RS232接口进行连接。 2. 配置串口:在STM32F103ZET6上配置串口的参数,包括波特率、数据位、停止位和奇偶校验位等,以适配Modbus RTU的通信要求。 3. 实现Modbus RTU协议:根据Modbus RTU协议的要求,编写程序来处理串口接收到的数据,并解析出Modbus的功能码和数据内容,然后进行相应的处理和响应。 4. 数据交换:根据Modbus RTU协议的指令集,通过串口模块与其他Modbus RTU设备进行数据的发送和接收。可以使用STM32F103ZET6的串口发送和接收函数来实现数据的传输。 5. 错误处理:在实现过程中,需要处理Modbus RTU通信过程中可能出现的错误,如校验错误、超时错误等,以保证通信的可靠性。 总之,通过使用STM32F103ZET6的串口模块,配合编程实现Modbus RTU协议的数据处理和通信操作,可以实现STM32F103ZET6与其他Modbus RTU设备的通信。同时,可以根据具体应用需求,进一步优化和扩展功能。 ### 回答2: STM32F103ZET6是一款强大的微控制器芯片,它具有串口通信功能,可以用于实现Modbus RTU通信协议。 Modbus RTU是一种常用的串口通信协议,主要用于工业自动化领域。它基于RS-485物理层通信,通过发送和接收数据帧来实现设备之间的通信。 在STM32F103ZET6上实现Modbus RTU通信,需要使用其内置的UART模块,配合相关的软件开发工具进行开发。 首先,我们需要配置UART模块的相关参数,如波特率、数据位数、校验位等。然后,将该模块连接到RS-485通信线路上,以便与其他设备进行数据交换。 接下来,我们需要编写相关的软件代码。在STM32F103ZET6上,可以使用C语言或者汇编语言进行编程。我们需要编写发送和接收函数,以实现Modbus RTU通信的功能。 在发送函数中,我们需要将要发送的数据帧按照协议规定的格式进行封装,并通过UART模块发送出去。在接收函数中,我们需要监听UART模块接收到的数据,并根据协议规定的格式对数据进行解析和处理。 最后,我们可以根据具体的应用需求,设计和实现更高级的功能,如读取和写入数据寄存器、处理异常情况等。 总的来说,STM32F103ZET6可以作为一个强大的控制器,利用其串口功能实现Modbus RTU通信协议。通过合适的配置和编程,我们可以实现设备之间的高效数据交换和控制,从而满足工业自动化应用的需求。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值