当前位置: 首页 > news >正文

【STM32单片机】#6 定时器比较输出

主要参考学习资料:

B站@江协科技

STM32入门教程-2023版 细致讲解 中文字幕

开发资料下载链接:https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwd=dspb

单片机套装:STM32F103C8T6开发板单片机C6T6核心板 实验板最小系统板套件科协

实验:

  • PWM驱动LED呼吸灯
  • PWM驱动舵机
  • PWM驱动直流电机

新函数:

  • 定时器库函数(输出比较部分)

目录

  • 输出比较简介
  • PWM简介
  • 输出比较通道
    • 通用定时器
    • 输出比较模式
    • PWM基本结构
        • 参数计算
    • 高级定时器
  • 外部设备
    • 舵机简介
      • 硬件电路
    • 直流电机及驱动简介
      • 硬件电路
  • 函数详解
    • TIM_OCxInit函数(x)
      • TIM_OCInitTypeDef结构体
    • TIM_OCStructInit函数
    • TIM_ForcedOCxConfig函数(x)(不常用)
    • TIM_OCxPreloadConfig函数(x)(不常用)
    • TIM_OCxFastConfig函数(x)(不常用)
    • TIM_ClearOCxRef函数(x)(不常用)
    • TIM_OCxPolarityConfig函数(x)
    • TIM_OCxNPolarityConfig函数(x)
    • TIM_CCxCmd函数(x)
    • TIM_CCxNCmd函数(x)
    • TIM_SelectOCxM函数(x)
    • TIM_SetComparex函数(x)
    • TIM_CtrlPWMOutputs函数
  • 实验10 PWM驱动LED呼吸灯
    • 接线图
    • PWM驱动
    • 主程序
    • 引脚重映射
  • 实验11 PWM驱动舵机
    • 接线图
    • PWM驱动
    • 舵机驱动
    • 主程序
  • 实验11 PWM驱动直流电机
    • 接线图
    • PWM驱动
    • 电机驱动
    • 主程序

输出比较简介

  • OC(Output Compare)输出比较
  • 输出比较可以通过比较CNT计数器与CCR捕获/比较寄存器值的关系,对输出电平进行置一、置零或翻转的操作,用于输出一定频率和占空比的PWM波形。
  • 每个高级定时器和通用定时器都拥有四个输出比较通道。
  • 高级定时器的前三个通道额外拥有死区生成和互补输出的功能。

PWM简介

  • PWM(Pulse Width Modulation)脉冲宽度调制
  • 在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域,即用数字信号等效模拟信号。
  • 惯性系统:LED由于余晖和视觉暂留现象不会立马熄灭;电机断电时转动会因为惯性过一会才停。
  • PWM参数:
    • 频率 = 1 / T S =1/T_S =1/TS:频率越快,等效的模拟信号就越平稳,性能开销也越大,一般在几千到几十千赫兹。
    • 占空比 = T O N / T S =T_{ON}/T_S =TON/TS:高电平时间相对于整个周期时间的比例,决定了等效模拟电压的大小。
    • 分辨率=占空比变化步距:占空比变化的精细程度。

输出比较通道

通用定时器

左侧来自捕获/比较寄存器的比较结果传入输出模式控制器,随后输出模式控制器改变输出OC1REF(reference缩写,参考信号)的高低电平。ETRF输入是定时器一个小功能,一般不用,无需了解。REF信号一方面可以映射到主模式的TRGO输出,但主要还是前往OC1。CC1P寄存器选择极性,写0时信号电平不翻转(高电平有效),写1时信号电平通过非门翻转(低电平有效)。输出使能电路选择要不要输出。最终信号到达OC1引脚,具体引脚参见引脚定义表TIMx_CHx功能。

输出比较模式

输出模式控制器的执行逻辑包含八种输出比较模式:

其中有效电平为高电平,无效电平为低电平。本次主要使用的模式为PWM模式1的向上计数情况,模式2是模式1的取反。

PWM基本结构

图中波形为ARR=99、CCR=30的情况,上方波形为CNT计数过程,下方波形为REF输出结果。

参数计算
  • PWM频率:Freq=CK_PSC/(PSC+1)/(ARR+1)(等于计数器更新频率)
  • PWM占空比:Duty=CCR/(ARR+1)
  • PWM分辨率:Reso=1/(ARR+1)(ARR越大,CCR的取值范围越大,分辨率越小)

高级定时器

