单片机:实现SPI通信(完整源码)

单片机实现SPI通信详解

作者:Katie
代码日期:2025-03-28


目录

  1. 项目简介
    1.1 项目背景
    1.2 什么是SPI通信
    1.3 项目目标与意义

  2. 相关理论与基础知识
    2.1 SPI通信的基本概念
    2.2 SPI协议的工作原理
    2.3 主从模式与全双工传输
    2.4 SPI的时序与信号线
    2.5 常见应用场景与优势

  3. 系统设计与实现思路
    3.1 系统总体架构
    3.2 硬件设计方案
    3.2.1 单片机与SPI接口连接
    3.2.2 外围设备与接口匹配
    3.2.3 供电与信号调理设计
    3.3 软件设计思路
    3.3.1 SPI通信流程与数据传输
    3.3.2 数据编码与解析
    3.3.3 中断与轮询实现方式
    3.4 系统数据流程图

  4. 详细代码实现
    4.1 代码整体结构说明
    4.2 完整代码(整合版,附详细注释)

  5. 代码解读
    5.1 系统初始化与外设配置
    5.2 SPI接口驱动与数据传输实现
    5.3 数据编码与协议解析
    5.4 中断与轮询方式比较
    5.5 调试信息输出与错误处理

  6. 系统调试与测试
    6.1 硬件调试方法
    6.2 软件调试与数据验证
    6.3 系统稳定性与性能测试

  7. 项目总结与心得
    7.1 项目成果总结
    7.2 项目中的挑战与收获
    7.3 后续改进与扩展方向

  8. 参考资料与扩展阅读


1. 项目简介

1.1 项目背景

在嵌入式系统中,数据传输与通信是实现系统互联和控制的重要环节。SPI(Serial Peripheral Interface)通信协议因其高速、全双工传输以及实现简单的特点被广泛应用于单片机与传感器、存储器、显示模块等外设之间的数据交换。与UART、I²C等通信方式相比,SPI具有传输速率高、硬件结构简单、适用于短距离高速通信等优点。

本项目的背景在于开发一个基于单片机的SPI通信系统,用于实现数据传输。无论是从传感器采集数据,还是与其他外设交换信息,SPI通信都是一种高效且可靠的选择。通过本项目,开发者可以深入理解SPI协议的时序、数据传输机制以及主从设备间的数据交互方式。

1.2 什么是SPI通信

SPI通信是一种同步串行通信协议,采用主从模式进行数据传输。SPI通信通常由四根信号线组成:

  • MOSI(Master Out Slave In):主设备向从设备发送数据;

  • MISO(Master In Slave Out):从设备向主设备发送数据;

  • SCLK(Serial Clock):由主设备生成的时钟信号;

  • SS(Slave Select):用于选择某个从设备进行通信。

SPI协议支持全双工传输,即主设备与从设备可以同时发送和接收数据。由于不需要复杂的握手协议,SPI传输速度快、实现简单,非常适合在短距离内高效传输数据。

1.3 项目目标与意义

本项目主要目标是利用单片机实现SPI通信功能,涵盖数据传送、数据编码与解析、错误检测与调试输出等方面。具体目标包括:

  • 实现单片机与外部SPI设备之间的高速数据交换;

  • 编写SPI通信驱动程序,实现数据发送和接收功能;

  • 通过UART或其他调试接口输出传输数据和系统状态,验证SPI通信的稳定性和正确性;

  • 为后续复杂系统(如传感器数据采集、多设备通信)提供可扩展的SPI通信模块。

项目意义在于掌握SPI通信协议的核心原理和实现方法,为嵌入式系统的数据传输和设备互联提供坚实的技术基础,同时为后续项目的开发和优化积累经验。


2. 相关理论与基础知识

2.1 SPI通信的基本概念

SPI(Serial Peripheral Interface)是一种串行数据传输协议,其基本特点包括:

  • 同步通信:由主设备提供时钟信号,同步传输数据;

  • 全双工模式:主从双方可以同时发送和接收数据;

  • 主从架构:由一个主设备和一个或多个从设备组成,主设备控制所有数据传输;

  • 简单高效:不需要复杂握手信号,数据传输速率高。

2.2 SPI协议的工作原理

