HAL定时器&PWM&PWM捕获应用编程

HAL定时器&PWM&PWM捕获应用编程

引言:

​ 在嵌入式系统中,HAL定时器和PWM以及PWM捕获是重要的应用编程技术。HAL定时器是一种用于生成定时中断的硬件设备,可以用于实现精确的时间控制和任务调度。而PWM(脉冲宽度调制)则是一种常用的控制电机和灯光亮度的技术,通过调整电平的高低和脉冲宽度的变化,可以实现精确的电机速度和灯光亮度控制。此外,PWM捕获还可以用于测量外部信号的频率和脉冲宽度,从而实现对外部信号的精确采集和处理。在本文中,我们将探讨HAL定时器、PWM和PWM捕获的原理和应用编程方法,帮助读者更好地理解和应用这些技术。

希望你在本次学习过后,能够有一定的收获!!!

心怀不惧,方能翱翔于天际。——赵云

​ 冲啊!!!! ╭ ( `∀´ )╯ ╰ ( ’ ’ )╮

一、定时器介绍

1.STM32定时器
  • 定时器是用来定时的机器,是存在于STM32单片机中的一个外设。STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6),如下图所示:

img

  • 这三种定时器的区别如下:

img

​ 即:高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。

2.通用定时器功能和特点

STM32的众多定时器中我们使用最多的是高级定时器和通用定时器,而高级定时器一般也是用作通用定时器的功能,下面我们就以通用定时器为例进行讲解,其功能和特点包括:

  • 位于低速的APB1总线上(APB1)

  • 16 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。

  • 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。

  • 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:

​ ① 输入捕获

​ ② 输出比较

​ ③ PWM 生成(边缘或中间对齐模式)

​ ④ 单脉冲模式输出

  • 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。

  • 如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):

​ ①更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

​ ②触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

   ③输入捕获 

   ④输出比较 

​ ⑤支持针对定位的增量(正交)编码器和霍尔传感器电路

   ⑥触发输入作为外部时钟或者按周期的电流管理
  • STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
  • 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
3.计数器模式

通用定时器可以向上计数、向下计数、向上向下双向计数模式。

①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。

②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。

③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
img

4.定时器有什么用

定时器有许多用途,以通用定时器为例。它可以测量输入信号的脉冲宽度,产生PWM波。此外定时器也可以用于触发ADC采集,按键检测等方面。

中文参考手册介绍如下

在这里插入图片描述

5.通用定时器输出引脚
通道1通道2通道3通道4
TIM2PA0PA1PA2PA3
TIM3PA6PA7PB0PB1
TIM4PB6PB7PB8PB9
TIM5PA0PA1PA2PA3

这里需要注意的是,如果对引脚进行了重映射,则通道对应引脚会发生变化。以TIM3为例

复用功能没有重映射部分重映射完全重映射
TIM3_CH1PA6PB4PC6
TIM3_CH2PA7PB5PC7
TIM3_CH3PB0PB0PC8
TIM3_CH4PB1PB1PC9

其他几个定时器如下

img

TIM2

img

TIM4

img

TIM5

6.定时器计时举例

Tout = ((arr+1)*(psc+1))/Tclk ;
其中:

定时 500ms

Tclk:定时器的输入时钟频率(单位MHZ)

Tout:定时器溢出时间(单位为us)

.TIM_Period = arr; eg;4999

.TIM_Prescaler = psc; eg:7199

Tout = ((4999+1)×(7199+1))/72 = 500000us = 500ms

  • 初始化定时器的时候指定我们分频系数psc,这里是将我们的系统时钟(72MHz)进行分频

  • 然后指定重装载值arr,这个重装载值的意思就是当 我们的定时器的计数值 达到这个arr时,定时器就会重新装载其他值.

例如当我们设置定时器为向上计数时,定时器计数的值等于arr之后就会被清0重新计数

  • 定时器计数的值被重装载一次被就是一个更新(Update)

  • 计算Update时间公式

Tout = ((arr+1)*(psc+1))/Tclk

公式推导详解:

Tclk是定时器时钟源,在这里就是72Mhz

我们将分配的时钟进行分频,指定分频值为psc,就将我们的Tclk分了psc+1,我们定时器的最终频率就是Tclk/(psc+1) MHz

这里的频率的意思就是1s中记 Tclk/(psc+1)M个数 (1M=10的6次方) ,每记一个数的时间为(psc+1)/Tclk ,很好理解频率的倒数是周期,这里每一个数的周期就是(psc+1)/Tclk 秒

然后我们从0记到arr 就是 (arr+1)*(psc+1)/Tclk

举例:比如我们设置arr=7199,psc=9999

我们将72MHz (1M等于10的6次方) 分成了(9999+1)等于 7200Hz

每记录一个数就是1/7200秒

定时器更新(7199+1)*(1/7200)=1s,也就是1s进入一次更新

二、PWM介绍

1、 什么是PWM

PWM(脉冲宽度调制),它是一种利用微处理器的数字输出来对模拟电路进行控制的技术,也可以理解为是对模拟信号电平进行数字编码的方法。PWM可被应用于电机驱动,调光,通信等方面。

2、 什么是占空比

一个PWM是有固定频率的,也就意味着周期一定,一个周期内有效电平持续时间占整个周期的比例可以称为占空比。比如一个周期100ms,其中50ms持续为有效电平,那么占空比就是50%。正是通过调节占空比,来调节电机转速,或者用不同占空比代表不同信号,用于通信。

3、STM32F1 PWM介绍

STM32F1系列单片机,除了基本定时器TIM6和TIM7外,都可以产生PWM输出。其中高级定时器TIM1和TIM8可以同时产生高达7路PWM输出。PWM输出其实就是对外输出占空比可调的方波,信号频率由自动重装载寄存器ARR的值决定,占空比由比较寄存器CCR的值决定。假设高电平为有效电平,见下图。ARR决定了周期(频率),CCR调节占空比。

img

PWM示意图

根据中文参考手册介绍,STM32F1的PWM比较输出模式共有8种。脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。有关寄存器的内容,这里就不不再做详细介绍。

这里介绍一下8种输出模式中比较常用的两种PWM输出模式,PWM1和PWM2。其实这两种输出模式差别不大,只不过输出电平的极性不同。 |模式|计数器CNT计数方式|说明 | – | --| – | |PWM1|递增|CNT < CCR,通道输出有效电平,否则输出无效电平 |PWM1|递减|CNT > CCR,通道输出无效电平,否则输出有效电平 |PWM2|递增|CNT < CCR,通道输出无效电平,否则输出有效电平 |PWM2|递减|CNT > CCR,通道输出有效电平,否则输出无效电平

4、占空比产生原理

如图为向上计数:
定时器重装载值为ARR,比较值CCRx
t时刻对计数器值和比较值进行比较
如果计数器值小于CCRx值,输出高电平
如果计数器值大于CCRx值,输出低电平
PWM的一个周期
定时器从0开始向上计数
当0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出高电平
t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出低电平
当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数…循环此过程
至此一个PWM周期完成
影响因素
ARR : 决定PWM周期(在时钟频率一定的情况下,当前为默认内部时钟CK_INT)
CCRx : 决定PWM占空比(高低电平所占整个周期比例)

5、PWM频率计算

频率 = (主时钟频率(72MHz) / (分频系数 + 1)) / 自动重装载值(单位为Hz)

在这里插入图片描述

频率

Fpwm = 100M / ((arr+1)*(psc+1))(单位:Hz)

  1. arr 是计数值
  2. psc 是预分频值

如:

  1. 主频=100M
  2. arr=100
  3. psc=1000
    100,000,000/100/1000=1000Hz

占空比
duty circle = TIM3->CCR1 / arr(单位:%)

TIM3->CCR1 是捕获比较寄存器值
从下面代码可以看出TIM3->CCR1 就是对应的sConfigOC.Pulse
arr对应htim5.Init.Period = 999;
psc对应htim5.Init.Prescaler = 99;

如果 arr=1000,TIM3->CCR1=500则pwm的占空比为50%,通过修改CCR1可以修改占空比,修改arr可以修改频率

三、定时器捕获介绍

输入捕获简介

输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。STM32 的输入捕获,简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。

img

1.测量频率

当捕获通道 TIx(如TIM2_CH1) 上出现上升沿时,发生第一次捕获,计数器 CNT 的值会被锁存到捕获寄存器 CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),并把捕获寄存器中的值读取到 value1中。当出现第二次上升沿时,发生第二次捕获,计数器 CNT 的值会再次被锁存到捕获寄存器 CCR 中,并再次进入捕获中断,在捕获中断中,把捕获寄存器的值读取到 value3 中,并清除捕获记录标志。利用 value3和value1 的差值我们就可以算出信号的周期(频率)。

2.测量脉宽

当捕获通道 TIx(如TIM2_CH1) 上出现上升沿时,发生第一次捕获,计数器 CNT 的值会被锁存到捕获寄存器 CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),并把捕获寄存器中的值读取到 value1中。然后把捕获边沿改变为下降沿捕获,目的是捕获后面的下降沿。当下降沿到来的时候,发生第二次捕获,计数器 CNT的值会再次被锁存到捕获寄存器 CCR中,并再次进入捕获中断,在捕获中断中,把捕获寄存器的值读取到 value3中,并清除捕获记录标志。然后把捕获边沿设置为上升沿捕获。 在测量脉宽过程中需要来回的切换捕获边沿的极性,如果测量的脉宽时间比较长,定时器就会发生溢出,溢出的时候会产生更新中断,我们可以在中断里面对溢出进行记录处理。

img

本章我们用到 TIM2_CH1 来捕获高电平脉宽,也就是要先设置输入捕获为上升沿检测,记录发生上升沿的时候 TIM2_CNT 的值。然后配置捕获信号为下降沿捕获,当下降沿到来时,发生捕获,并记录此时的 TIM2_CNT 值。这样,前后两次 TIM2_CNT 之差,就是高电平的脉宽,同时 TIM2 的计数频率我们是知道的,从而可以计算出高电平脉宽的准确时间。需要用到的寄存器有:TIM2_ARR、TIM2_PSC、TIM2_CCMR1、TIM2_CCER、TIM2_DIER、TIM2_CR1、TIM2_CCR1。 首先 TIMx_ARR 和 TIMx_PSC,这两个寄存器用来设自动重装载值和 TIMx 的时钟分频,用法我在前面的第六、第七章已经讲过了,这里就不做赘述了。

四、相关函数介绍

定时相关函数

HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);

功能

  • HAL_TIM_Base_Start_IT函数是ST公司提供的STM32 HAL库中的一个函数,用于启动定时器的基本定时中断功能。
  • 基本定时器是STM32微控制器中的一个定时器模块,用于生成固定时间间隔的中断。HAL_TIM_Base_Start_IT函数用于启动基本定时器的中断功能,并在每个固定时间间隔触发一个中断。

参数

  • htim:是一个指向TIM_HandleTypeDef结构体的指针,该结构体包含了定时器的配置信息。

  • 举例:

      HAL_TIM_Base_Start_IT(&htim2); // 使能定时器及其更新中断
    

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

功能

  • HAL_TIM_PeriodElapsedCallback是ST公司提供的STM32 HAL库中的一个回调函数,用于处理定时器的周期中断事件。
  • 当定时器的计数器达到预设的周期值时,定时器会触发一个中断,同时会调用HAL_TIM_PeriodElapsedCallback函数。这个函数是一个预定义的回调函数,可以在应用程序中实现它,以便在定时器周期中断发生时执行特定的操作。

参数

  • htim:是一个指向TIM_HandleTypeDef结构体的指针,该结构体包含了定时器的配置信息。

  • 举例:

    // 定时TIM2 定时亮灯的中断函数
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *tim)
    {
      if (tim == &htim2)
      {HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
      }
    }
    

PWM产生相关函数
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)

功能

  • HAL_TIM_PWM_Start函数是ST公司提供的STM32 HAL库中的一个函数,用于启动定时器的PWM输出功能。
  • PWM(Pulse Width Modulation,脉宽调制)是一种常用的信号调制技术,可以通过调节信号的脉冲宽度来控制信号的平均功率。在STM32微控制器中,定时器模块可以用于生成PWM信号。
  • HAL_TIM_PWM_Start函数用于启动定时器的PWM输出功能,并开始生成PWM信号。使用该函数前,需要先初始化定时器,并配置定时器的时钟源、预分频因子、计数器周期和PWM输出通道。

参数

  • htim:是一个指向TIM_HandleTypeDef结构体的指针,该结构体包含了定时器的配置信息。

  • Channel是PWM输出通道的标识,用于指定要启动的PWM输出通道。

  • 举例:

    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); // 使能定时器及其PWM输出
    

#define __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)

功能

  • __HAL_TIM_SET_COMPARE是STM32 HAL库中的一个宏,用于设置定时器的比较值。
  • 在定时器的比较模式下,定时器可以用于产生比较事件,并在比较事件发生时触发中断或者更新输出信号。比较值是一个与定时器计数器进行比较的值,当定时器计数器的值等于或超过比较值时,将触发比较事件。

参数

  • __HANDLE__是一个指向TIM_HandleTypeDef结构体的指针,该结构体包含了定时器的配置信息。

  • __CHANNEL__是比较通道的标识,用于指定要设置比较值的通道。

  • __COMPARE__是要设置的比较值。

  • 举例:

        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 10); // 设置一个PWM波形进行测量
    

PWM捕获相关函数
HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);

功能

  • HAL_TIM_IC_Start_IT函数是ST公司提供的STM32 HAL库中的一个函数,用于启动定时器的输入捕获功能,并开启输入捕获中断。
  • 在定时器的输入捕获模式下,定时器可以用于捕获外部信号的上升沿或下降沿,并记录捕获时刻的计数值。启动输入捕获功能后,定时器将开始捕获外部信号,并在捕获事件发生时触发中断。

参数

  • htim:是一个指向TIM_HandleTypeDef结构体的指针,该结构体包含了定时器的配置信息。

  • Channel是PWM输出通道的标识,用于指定要启动的PWM输出通道。

  • 举例:

     HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);    // 使能定时器及其输入捕获
    

uint32_t HAL_TIM_ReadCapturedValue(const TIM_HandleTypeDef *htim, uint32_t Channel);

功能

  • HAL_TIM_ReadCapturedValue函数是ST公司提供的STM32 HAL库中的一个函数,用于读取定时器输入捕获通道的捕获值。
  • 在定时器的输入捕获模式下,定时器可以用于捕获外部信号的上升沿或下降沿,并记录捕获时刻的计数值。通过使用HAL_TIM_ReadCapturedValue函数,可以读取指定输入捕获通道的捕获值,以获取捕获时刻的计数值。

参数

  • htim:是一个指向TIM_HandleTypeDef结构体的指针,该结构体包含了定时器的配置信息。

  • Channel是PWM输出通道的标识,用于指定要启动的PWM输出通道。

  • 举例:

    Cap_val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // 获取捕获值
    

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);

功能

  • HAL_TIM_IC_CaptureCallback是ST公司提供的STM32 HAL库中的一个回调函数,用于处理定时器输入捕获事件。
  • 在定时器输入捕获模式下,定时器可以用于捕获外部信号的上升沿或下降沿,并记录捕获时刻的计数值。当定时器捕获到外部信号时,定时器会触发一个中断,并调用HAL_TIM_IC_CaptureCallback函数。这个函数是一个预定义的回调函数,可以在应用程序中实现它,以便在输入捕获事件发生时执行特定的操作。

参数

  • htim:是一个指向TIM_HandleTypeDef结构体的指针,该结构体包含了定时器的配置信息。

  • 举例:

    // 定时输入捕获回调函数 计算占空比和频率
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {
        if (htim->Instance == TIM1)
        {
            if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
            {
                Cap_val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
            }
            if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
            {
                Cap_val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
                Duty = 100 - (float)Cap_val2 / (float)Cap_val1 * 100;
                Frequency = 0.001 * Cap_val1;
            }
        }
    }
    

五、工程建立

CubeMX配置

基本的配置在我之前的文章中有,这里我们直接跳到对应端口的配置

  1. 选择对应的芯片端口使用

在这里插入图片描述

  1. 串口通信配置

在这里插入图片描述

在这里插入图片描述

  1. 定时器定时配置

    在这里插入图片描述

    在这里插入图片描述

  2. PWM波形捕获

在这里插入图片描述

在这里插入图片描述

  1. PWM生成
    在这里插入图片描述

函数撰写

main.c 主要函数
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

uint8_t i = 0;

float Duty = 0;
float Frequency = 0;
uint16_t Cap_val1 = 0;
uint16_t Cap_val2 = 0;

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM1_Init();
    MX_TIM3_Init();
    MX_USART1_UART_Init();
    MX_TIM2_Init();
    /* USER CODE BEGIN WHILE */

    printf("串口通信测试\r\n");
    /
    HAL_TIM_Base_Start_IT(&htim2); // 使能定时器及其更新中断
    /
    
    /
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); // 使能定时器及其PWM输出
    /
    
    /
    HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);       // 使能定时器及其输入捕获
    HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2);       // 使能定时器及其输入捕获
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 10); // 设置一个PWM波形进行测量
    /

    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        // 串口发送 频率 占空比
        printf("Cap_val1 is :%d ,  Cap_val2 is : %d \r\n", Cap_val1, Cap_val2);
        printf("Duty is :%0.2f%% Frequency is : %0.2f ms\r\n", Duty, Frequency);
        HAL_Delay(1000);
        /循环设置呼吸灯
        // for (i = 0; i <= 100; i++)
        // {
        //   __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, i);
        //     HAL_Delay(10);
        // }
        // for (i = 0; i <= 100; i++)
        // {
        //     __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 100 - i);
        //     HAL_Delay(10);
        // }
        /
    }
}

/* USER CODE BEGIN 4 */
/
// 定时TIM2 定时亮灯的中断函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *tim)
{
    if (tim == &htim2)
    {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
}
/

/
// 定时输入捕获回调函数 计算占空比和频率
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM1)
    {
        if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
        {
            Cap_val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
        }
        if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
        {
            Cap_val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
            Duty = 100 - (float)Cap_val2 / (float)Cap_val1 * 100;
            Frequency = 0.001 * Cap_val1;
        }
    }
}
/

六、效果展示

实验效果

Video1:

定时

Video2:

呼吸灯

Video3:

占空比

波形分析

Video4:

波形分析PWM

视频观察可知,对应的高电平在持续发生变化进而产生对应的pwm波形

七、总结

本文主要介绍了HAL定时器、PWM以及PWM捕获应用编程的相关内容。

在实际应用中,定时器可以用于生成定时中断、计时等功能;PWM可以用于产生特定的脉冲宽度以控制电机、灯光等设备的工作状态;而PWM捕获则可以用于测量外部信号的频率、占空比等参数。

在编程实现上,我们可以使用HAL库中提供的相关函数来配置和使用这些功能,例如HAL_TIM_Base_Start_IT()函数用于启动定时器中断、HAL_TIM_PWM_Start()函数用于启动PWM输出等。

通过本文的学习,我们可以深入了解HAL定时器、PWM以及PWM捕获的原理和应用,为实际项目的开发提供技术支持。

最后感谢大佬友情链接:

  • https://blog.csdn.net/qq_44016222/article/details/123507270
  • https://zhuanlan.zhihu.com/p/663070301
  • https://zhuanlan.zhihu.com/p/145635309
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LX很爱吃葱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值