仅需大致了解上期介绍的输出比较电路升级的内容即可。

外部设备

舵机简介

  • 舵机是一种根据输入PWM信号占空比来控制输出角度的装置。
  • 输入PWM信号要求:周期20ms,高电平宽度0.5ms~2.5ms

舵机的大致执行逻辑为PWM信号输入到控制板,给控制板一个指定的目标角度,电位器检测输出轴的当前角度,若大于目标角度电机反转,若小于目标角度电机正转,最终使输出轴固定在指定角度。此时PWM主要是一种通信协议,与等效模拟信号关系不大。

硬件电路

舵机需要5V供电,若外接电机电源,则电源一端接GND,一端接舵机5V口。套件中可使用STLINK的5V输出脚实现USB供电。

直流电机及驱动简介

  • 直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时电机正转,当电极反接时电机反转。
  • 直流电机属于大功率器件,GPIO无法直接驱动,需要配合电机驱动电路来操作。
  • TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向。

硬件电路

如图左侧为TB6612芯片引脚图,右上为引脚定义表,右下为控制电平逻辑表。

驱动模块每路电机的输入由一个PWM信号输入端和两个控制模式输入端组成,输出由两个驱动输出端组成。输出端均为低电平时电机制动(刹车),一高一低时电机根据正/反接情况正/反转。输入中PWM信号决定电机是否旋转,控制模式输入端决定电机旋转方向,两者共同决定输出电平。

函数详解

以下函数名称后标注(x)的,函数名称中x可取1~4,代表对应的输出比较通道。

TIM_OCxInit函数(x)

简介:配置输出比较模块。

参数一:定时器名称

参数二:指向初始化信息TIM_OCInitTypeDef结构体的指针

TIM_OCInitTypeDef结构体

成员TIM_OCMode:输出比较模式

TIM_OCMode_Timing(冻结)
TIM_OCMode_Active(匹配置有效电平)
TIM_OCMode_Inactive(匹配置无效电平)
TIM_OCMode_Toggle(匹配电平翻转)
TIM_OCMode_PWM1(PWM模式1)
TIM_OCMode_PWM2(PWM模式2)
TIM_ForcedAction_Active(强制为有效电平)
TIM_ForcedAction_InActive(强制为无效电平)
强制模式无法在初始化时配置,但可通过后续其他配置函数配置。

成员TIM_OutputState:输出使能/失能(非互补输出通道)

TIM_OutputState_Enable, TIM_OutputState_Disable

成员TIM_OutputNState:输出使能/失能(互补输出通道)

TIM_OutputNState_Enable, TIM_OutputNState_Disable

成员TIM_Pulse:CCR寄存器值

成员TIM_OCPolarity:极性(非互补输出通道)

TIM_OCPolarity_High, TIM_OCPolarity_Low

成员TIM_OCNPolarity:极性(互补输出通道)

TIM_OCNPolarity_High, TIM_OCNPolarity_Low

成员TIM_OCIdleState:空闲状态输出电平(非互补输出通道)

TIM_OCIdleState_Set, TIM_OCIdleState_Reset

成员TIM_OCNIdleState:空闲状态输出电平(非互补输出通道)

TIM_OCNIdleState_Set, TIM_OCNIdleState_Reset

TIM_OCStructInit函数

简介:给TIM_OCInitTypeDef结构体赋默认值。

参数:指向初始化信息TIM_OCInitTypeDef结构体的指针

TIM_ForcedOCxConfig函数(x)(不常用)

简介:配置强制输出模式。

参数一:定时器名称

参数二:输出比较模式

TIM_ForcedAction_Active(强制为有效电平)
TIM_ForcedAction_InActive(强制为无效电平)

TIM_OCxPreloadConfig函数(x)(不常用)

简介:配置CCR寄存器的预装功能。

参数一:定时器名称

参数二:是否预装

TIM_OCPreload_Enable, TIM_OCPreload_Disable

TIM_OCxFastConfig函数(x)(不常用)

简介:配置快速使能(匹配条件发生时立即改变输出状态)。

参数一:定时器名称

参数二:是否快速使能

TIM_OCFast_Enable, TIM_OCFast_Disable

TIM_ClearOCxRef函数(x)(不常用)

简介:外部事件清除REF信号。

参数一:定时器名称

参数二:是否启用外部事件清除

TIM_OCClear_Enable, TIM_OCClear_Disable