SPI协议的通信过程主要包括:

  • 数据发送:主设备通过MOSI线向从设备发送数据;

  • 数据接收:从设备通过MISO线将数据返回给主设备;

  • 时钟控制:SCLK由主设备生成,同步数据传输;

  • 设备选择:SS(或CS)信号用于选择需要通信的从设备,通常为低有效。

数据传输时,数据位通常按照从最高位到最低位顺序发送,传输过程中主设备不断提供时钟脉冲,使数据在MOSI和MISO线上同步传输。

2.3 主从模式与全双工传输

  • 主从模式:SPI通信中,主设备控制数据传输,决定何时发送和接收数据。从设备只在被选中时响应主设备的命令。

  • 全双工传输:在同一时刻,主设备与从设备可以同时进行数据传输,极大提高通信效率。

2.4 SPI的时序与信号线

SPI协议中主要的信号线及其作用:

  • MOSI:主设备输出的数据线;

  • MISO:从设备输出的数据线;

  • SCLK:主设备生成的时钟信号,决定数据传输速率;

  • SS/CS:从设备选择信号,低电平表示该设备被选中进行通信。

SPI时序要求数据在时钟上升沿或下降沿采样,具体取决于所使用的SPI模式(共有四种模式),在配置中需要确保主从双方采用一致的时序参数。

2.5 常见应用场景与优势

SPI通信广泛应用于:

  • 传感器数据采集:高速传输传感器采集的数据;

  • 存储器接口:与外部Flash、EEPROM等存储器进行数据交换;

  • 显示控制:与LCD、OLED等显示设备通信;

  • 无线通信模块:连接蓝牙、Wi-Fi等模块。

SPI的主要优势在于传输速率高、实现简单、硬件资源占用少,适用于短距离内高效数据交换。


3. 系统设计与实现思路

3.1 系统总体架构

本系统采用单片机作为主控制单元,通过SPI接口与外设(如传感器、存储器或其他模块)进行数据传送。系统总体架构包括以下模块:

  • 数据采集模块:采集模拟或数字数据,存储于内存中;

  • 数据编码与传输模块:将采集数据按照预定格式进行编码,通过SPI发送给目标设备;

  • 数据接收与解析模块:在从设备上接收数据后进行解析,确保数据正确传输;

  • 调试输出模块:利用UART输出传输数据和系统状态,便于调试和系统监控。

3.2 硬件设计方案

3.2.1 单片机与SPI接口连接
  • SPI接口引脚分配:将单片机的SPI相关引脚(MOSI、MISO、SCLK和SS)连接至外设对应引脚。

  • 信号电平匹配:确保单片机和SPI外设工作在相同的电压等级,必要时使用电平转换电路。

  • 供电与抗干扰设计:采用稳压电源,并在信号线上增加滤波元件和屏蔽措施,提高通信的稳定性。

3.2.2 数据传送外设与接口设计
  • 传感器或存储器接口:根据具体应用设计与SPI通信外设的连接方案,例如连接外部传感器、Flash存储器或无线模块。

  • 调试接口:利用UART接口输出通信状态和调试数据,便于系统开发与调试。

3.2.3 供电与信号调理
  • 稳压电源:确保单片机及所有通信模块获得稳定的供电,降低噪声对数据传输的干扰。

  • 信号滤波:在SPI信号线上增加适当的滤波措施,确保信号清晰,防止高频干扰导致数据错误。

3.3 软件设计思路

3.3.1 数据传送流程与协议实现
  • 数据采集与编码:采集传感器数据或其他输入数据,并将其转换为适合传输的格式(如ASCII码、二进制流或自定义数据包格式)。

  • SPI通信实现:配置单片机SPI模块或利用软件模拟SPI通信,按照SPI协议的时序,依次发送和接收数据。

  • 数据解析与校验:在数据接收端对传输数据进行解析,必要时加入校验码以确保数据传输正确。

3.3.2 中断与轮询的实现方案
  • 中断驱动方式:利用外部中断或SPI模块中断,实现数据传输的即时响应和高效处理。

  • 轮询方式:在主循环中不断检查通信状态,适用于传输速率要求不高的场合。

  • 两种方式结合:根据实际应用场景,结合中断与轮询,达到最佳性能和平衡系统资源占用。

