STM32控制ULN2003步进电机驱动设计
简介:本项目是STM32微控制器与ULN2003驱动器结合控制28BYJ-48步进电机的实践案例。通过编写程序,实现对步进电机的精确控制,包括初始化GPIO口、生成脉冲序列、速度与方向控制,以及定位和运动控制。本案例将使初学者深入了解嵌入式系统、电机控制和电路设计,对提升硬件控制技能具有显著价值。
1. STM32微控制器介绍
STM32微控制器是基于ARM Cortex-M系列处理器构建的32位微控制器家族,广泛应用于嵌入式系统和物联网项目中。该系列微控制器以高性能、高集成度和丰富的外设支持而著称,非常适合用于复杂控制和信号处理应用。
1.1 STM32微控制器的主要优势
- 高性能处理能力 :借助Cortex-M内核,STM32提供了出色的处理性能,支持浮点运算和复杂的控制算法实现。
- 丰富的外设接口 :包括ADC、DAC、定时器、串行通讯接口等,大大简化了电路设计和编程工作。
- 低功耗特性 :STM32微控制器系列提供了多种低功耗模式,有助于延长电池供电设备的使用时间。
1.2 开发工具与环境
开发STM32微控制器项目,通常需要以下工具和环境:
- 开发环境 :如Keil MDK、IAR Embedded Workbench、STM32CubeIDE等集成开发环境。
- 调试与编程工具 :如ST-Link/V2-1、J-Link等硬件调试器和编程器。
- 软件库 :如STM32 HAL库、LL库和Standard Peripheral Library等,简化开发过程。
STM32微控制器由于其强大的性能、灵活的外设选择和开发便捷性,在众多应用领域都具有广泛的应用潜力。随着物联网和人工智能技术的发展,STM32将在智能化产品设计中扮演更加重要的角色。
2. 步进电机工作原理及控制基础
2.1 步进电机的基本概念和类型
2.1.1 步进电机的工作原理
步进电机是一种将电脉冲信号转换为角位移或直线位移的电机。每个脉冲信号都使电机转动一个固定的角度,称为步距角。这种转换通过电机内部的电磁结构实现,通常包括定子和转子两部分,定子提供磁场,转子跟随磁场变化而旋转。
以最常见的两相步进电机为例,它由两个线圈组成,当电流通过这两个线圈时,会产生两个相互垂直的磁场,这个磁场使得转子上的磁铁与其相互作用,产生旋转。通过顺序改变线圈的通电状态,可以控制转子转动的方向和角度。
2.1.2 步进电机的分类与特点
步进电机根据其内部结构和工作原理,大致可以分为以下几类:
-
变阻(VR)步进电机
- 特点:结构简单,成本低,但精度不高,易失步。 -
永磁(PM)步进电机
- 特点:中等成本,运行平滑,低速性能良好。 -
混合式(HYBRID)步进电机
- 特点:高扭矩,高精度,高分辨率,是目前应用最广泛的步进电机类型。 -
单极性(UNIPOLAR)与双极性(BIPOLAR)步进电机
- 单极性电机每个线圈有一个中心抽头,通过切换线圈的电流方向控制步进。
- 双极性电机没有中心抽头,通过改变线圈电流的方向来控制步进。
- 双极性步进电机相比单极性电机拥有更高的效率和扭矩,但其控制电路更复杂。
2.2 步进电机控制系统概述
2.2.1 控制系统的组成
一个典型的步进电机控制系统包括:
-
微控制器(MCU)
- 用于生成控制信号和执行运动控制算法。 -
驱动器
- 将微控制器输出的信号放大,以驱动步进电机。 -
步进电机
- 根据控制信号完成精确的位置移动。 -
传感器
- 反馈位置信息或转速信息到控制系统,实现闭环控制。
2.2.2 控制方式与控制要求
控制方式主要有以下两种:
-
开环控制
- 电机的运动仅由输入脉冲控制,不考虑外部负载及摩擦等因素的影响。开环控制结构简单,成本低,适用于对精度要求不高的场合。 -
闭环控制
- 通过传感器反馈电机的实际运行情况,控制系统会根据反馈信号调整控制策略,使电机准确到达指定位置。闭环控制能提供更高的精度和稳定性,但系统复杂度和成本也相对较高。
控制要求通常包含:
- 精确的位置控制。
- 平滑且稳定的运转。
- 在各种负载条件下的可靠运行。
- 适应快速加减速的能力。
- 故障检测与响应机制。
控制系统的设计需要综合考虑成本、精度、可靠性以及可维护性。在设计之前,必须详细了解步进电机的特性和应用需求,以便选用合适的控制策略和组件。
3. ULN2003驱动器功能及应用
3.1 ULN2003驱动器概述
3.1.1 ULN2003的结构与特性
ULN2003驱动器是一款专为步进电机设计的驱动芯片,它具有多个通道,每个通道都可以独立控制并驱动一个步进电机线圈。ULN2003包含7个集电极开路的达林顿晶体管,每个晶体管都可以承受高达500mA的电流,适用于驱动小型步进电机。此外,该驱动器内建有反向二极管,可以用来抑制电机线圈在断电时产生的感应电压,保护驱动电路不受损害。
3.1.2 ULN2003与步进电机的连接方法
ULN2003的每个通道都可以直接连接步进电机的一个线圈,驱动器通过输入逻辑电平来控制相应的输出通道。连接时,需要将ULN2003的输入端连接到微控制器的I/O口,并通过适当的电阻限制输入电流。输出端则连接步进电机的相应线圈,并确保电机的电源地与驱动器的公共地(GND)相连。下面是连接图示例:
+5V +5V
| |
R |
| |
+---------+-----------> IN1 ----+----> Coil A
| | |
GND ULN2003 GND |
| | |
+---------+-----------> IN2 ----+----> Coil B
| |
R |
| |
GND +5V
注解:R为限流电阻, Coil A/B代表步进电机的两个线圈。
3.2 ULN2003在步进电机控制中的应用
3.2.1 电路设计与保护措施
使用ULN2003驱动步进电机时,电路设计需要考虑以下几个方面:
- 供电系统 :确保为步进电机和ULN2003提供稳定的电源,对于电源电压和电流的要求需参照步进电机规格和ULN2003的数据手册。
- 限流电阻选择 :限流电阻需根据ULN2003的最大电流承受能力和步进电机线圈的电阻值综合考虑。
- 保护措施 :在电路中加入TVS管(瞬态电压抑制器),以防止电压尖峰造成的损害;反向二极管必须连接在ULN2003的输出端,用于消除线圈断电时产生的反向电动势。
3.2.2 驱动器与微控制器的接口实现
微控制器与ULN2003驱动器的接口通常通过GPIO(通用输入输出)引脚来实现。例如,使用Arduino开发板控制ULN2003的代码片段如下:
// 定义控制引脚
int motorPin1 = 8; // IN1连接到Arduino数字引脚8
int motorPin2 = 9; // IN2连接到Arduino数字引脚9
// 设置引脚模式为输出
pinMode(motorPin1, OUTPUT);
pinMode(motorPin2, OUTPUT);
void setup() {
// 初始化代码
}
void loop() {
// 步进电机控制逻辑
digitalWrite(motorPin1, HIGH); // 使能线圈A
delay(1); // 持续时间控制
digitalWrite(motorPin1, LOW);
digitalWrite(motorPin2, HIGH); // 使能线圈B
delay(1); // 持续时间控制
digitalWrite(motorPin2, LOW);
}
在该代码中,通过对 motorPin1 和 motorPin2 引脚输出高低电平,控制ULN2003来驱动步进电机的两个线圈。通过改变延时函数 delay() 中参数的大小,可以控制步进电机的转速。
以上是ULN2003驱动器在步进电机控制中的基本应用方法。在实际使用中,还需要根据步进电机的具体型号和控制需求,对电路进行相应的调整和优化。
4. 步进电机控制程序核心部分
4.1 控制程序框架与流程
4.1.1 程序结构设计
在设计步进电机控制程序时,构建一个合理的程序框架至关重要。它不仅需要满足控制需求,同时要求具有良好的可读性和可维护性。通常,步进电机控制程序会采用模块化的结构设计,包括初始化模块、主控制循环、中断服务程序等。初始化模块负责设置微控制器的相关寄存器,包括时钟系统、输入输出端口、定时器和中断系统等。主控制循环则是程序的核心,负责电机的运动控制逻辑,如启动、停止、速度调整等。而中断服务程序用于处理各种实时事件,如定时器中断用于产生精确的脉冲信号。
初始化模块代码示例:
#include "stm32f10x.h" // 包含STM32标准外设库头文件
void System_Init(void) {
// 初始化系统时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
// 初始化GPIO端口A为推挽输出模式
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 假设使用PA0作为步进电机控制引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始化定时器等其他外设...
}
int main(void) {
System_Init(); // 系统初始化
while(1) {
// 主循环,执行控制逻辑
}
}
4.1.2 主程序与子程序的划分
在主控制循环中,可以将不同的控制功能划分为子程序,比如步进电机的启动、停止、方向控制和速度控制等。这样做有助于提高程序的模块化程度和可读性,使得代码更加清晰易懂。同时,在发生错误或需要进行维护时,也更易于定位问题和进行修改。
子程序示例:
void StepMotor_Start(void) {
// 步进电机启动控制逻辑
}
void StepMotor_Stop(void) {
// 步进电机停止控制逻辑
}
void StepMotor_ChangeDirection(int direction) {
// 方向控制逻辑,1为正转,-1为反转
}
void StepMotor_SetSpeed(int speed) {
// 设置步进电机速度的控制逻辑
}
在主程序中,根据控制需求调用相应的子程序:
int main(void) {
System_Init(); // 系统初始化
while(1) {
StepMotor_Start(); // 启动电机
StepMotor_SetSpeed(50); // 设置电机速度为50
Delay_ms(1000); // 延时函数,等待1秒
StepMotor_Stop(); // 停止电机
}
}
4.2 控制算法的设计与实现
4.2.1 微步控制算法
步进电机的微步控制是一种使电机以更小的角度旋转的技术,这样可以提高电机的运动精度和平滑性。微步控制算法需要计算出每个脉冲对应的占空比,通过调整电机绕组的电流来实现。这种方法通常需要更复杂的驱动电路和控制逻辑。
微步控制算法伪代码:
定义微步参数:
full_step_angle = 电机全步角度
micro_steps = 微步数量
angle_per_step = full_step_angle / micro_steps
对于每个脉冲信号:
计算下一个位置的角度增量 = angle_per_step
更新电机位置
根据位置调整绕组电流,实现微步动作
4.2.2 加减速控制策略
为了实现平滑的启动和停止,以及在运动过程中保持匀速或匀加速运动,加减速控制策略是必须的。加减速控制通常涉及对脉冲频率的动态调整,或者使用算法来平滑地改变加速度。
加减速控制伪代码:
设定最大加速度、最大速度和最大减速度参数
如果电机处于加速状态:
增加脉冲间隔时间
如果达到最大速度,则切换到匀速状态
如果电机处于匀速状态:
维持当前脉冲间隔时间
如果电机处于减速状态:
减少脉冲间隔时间
如果达到停止,则执行停止动作
通过上述章节的详细介绍,我们已经了解了步进电机控制程序的核心部分,包括控制程序的框架设计、控制算法的具体实现方法,以及如何实现微步控制和加减速控制。这为进一步深入研究和实践步进电机的控制技术奠定了坚实的理论基础。在后续章节中,我们将探索更为复杂的技术,如脉冲序列的生成和速度控制策略,以及方向控制和定位技术,最终实现步进电机的综合控制实践。
5. 脉冲序列生成与速度控制策略
5.1 脉冲序列的生成技术
脉冲序列是步进电机驱动的关键,它决定了电机的步进频率和步进精度。生成脉冲序列的主要目的是精确地控制电机的运动,确保步进电机能够按照预定的速度和方向运行。
5.1.1 脉冲信号的产生方法
脉冲信号的产生可以通过多种方式实现,常见的有软件生成和硬件生成。软件生成脉冲信号依赖于微控制器的定时器/计数器单元,而硬件方法通常涉及到专用的脉冲发生器芯片。在步进电机控制中,利用软件生成脉冲信号是一种经济且灵活的方法。
软件生成脉冲信号的逻辑
#include <定时器库.h>
// 初始化定时器
void Timer_Init(void) {
// 定时器初始化代码,设置定时器工作模式、频率等参数
}
// 定时器中断服务程序
void Timer_Interrupt_Handler(void) {
// 定时器中断处理代码,此处产生一个脉冲信号
// 例如:改变某个GPIO的电平状态
HAL_GPIO_TogglePin(GPIOx, GPIO_PIN_x);
}
在上述代码中, Timer_Init 函数用于配置定时器的基本参数,而 Timer_Interrupt_Handler 是定时器中断服务程序,用于产生脉冲信号。每次中断发生时,执行代码切换GPIO的状态,从而产生脉冲。
5.1.2 脉冲宽度调制(PWM)技术应用
脉冲宽度调制(PWM)是一种利用数字信号控制模拟电路的方法,通过改变脉冲的宽度来控制电机的平均电压。在步进电机控制中,PWM可以用于控制电机的扭矩或者实现速度的平滑变化。
PWM信号的生成逻辑
#include <定时器库.h>
// 初始化PWM
void PWM_Init(void) {
// PWM初始化代码,设置PWM模式、频率、占空比等参数
}
// 设置PWM占空比
void Set_PWM_Duty_Cycle(uint8_t dutyCycle) {
// 根据传入的占空比参数设置PWM输出的占空比
TIM_SetCompare1(TIMx, dutyCycle);
}
PWM_Init 函数用于配置PWM模块,而 Set_PWM_Duty_Cycle 函数用于调整PWM占空比。通过改变占空比,可以控制电机的平均电流,进而影响电机的转矩输出。
5.2 速度控制策略的实现
步进电机的速度控制是控制策略中的重要部分。电机的速度取决于脉冲的频率,即每秒钟发出的脉冲数(PPS)。控制策略的目的在于实现电机从静止到目标速度的平滑过渡,以及在运行过程中对速度的精确控制。
5.2.1 基于时间的脉冲间隔控制
一种常见的速度控制方法是基于时间的脉冲间隔控制,即通过调整连续两个脉冲之间的时间间隔来改变电机的运行速度。
基于时间的脉冲间隔控制代码逻辑
#include <定时器库.h>
// 延时函数,产生固定时间间隔
void Delay_us(uint32_t us) {
// 代码逻辑,通过延时函数等待指定的微秒数
}
// 生成脉冲序列
void Generate_Pulse_Series(uint32_t steps, uint32_t delay_us) {
for (uint32_t i = 0; i < steps; i++) {
HAL_GPIO_TogglePin(GPIOx, GPIO_PIN_x); // 产生一个脉冲
Delay_us(delay_us); // 等待指定的时间间隔
}
}
在 Generate_Pulse_Series 函数中,通过循环调用 Delay_us 函数来控制脉冲间隔时间,从而控制电机速度。通过改变 delay_us 参数值,就可以调节电机的速度。
5.2.2 基于速度反馈的闭环控制
闭环控制是一种更为精确和稳定的速度控制策略,它依赖于速度反馈来调整脉冲间隔。速度反馈可以来自于编码器或其他速度传感器。
基于速度反馈的闭环控制逻辑
#include <PID库.h>
// PID控制器初始化
PID_TypeDef pid;
PID_Init(&pid, Kp, Ki, Kd); // Kp, Ki, Kd为PID控制参数
// 速度控制主循环
void Velocity_Control_Loop(void) {
float currentSpeed = 0;
float targetSpeed = TARGET_SPEED; // 目标速度值
float controlValue;
while (1) {
// 读取当前速度值,可能需要通过编码器等传感器获得
currentSpeed = Read_Current_Speed();
// 计算速度偏差
controlValue = PID_Compute(&pid, targetSpeed, currentSpeed);
// 根据控制值调整脉冲间隔
Adjust_Pulse_Interval(controlValue);
// 其他控制逻辑...
}
}
在这个控制循环中, PID_Compute 函数用于计算速度偏差值,并返回一个控制值。 Adjust_Pulse_Interval 函数根据控制值调整脉冲间隔,从而实现对电机速度的实时调节。
通过上述两节的介绍,我们可以看到脉冲序列生成和速度控制策略在步进电机控制中的重要性和实现方法。脉冲序列的产生为电机的精确控制提供了基础,而基于时间和闭环的速度控制策略则保证了电机运动的平稳和精确。
6. 方向控制方法与定位技术
6.1 方向控制策略
6.1.1 方向控制的实现原理
方向控制是步进电机控制中的关键组成部分,它决定了电机轴的旋转方向。方向控制的实现通常依赖于步进电机驱动器,通过改变绕组通电顺序来实现电机的正转或反转。
方向控制原理基于步进电机的多相绕组结构。典型步进电机有两相或四相绕组,当按照一定的顺序对这些绕组通电时,电机轴会按照特定方向旋转。要改变方向,只需简单地反转绕组的通电顺序。
方向控制在软件层面通常通过控制IO口的高低电平顺序来实现。例如,若使用ULN2003驱动器配合微控制器实现方向控制,可以通过设置不同的输出端口高低电平的序列来控制电机的旋转方向。
6.1.2 方向控制的编程实现
在编程实现方向控制时,首先需要定义控制步进电机相绕组的IO口。在微控制器上,这些IO口将被配置为输出模式,并通过改变其电平状态来控制步进电机的方向。
// 假设使用单片机的GPIO进行方向控制
// GPIO定义与初始化
#define DIR_PIN 1 // 定义方向控制引脚
#define STEP_PIN 2 // 定义步进脉冲引脚
void setup() {
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
}
void loop() {
digitalWrite(DIR_PIN, HIGH); // 设置方向为正转
digitalWrite(STEP_PIN, HIGH); // 发出一个步进脉冲
delayMicroseconds(1000); // 控制脉冲宽度
digitalWrite(STEP_PIN, LOW);
delay(10); // 控制步进速度
// 反转方向
digitalWrite(DIR_PIN, LOW); // 设置方向为反转
digitalWrite(STEP_PIN, HIGH); // 发出一个步进脉冲
delayMicroseconds(1000); // 控制脉冲宽度
digitalWrite(STEP_PIN, LOW);
delay(10); // 控制步进速度
}
在上述示例代码中,我们首先定义了两个控制引脚, DIR_PIN 和 STEP_PIN ,分别用于控制方向和发出步进脉冲。通过改变 DIR_PIN 的电平,我们能够控制电机的旋转方向。 STEP_PIN 用于控制步进电机的转动步数和速度。
6.2 定位控制技术
6.2.1 定位技术的要求与挑战
定位控制技术是指在步进电机执行过程中,能够精确控制其旋转到指定位置的能力。要求控制系统能够准确地记录步进电机的步数或位置,并能够通过某种方式校准和修正步进误差。
在实际应用中,定位技术面临的挑战包括步进电机的失步问题、重复定位精度差、响应速度慢等。为了克服这些挑战,需要采用高精度的编码器、闭环控制技术、以及更精细的控制算法。
6.2.2 硬件与软件协同定位方法
为了提高定位精度,通常需要硬件和软件的协同工作。在硬件方面,可以使用增量式或绝对式编码器来检测电机轴的实时位置。增量式编码器通过计数输出的脉冲来确定位置,而绝对式编码器则能够在任何时候提供当前位置的准确信息。
软件层面,需要通过编程实现对编码器信号的读取和处理,然后与预期位置进行比较,从而调整电机的运动,使实际位置与预期位置一致。这通常涉及到PID控制算法,通过比例(P)、积分(I)和微分(D)参数的调节来实现精确控制。
// 示例代码,使用增量式编码器进行位置校准
// 假设编码器接口函数已经实现
int readEncoder(); // 读取编码器当前位置
void moveMotorToPosition(int targetPosition); // 移动电机到目标位置
void loop() {
int currentPos = readEncoder(); // 读取当前位置
if (currentPos != targetPosition) {
// 如果当前位置与目标位置不一致
moveMotorToPosition(targetPosition); // 控制电机移动到目标位置
}
// 其他控制逻辑...
}
在上述代码中,我们通过调用 readEncoder 函数读取当前位置,然后与预设的目标位置进行比较。若不一致,则调用 moveMotorToPosition 函数,执行相应的控制算法,使电机移动到目标位置。
综上所述,方向控制和定位技术是步进电机控制系统中不可缺少的部分。方向控制通过改变通电顺序来控制电机旋转方向,而定位技术则通过硬件和软件的协同工作,确保步进电机准确到达预定位置。随着技术的进步,更加智能和精确的控制方法正在不断发展,为步进电机的应用打开了更广阔的空间。
7. 步进电机的综合控制实践
7.1 综合控制实例分析
在讨论了步进电机的控制基础与驱动器应用之后,我们现在将通过一个实际的控制实例,来进一步分析步进电机的综合控制实践。该实例将展示如何将前面章节中提到的理论知识,应用到具体实践中去。
7.1.1 实例设计思路与要求
在设计一个步进电机控制系统时,需要考虑以下要素:
- 系统要求 :确定系统需要控制的步进电机类型,如双极或单极,以及所需的精度、速度和扭矩等指标。
- 控制策略 :基于速度、加减速控制策略和微步控制等要求设计控制算法。
- 硬件选择 :选择合适的微控制器、驱动器和其他硬件组件。例如,可以使用STM32微控制器,并结合ULN2003驱动器。
- 软件实现 :编写程序来实现脉冲序列的生成,方向控制,以及故障诊断与维护。
接下来,我们将通过一个简单的实例来展示如何设计并调试一个基于STM32和ULN2003的步进电机控制系统。
7.1.2 控制程序的调试与优化
首先,我们需要编写控制程序来实现我们的设计要求。以下是一个基于STM32微控制器的简单控制程序的框架。
#include "stm32f10x.h"
// 初始化GPIO和定时器等
void system_init() {
// 初始化代码...
}
// 生成脉冲信号
void pulse_generation() {
// 脉冲信号生成代码...
}
// 步进电机控制函数
void stepper_control() {
// 控制代码,包括方向控制和微步控制...
}
int main() {
system_init(); // 系统初始化
while(1) {
pulse_generation(); // 持续生成脉冲信号
stepper_control(); // 步进电机控制
}
}
在上述代码框架中, system_init 函数用于系统初始化,包括时钟配置、GPIO配置和定时器配置等。 pulse_generation 函数负责产生步进电机的脉冲信号,而 stepper_control 函数用于实现电机的方向控制和微步控制逻辑。
接下来,我们需要在STM32环境中编译和上传该程序到微控制器,然后进行调试。调试步骤包括:
- 检查硬件连接 :确保所有硬件连接正确,无短路或松动现象。
- 基础功能测试 :测试单个功能模块,如脉冲生成是否正常,方向控制是否准确。
- 综合性能测试 :综合运用各个功能模块,检查整个系统的响应和执行情况。
- 性能优化 :根据实际运行情况对系统进行性能优化,如调整脉冲宽度、改变加减速策略等。
通过上述步骤,我们可以对控制系统进行调试和优化,确保步进电机能够按照既定的要求运行。
7.2 故障诊断与系统维护
7.2.1 常见问题的诊断方法
在步进电机控制系统运行过程中,可能会遇到多种故障。以下是一些常见的问题及其诊断方法:
- 电机不动作 :检查电机供电是否正常,连接线是否松动,驱动器是否故障。
- 步进丢失 :可能由于供电不足或加速过快导致,调整供电电压或减缓加速过程。
- 方向错误 :检查控制信号和逻辑,确保程序中方向控制信号正确。
7.2.2 系统维护与性能提升建议
系统在长期运行后,为了保持其性能,以下是一些建议:
- 定期检查 :定期检查电机、驱动器和连接线是否正常。
- 清洁保养 :定期清洁电机和驱动器,避免灰尘和杂物影响性能。
- 性能监控 :监控系统的运行状态,记录运行数据,定期分析性能趋势,及时调整控制策略。
通过上述维护和优化措施,可以有效提升步进电机控制系统的稳定性和寿命。
简介:本项目是STM32微控制器与ULN2003驱动器结合控制28BYJ-48步进电机的实践案例。通过编写程序,实现对步进电机的精确控制,包括初始化GPIO口、生成脉冲序列、速度与方向控制,以及定位和运动控制。本案例将使初学者深入了解嵌入式系统、电机控制和电路设计,对提升硬件控制技能具有显著价值。
更多推荐
所有评论(0)