TIM_OCxPolarityConfig函数(x)

简介:单独配置输出比较通道的极性(非互补输出通道)。

参数一:定时器名称

参数二:极性

TIM_OCxNPolarityConfig函数(x)

简介:单独配置输出比较通道的极性(互补输出通道,无OC4)。

参数一:定时器名称

参数二:极性

TIM_CCxCmd函数(x)

简介:单独配置输出使能参数(非互补输出通道)。

参数一:定时器名称

参数二:输出通道

TIM_Channel_1, ..., TIM_Channel_4

参数三:使能/失能

TIM_CCx_Enable, TIM_CCx_Disnable

TIM_CCxNCmd函数(x)

简介:单独配置输出使能参数(互补输出通道)。

参数一:定时器名称

参数二:输出通道

参数三:使能/失能

TIM_CCxN_Enable, TIM_CCxN_Disnable

TIM_SelectOCxM函数(x)

简介:选择输出比较模式。

参数一:定时器名称

参数二:输出通道

参数三:输出比较模式

TIM_SetComparex函数(x)

简介:单独配置CCR寄存器值。

参数一:定时器名称

参数二:CCR值

TIM_CtrlPWMOutputs函数

简介:使用高级定时器输出PWM时需要调用该函数使能主输出。

参数一:定时器名称

参数二:使能/失能

实验10 PWM驱动LED呼吸灯

接线图

PWM驱动

PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);

#endif

PWM.c

#include "stm32f10x.h" 

void PWM_Init(void)
{
	//初始化PA0
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	//复用推挽输出将输出控制权转移给片上外设(定时器)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//时基单元初始化参照实验8
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	//设置PWM波形频率1KHz,分辨率1%
	//ARR=100-1, PSC=720-1,此时占空比=CCR/100*100%
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	//高级定时器部分的成员用不到,但为了结构体完整性,使用默认值初始化所有成员,再更改需要的成员
	TIM_OCStructInit(&TIM_OCInitStructure);
	//PWM1模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	//高电平有效
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	//输出使能
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	//PA0口对应OC1通道
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

//修改CCR
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);
}

主程序

#include "stm32f10x.h" 
#include "Delay.h"
#include "PWM.h"

//循环变量
uint8_t i;

int main(void)
{
	PWM_Init();
	while(1)
	{
		//占空比递增,LED变亮
		for(i = 0;i <= 100;i++)
		{
			PWM_SetCompare1(i);
			Delay_ms(10);
		}
		//占空比递减,LED变暗
		for(i = 0;i <= 100;i++)
		{
			PWM_SetCompare1(100 - i);
			Delay_ms(10);
		}
	}
}

引脚重映射

回顾外部中断一节介绍的引脚重映射函数:

GPIO_PinRemapConfig函数

简介:引脚重映射。

参数一:重映射方式(参数繁多,需见手册)

参数二:使能/失能

向PWMInit函数添加以下代码,将PA0端口重映射到PA15端口,以此在PA15实现TIM2_OC1的输出比较功能。

//引脚重映射
//启用AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//将PA0映射到PA15
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//PA15为调试端口,需解除原有的JTAG复用功能
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

原PA0初始化函数改为PA15:

//初始化PA15
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

LED接线需改到PA15。

实验11 PWM驱动舵机

实现功能:每按一次按键舵机旋转30°,旋转到180°重置。

接线图

PWM驱动

在实验10基础上更改。

PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
//修改函数编号为通道2
void PWM_SetCompare2(uint16_t Compare);

#endif

PWM.c

#include "stm32f10x.h" 

void PWM_Init(void)
{
	//初始化PA1
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	//更改引脚编号
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	//舵机要求PWM频率20Hz
	//ARR=20K-1, PSC=72-1, 此时高电平时间=(CCR/1000)ms
	TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	//PA1口对应OC2通道
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

//修改函数编号为通道2
void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2, Compare);
}

舵机驱动

Servo.h

#ifndef __SERVO_H
#define __SERVO_H

void Servo_Init(void);
void Servo_SetAngle(float Angle);

#endif

Servo.c

#include "stm32f10x.h"
#include "PWM.h"

void Servo_Init(void)
{
	//初始化底层PWM
	PWM_Init();
}

//设置舵机角度
void Servo_SetAngle(float Angle)
{
	//角度换算到高电平持续时间
	//0.5ms对应0°,2.5ms对应180°,CCR=1000对应1ms
	PWM_SetCompare2(Angle / 180 * 2000 + 500);
}