3.3.3 调试接口与状态反馈
  • UART调试输出:通过UART接口将数据传送状态、错误信息、传输数据等输出到PC终端,便于实时监控与调试。

  • LCD显示:可选加入LCD模块,实现图形化界面显示,增强用户体验。

3.4 系统数据流程图

┌────────────────────────────┐
│         系统上电初始化        │
└──────────────┬─────────────┘
               │
               ▼
┌────────────────────────────┐
│    数据采集与编码模块         │
└──────────────┬─────────────┘
               │
               ▼
┌────────────────────────────┐
│    SPI通信数据传输模块        │
│  (数据发送与接收)           │
└──────────────┬─────────────┘
               │
               ▼
┌────────────────────────────┐
│  数据解析与校验模块           │
└──────────────┬─────────────┘
               │
               ▼
┌────────────────────────────┐
│  调试信息输出与状态反馈模块    │
└────────────────────────────┘

3.5 软件模块划分

软件主要模块包括:

  • 系统初始化模块:完成单片机各外设(I/O、定时器、SPI、UART)的初始化;

  • 数据采集模块:采集原始数据,并进行编码、格式化处理;

  • SPI通信模块:实现SPI数据传输,包含数据发送与接收函数;

  • 数据解析模块:解析接收到的数据包,进行校验和错误检测;

  • 调试输出模块:通过UART输出通信状态、数据内容和错误信息;

  • 错误处理与重传模块:预留错误处理接口,确保数据传输的可靠性(可扩展)。


4. 详细代码实现

下面给出完整代码(整合版),代码中整合了单片机初始化、数据采集、SPI通信、数据解析与UART调试输出功能。所有代码均附有详细注释,便于后续理解和扩展。
(注:代码示例基于51单片机平台,实际应用中可根据具体硬件环境进行调整。)

4.1 完整代码(整合版)

5. 代码解读

下面对各模块代码功能进行详细解读:

5.1 系统初始化与外设配置

  • SystemInit:在系统上电后,初始化全局变量(如系统时间、采集数据变量)和各端口状态,确保SPI、UART及其他外设工作于已知状态,为后续数据采集与传送做好准备。

  • Timer0_Init:配置8位定时器0为16位模式,并根据系统时钟设置重载值,实现每1ms一次中断,用于更新时间(systemTime_ms)并为数据采集提供时间基准。

  • UART_Init:初始化UART模块,配置为模式1,波特率9600,为系统调试输出提供稳定的通信接口。

  • SPI_Init:通过软件模拟SPI通信,配置MOSI、MISO、SCLK和片选引脚的初始状态,为后续数据传输做准备。

5.2 SPI接口驱动与数据传输实现

  • SPI_Transfer:核心函数,采用软件模拟SPI数据传输。函数从数据的最高位开始依次发送,每个时钟脉冲期间将MOSI上的数据传输给外设,并同时从MISO读取返回数据,实现全双工数据交换。

  • TLC2543或其他外设通信:在本示例中,数据传送模块调用SPI_Transfer实现数据发送与接收。实际应用中,可根据具体通信协议构建数据传输格式。

5.3 数据编码与协议解析

  • Get_SensorData:模拟传感器数据采集函数,在实际应用中应替换为真实ADC读取函数。函数模拟数据在0~1023范围内循环变化,为数据传送提供原始数据。

  • Process_Data:对采集数据进行预处理,当前示例中直接传递数据,后续可增加滤波、校准或数据格式转换。

  • Transmit_Data:将处理后的数据与系统时间一起通过UART接口以字符串形式输出,便于调试和数据验证。此函数整合了数据编码与格式化输出过程。

5.4 中断与轮询方式比较

  • 定时器中断(Timer0_ISR):用于实现系统时间更新和为数据采集提供时间基准。中断方式具有实时性好、资源占用低的优点,确保数据采集间隔稳定。

  • 主循环轮询:主循环中不断调用数据采集、处理和传送函数,结合定时器中断实现系统整体协调工作,确保数据传送稳定且响应及时。

5.5 调试信息输出与错误处理

  • UART发送函数:UART_SendChar、UART_SendString和UART_SendNumber等函数实现字符串与数字的转换和发送,通过UART接口输出调试信息,为开发者提供实时系统状态与数据传送情况。

  • 错误处理与数据校验:本示例中未加入复杂的错误检测机制,实际应用中可扩展数据校验和重传机制,确保数据传输的可靠性。