主程序

#include "stm32f10x.h" 
#include "Delay.h"
#include "Servo.h"
#include "OLED.h"
#include "Key.h"

uint8_t KeyNum;
float Angle;

int main(void)
{
	OLED_Init();
	Servo_Init();
	Key_Init();
	OLED_ShowString(1, 1, "Angle");
	while(1)
	{
		//获取键值
		KeyNum = Key_GetNum();
		//按下按键舵机转30度
		if(KeyNum == 1)
		{
			Angle += 30;
			//转到头则重置角度
			if(Angle > 180)
			{
				Angle = 0;
			}
		}
		Servo_SetAngle(Angle);
		OLED_ShowNum(1, 7, Angle, 3);
	}
}

实验11 PWM驱动直流电机

实现功能:每按一次按键电机速度+20,速度到100反转。

接线图

建议在接线图基础上将驱动芯片的GND接地,否则电机可能不转。

PWM驱动

在实验10基础上更改。

PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
//修改函数编号为通道3
void PWM_SetCompare3(uint16_t Compare);

#endif

PWM.c

#include "stm32f10x.h" 

void PWM_Init(void)
{
	//初始化PA2
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	//更改引脚编号
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	//PA2口对应OC3通道
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

//修改函数编号为通道3
void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2, Compare);
}

电机驱动

Motor.h

#ifndef __MOTOR_H
#define __MOTOR_H

void Motor_Init(void);
void Motor_SetSpeed(int8_t Speed);

#endif

Motor.c

#include "stm32f10x.h"
#include "PWM.h"

void Motor_Init(void)
{
	PWM_Init();
	//初始化PA4和PA5
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void Motor_SetSpeed(int8_t Speed)
{
	//根据速度正负控制正反转,方向自定
	if(Speed >= 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_4);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
		PWM_SetCompare2(Speed);
	}
	else
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_5);
		GPIO_ResetBits(GPIOA, GPIO_Pin_4);
		//CCR传入正值
		PWM_SetCompare2(-Speed);
	}
}

主程序

#include "stm32f10x.h" 
#include "Delay.h"
#include "Motor.h"
#include "OLED.h"
#include "Key.h"

uint8_t KeyNum;
int8_t Speed;

int main(void)
{
	OLED_Init();
	Motor_Init();
	Key_Init();
	Motor_SetSpeed(0);
	OLED_ShowString(1, 1, "Speed:");
	while(1)
	{
		KeyNum = Key_GetNum();
		//按下按键电机速度加20
		if(KeyNum == 1)
		{
			Speed += 20;
			//超过100则反转
			if(Speed > 100)
			{
				Speed = -100;
			}
		}
		Motor_SetSpeed(Speed);
		OLED_ShowSignedNum(1, 7, Speed, 3);
	}
}

相关文章:

  • OceanSim: 基于Isaac Sim GPU 加速水下机器人感知仿真框架
  • 基于SpringBoot酒店管理系统设计和实现(源码+文档+部署讲解)
  • qt socket编程正确重启tcpServer的姿势
  • 同一份数据,Redis为什么要存两次
  • 人脸考勤管理一体化系统(人脸识别系统,签到打卡)
  • WinForm真入门(9)——RichTextBox控件详解
  • 基于大数据的美团外卖数据可视化分析系统
  • 【易飞】易飞批量选择品号处理方法,工作效率提升300%
  • 学透Spring Boot — 018. 优雅支持多种响应格式
  • 多智能体优秀开发框架
  • Java 中的 CompletableFuture:异步编程的强大工具
  • 网络原理 - HTTP/HTTPS
  • HAL 库设置回调成员函数的一种方法
  • 2-vim编辑器的安装和使用
  • 【爬虫】携程旅游项目数据爬取
  • GPT-4o从语义分割到深度图生成,大模型狂潮下的计算机视觉:技术进步≠替代危机
  • C#UDP协议客户端工具类
  • C#实现存储数据到Redis
  • 运行小程序报错
  • Leetcode 3508. Implement Router
  • 商丘 网站建设/整合营销传播的方法包括
  • seo网站优化报价/东营百度推广电话
  • 如何制作一部动漫/广州网站优化费用
  • 网站便捷营销/360seo排名点击软件
  • 新沂网站开发/营销的目的有哪些
  • wordpress文章页名称/亚马逊seo什么意思