6. 系统调试与测试

6.1 硬件调试方法

  • SPI信号检测:利用示波器检测MOSI、MISO、SCLK和CS信号,确保SPI数据传输时序和电平正确。

  • 供电与接线检查:检查单片机和外设的供电是否稳定,确保所有I/O引脚正确连接,防止因电压波动和干扰导致数据传输错误。

6.2 软件调试与数据验证

  • 数据采集验证:通过调试器观察Get_SensorData返回值,确保数据在预定范围内变化,并验证Process_Data函数的处理效果。

  • UART调试输出:使用串口调试工具检查Transmit_Data函数输出的信息,验证数据传送和系统时间是否正确显示。

  • 定时器中断验证:观察systemTime_ms的累加情况,确保定时器中断按照1ms周期触发,保证数据采集周期稳定。

6.3 系统稳定性与性能测试

  • 连续运行测试:长时间运行系统,检测数据采集与传送是否稳定,确保不会因中断漂移或内存泄露导致错误。

  • 误差分析与校准:对比实际采集数据与标准数据,分析可能存在的误差来源,必要时调整延时与中断配置。


7. 项目总结与心得

7.1 项目成果总结

本项目成功实现了基于单片机的数据传送系统,主要成果包括:

  • 通过软件模拟SPI接口,实现了数据的高速全双工传输;

  • 利用定时器中断提供了稳定的时间基准,为数据采集和传送提供了可靠支持;

  • 将采集、处理与传送功能模块化设计,代码结构清晰,便于后续扩展;

  • 通过UART输出调试信息,为系统调试和性能优化提供了有效依据;

  • 为后续多设备数据传送和智能控制系统打下了坚实的基础。

7.2 项目中的挑战与收获

  • 时序与信号控制:SPI数据传输对时序要求严格,软件模拟实现时需要精确控制时钟脉冲和数据采样,经过多次调试优化,确保数据传输正确无误。

  • 中断管理:合理配置定时器中断确保1ms周期触发,为数据采集提供了稳定的时间基准,提高了系统整体实时性。

  • 模块化设计:将系统分为数据采集、处理、传送和调试输出模块,有助于降低开发难度和系统维护成本,同时为扩展其他通信协议提供了接口。

  • 调试与验证:利用UART调试输出实时监控数据传送情况,快速定位问题,为系统稳定性和可靠性提升积累了丰富经验。

7.3 后续改进与扩展方向

  • 多协议支持:扩展系统支持SPI、I²C、UART等多种数据传输协议,以适应不同外设和应用需求;

  • 数据校验与错误纠正:加入CRC或校验和机制,确保数据传输的完整性和可靠性;

  • 多通道数据采集:扩展系统支持同时采集多个数据源,实现多路数据并行传送;

  • 图形化用户界面:结合LCD或OLED显示,实现数据实时显示和调试信息的直观呈现;

  • 无线数据传送:加入无线模块(如蓝牙、Wi-Fi)实现远程数据传输和监控,拓宽系统应用场景。


8. 参考资料与扩展阅读

  1. 《嵌入式系统设计与实践》——详细介绍了单片机外设配置、定时器中断及SPI、UART、I²C等通信接口的实现方法。

  2. 《C语言嵌入式系统开发》——涵盖了模块化编程、中断处理和数据传送技术,为本项目提供了理论和实践支持。

  3. 《数字通信原理》——讲解了数据编码、传输协议和错误检测机制,帮助理解数据传送过程中的关键问题。

  4. 《微控制器原理及应用》——介绍了单片机的基本原理、外设接口和数据采集技术,是理解本项目的重要参考。

  5. 各大技术论坛(如优快云、51单片机论坛)中的SPI通信案例和讨论,为本项目提供了丰富的实践经验和优化建议。


结语

本文详细介绍了如何利用单片机实现数据传送功能的完整方案。从项目背景、数据传送基本概念及常见通信协议,到系统总体架构设计、硬件接口方案和软件模块划分,再到完整代码实现及详细注释,逐步阐述了单片机如何采集数据、进行编码和通过SPI(或其他通信协议)传送数据,并利用UART调试输出验证数据传送状态。
通过代码解读部分,读者能够深入理解各模块的功能和实现原理,同时在调试与测试部分获得丰富的实用建议,为后续系统优化和扩展提供依据。
该系统为嵌入式应用中数据传送提供了一种低成本、稳定可靠的解决方案,同时也为多设备通信和智能控制系统的实现打下了坚实基础。

/*
 * 单片机实现数据传送
 * 作者:Katie
 * 代码日期:2025-03-28
 *
 * 本程序利用51单片机实现数据传送功能,通过SPI接口与外部设备交换数据。
 * 主要功能包括:
 * 1. 从传感器或其他输入接口采集数据(本示例中采用模拟数据生成);
 * 2. 将数据编码为预定格式,并通过SPI接口发送给从设备;
 * 3. 同时,通过SPI接口接收从设备返回的数据,并进行解析校验;
 * 4. 通过UART接口输出传输状态和调试信息,便于系统监控与调试。
 *
 * 硬件连接说明:
 * - SPI接口:本例使用软件SPI模拟实现。单片机的MOSI、MISO、SCLK和片选引脚分别连接至外部设备对应引脚。
 * - UART接口用于数据传输调试,连接至PC串口调试工具。
 * - 传感器数据部分,本示例以模拟数据生成,实际应用中可连接ADC模块等外设。
 */

#include <reg51.h>
#include <stdio.h>
#include <string.h>

// -------------------- 宏定义 --------------------
#define FOSC 12000000UL       // 系统时钟12MHz

// SPI引脚定义(假设使用P3口模拟SPI接口)
sbit SPI_MOSI = P3_0;         // 主输出从输入
sbit SPI_MISO = P3_1;         // 主输入从输出
sbit SPI_SCLK = P3_2;         // SPI时钟
sbit SPI_CS   = P3_3;         // 片选(低有效)

// UART波特率及相关定义(配置为9600)
#define BAUD_RATE 9600

// 模拟数据生成相关(模拟传感器数据,范围0~1023)
#define SIMULATED_DATA_MAX 1023

// -------------------- 全局变量 --------------------
volatile unsigned int sensorData = 0;  // 存储采集的传感器数据
volatile unsigned long systemTime_ms = 0; // 系统时间计数器(单位:ms)

// 用于UART输出的调试信息缓冲区
char debugBuffer[32];

// -------------------- 函数原型声明 --------------------
void SystemInit(void);
void Timer0_Init(void);
void UART_Init(void);
void SPI_Init(void);
unsigned char SPI_Transfer(unsigned char data);
unsigned int Get_SensorData(void);
void Process_Data(unsigned int data);
void Transmit_Data(unsigned int data);
void Delay_ms(unsigned int ms);
void UART_SendChar(char c);
void UART_SendString(const char *str);
void UART_SendNumber(unsigned int num);

// 定时器0中断服务函数,用于更新时间
void Timer0_ISR(void) interrupt 1;

int main(void)
{
    unsigned int data;
    
    SystemInit();    // 系统初始化
    Timer0_Init();   // 初始化定时器0,实现1ms中断更新系统时间
    SPI_Init();      // 初始化软件SPI接口
    UART_Init();     // 初始化UART,用于数据调试输出
    EA = 1;          // 允许全局中断
    
    while(1)
    {
        // 模拟采集传感器数据
        data = Get_SensorData();
        sensorData = data;
        
        // 数据处理(本示例简单传递数据)
        Process_Data(data);
        
        // 将数据通过SPI接口传送给从设备,并接收返回数据(本示例简单回环)
        // 先拉低片选
        SPI_CS = 0;
        // 发送模拟数据
        unsigned char spiSend = (unsigned char)(data >> 2); // 将10位数据转换为8位数据
        unsigned char spiRecv = SPI_Transfer(spiSend);
        SPI_CS = 1;
        
        // 数据处理:本示例中直接将接收的数据作为最终结果
        data = ((unsigned int)spiRecv) << 2;
        
        // 通过UART输出数据与系统时间
        Transmit_Data(data);
        
        Delay_ms(100);  // 每100ms采集一次数据
    }
}

// -------------------- 系统初始化函数 --------------------
void SystemInit(void)
{
    // 初始化系统时间与全局变量
    systemTime_ms = 0;
    sensorData = 0;
    // 初始化各端口:根据实际硬件连接,本例简化设置
    P3 = 0xFF;  // 将P3所有引脚默认设为高电平
}

// -------------------- 定时器0初始化函数 --------------------
void Timer0_Init(void)
{
    // 配置定时器0为模式1(16位定时器),用于产生1ms中断
    TMOD &= 0xF0;
    TMOD |= 0x01;
    // 计算重载值:FOSC/12 = 1MHz, 1ms = 1000个计数,重载值 = 65536 - 1000 = 64536 = 0xFC18
    TH0 = 0xFC;
    TL0 = 0x18;
    ET0 = 1;  // 允许定时器0中断
    TR0 = 1;  // 启动定时器0
}

// -------------------- UART初始化函数 --------------------
void UART_Init(void)
{
    SCON = 0x50;  // 串口模式1,8位数据,REN允许接收
    TMOD &= 0x0F;
    TMOD |= 0x20; // 定时器1模式2(8位自动重载)
    TH1 = 0xFD;   // 波特率9600(对于12MHz晶振)
    TL1 = 0xFD;
    TR1 = 1;      // 启动定时器1
}

// -------------------- SPI初始化函数 --------------------
void SPI_Init(void)
{
    // 软件SPI方式,直接控制相关引脚
    SPI_MOSI = 0;
    SPI_SCLK = 0;
    SPI_CS = 1;  // 片选高电平,未选中状态
}

// -------------------- SPI数据传输函数 --------------------
/*
 * SPI_Transfer函数通过软件模拟SPI通信,发送一个字节数据并接收返回数据。
 * 数据从最高位到最低位依次传输。
 */
unsigned char SPI_Transfer(unsigned char data)
{
    unsigned char i, received = 0;
    for(i = 0; i < 8; i++)
    {
        // 设置MOSI输出当前最高位
        SPI_MOSI = (data & 0x80) ? 1 : 0;
        data <<= 1;
        
        // 拉高SCLK产生上升沿
        SPI_SCLK = 1;
        // 接收MISO数据
        received <<= 1;
        if(SPI_MISO)
            received |= 0x01;
        SPI_SCLK = 0;
    }
    return received;
}

// -------------------- 模拟传感器数据采集函数 --------------------
/*
 * Get_SensorData函数模拟传感器数据采集,
 * 实际应用中应调用ADC转换接口获取模拟数据。
 * 本示例采用简单计数器模拟数据变化,返回值范围为0~SIMULATED_DATA_MAX。
 */
unsigned int Get_SensorData(void)
{
    static unsigned int simData = 0;
    simData = (simData + 10) % (SIMULATED_DATA_MAX + 1);
    return simData;
}

// -------------------- 数据处理函数 --------------------
/*
 * Process_Data函数对采集到的原始数据进行处理,
 * 本示例中仅直接传递数据,实际应用中可加入滤波、校准等算法。
 */
void Process_Data(unsigned int data)
{
    sensorData = data;
}

// -------------------- 数据传送函数 --------------------
/*
 * Transmit_Data函数将采集与处理后的数据通过UART接口传送出去,
 * 以字符串形式输出数据及当前系统时间,便于调试与数据监控。
 */
void Transmit_Data(unsigned int data)
{
    UART_SendString("Sensor Data: ");
    UART_SendNumber(data);
    UART_SendString("  Time: ");
    UART_SendNumber(systemTime_ms);
    UART_SendString(" ms\r\n");
}

// -------------------- UART发送函数 --------------------
void UART_SendChar(char c)
{
    SBUF = c;
    while(!TI);
    TI = 0;
}

void UART_SendString(const char *str)
{
    while(*str)
    {
        UART_SendChar(*str++);
    }
}

void UART_SendNumber(unsigned int num)
{
    char buffer[6];
    sprintf(buffer, "%u", num);
    UART_SendString(buffer);
}

// -------------------- 延时函数 --------------------
void Delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 120; j++);
}

// -------------------- 定时器0中断服务函数 --------------------
void Timer0_ISR(void) interrupt 1
{
    TH0 = 0xFC;
    TL0 = 0x18;
    systemTime_ms++;  // 每1ms更新系统时间
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值