嵌入式软件学习资料汇总

一、链接

1、stm32【按键处理:单击、连击、长按】_stm32长按短按 连续长按_Elven-C的博客-CSDN博客

2、复用和重映像的关系_复用功能的重映象_lwlwinner的博客-CSDN博客

3、GPIO输入输出模式原理(八种工作方式附电路图详解)_gpio输出模式_行稳方能走远的博客-CSDN博客

二、

2、1 工装制作(IAR)

(1)目的:

    制作一个检测遥控器低功耗的检测装置

(2)逻辑:

  上电即检测遥控器电流,电流>10uA,无源蜂鸣器滴一声,电流<10uA,无源蜂鸣器长鸣,按下按键后蜂鸣器停止响。

(3)思路:

  a、GPIO口配置  Set_Gpio.c
#ifndef _GPIOSET_C
#define _GPIOSET_C

#include "sys.h"
#include "GPIOSet.h"

void GPIO_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  
  RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA|RCC_AHBENR_GPIOB|RCC_AHBENR_GPIOC|RCC_AHBENR_GPIOD, ENABLE);//使能PORTA,PORTB,PORTC时钟
  
//BUZZ 
  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
//KEY
  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  


}
b、无源蜂鸣器用定时器配置(我用的是定时器2)  Timer.c
#ifndef _TIM_C
#define _TIM_C

#include "TIM.h"
#include "sys.h"

void PWM_TIM2_Configuration(void)
{
  
  RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB|RCC_AHBENR_GPIOA, ENABLE);  
  RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM2, ENABLE);
  GPIO_InitTypeDef GPIO_InitStructure;//PB6 BUZZER 
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6; // DIANJI|GPIO_Pin_1|GPIO_Pin_3|GPIO_Pin_13|GPIO_Pin_14
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  //  GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_6); //TIM1-CH2  LED  PB4
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_4); //TIM2-CH1   BUZZ PB6

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; 
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000;
  
  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 1000-1; //计数周期,向上记到此数,计数值清零
  TIM_TimeBaseStructure.TIM_Prescaler = 12-1;//48-1;//定时器分频系数,Ftimer = 72M/(TIM_Prescaler+1) = 1us
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//与死区时间分频有关
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  
  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitTypeDef        TIM_OCInitStructure;
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//比较互补输出使能
  TIM_OCInitStructure.TIM_Pulse = 0;   //比较值,即占空比
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;  //输出极性
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;//互补输出极性
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;//指定空闲状态下的TIM输出比较的引脚状态。
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;//指定空闲状态下的TIM互补输出比较的引脚状态。
  TIM_OC1Init(TIM2,&TIM_OCInitStructure);   //初始化通道二比较输出
  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);      //配置通道二,自动重装载使能
  
  
  TIM_ARRPreloadConfig(TIM2, ENABLE);//重载装载值 ENABLE 立即生效,DISABLE 下一个比较周期生效
  
  
  TIM_Cmd(TIM2, ENABLE);//使能定时器2
  
  TIM_CtrlPWMOutputs(TIM2, ENABLE);//使能PWM外围输出 
  
}



void TIM2_Pulse(unsigned char channel,unsigned short Pulse)
{
  switch(channel)
  {
  case TIM_CHANNEL1:     
    {
      TIM2->CCR1 = (Pulse);
    }break;
  case TIM_CHANNEL2 :     
    {
      TIM2->CCR2 =(Pulse);
    }break;   
  case TIM_CHANNEL3:     
    {
      TIM2->CCR3 = (Pulse);
    }break;
  case TIM_CHANNEL4 :     
    {
      TIM2->CCR4 =(Pulse);
    }break;   
  }
}




#endif

Timer.h

#ifndef _TIM_H
#define _TIM_H

#define	SYS_CLOCK	  48000000UL	                        // 48MHz
#define PWM_FREQ    ((unsigned short) 16000)                       // in Hz  (N.b.: pattern type is center aligned)
#define DEADTIME_NS	((unsigned short) 1600)                        //in nsec (上升沿+下降沿 死区时间之和),2.25us

#define PWMCYCLE   ((SYS_CLOCK / PWM_FREQ/2) - 1)      // = 1199
#define MAXPWM     PWMCYCLE                            // 0:pwm = 0%,    MAXPWM: pwm = 100%
#define	MINPWM	 	 60

#define TIM_CHANNEL1   1
#define TIM_CHANNEL2   2
#define TIM_CHANNEL3   3
#define TIM_CHANNEL4   4

void PWM_TIM2_Configuration(void);
void TIM2_Pulse(unsigned char channel,unsigned short Pulse);

#endif
c、sys.c
#include "sys.h"
 RCC_ClocksTypeDef  Frequency;	
volatile unsigned int  Sys_DelayCnt=0;
void Systick_Init(void)
{
     /**Configure the Systick interrupt time */
   RCC_GetClocksFreq(&Frequency);
   SysTick_Config(Frequency.SYSCLK_Frequency/1000);
//  /* SysTick_IRQn interrupt configuration */
   NVIC_SetPriority(SysTick_IRQn, 0x03);//SysTickא׏ԅЈܶʨ׃;   

}
void SysDelay_ms(unsigned int delays)
{ 
  Sys_DelayCnt=delays;
  while(Sys_DelayCnt)
    IWDG_ReloadCounter(); 
}
sys.h
#ifndef __SYS_H 			   
#include "HAL_conf.h"
#include "HAL_device.h"
#include "stdio.h"
#include "dtype.h"
extern volatile unsigned int  Sys_DelayCnt;
void Systick_Init(void);
void SysDelay_ms(unsigned int delays);
#endif
d、BUZZ.c 
#ifndef _BUZZ_C
#define _BUZZ_C

#include "TIM.h"
#include "BUZZ.h"

BUZZ_Control BUZZ1_Control;
unsigned int BUZZ_Count1;//电流小于10uA 记时间
unsigned int BUZZ_Count2;//电流大于10uA  记时间
unsigned short Df_cnt;
unsigned short Scan_cnt;
//unsigned int Buzz_Continue;
unsigned char Flag_Scan=0;
void Buzz_init(void)
{
  BUZZ1_Control.BUZZ_OldStatus=BUZZ_OFF;
  BUZZ1_Control.BUZZ_Status=BUZZ_OFF;
  BUZZ1_Control.BUZZ_Cnt=0;
  BUZZ1_Control.BUZZ_Cnt1=0;
  BUZZ1_Control.BUZZ_ControlStatus=0;
  BUZZ1_Control.BUZZ_RunStatus=0;
}

void Buzz_Control(void)
{
  if((BUZZ1_Control.BUZZ_Status!=BUZZ_IDLE))
  {
    if(BUZZ1_Control.BUZZ_Cnt==0)
    {
      BUZZ1_Control.BUZZ_Status=BUZZ_OFF;
    } 
    if ((BUZZ1_Control.Buzz_Send_cnt<=4)&&(BUZZ1_Control.BUZZ_Cnt1==0))
    { 
      
      switch (BUZZ1_Control.BUZZ_Buff[BUZZ1_Control.Buzz_Send_cnt])
      {
      case 1:
        {
          BUZZ1_Control.BUZZ_Status=BUZZ_ON;
          BUZZ1_Control.BUZZ_Cnt=BUZZ_ShortTIME;
          BUZZ1_Control.BUZZ_Cnt1=BUZZ_ShortTIME*2;  
        }break;
      case 2:
        {
          BUZZ1_Control.BUZZ_Status=BUZZ_ON;
          BUZZ1_Control.BUZZ_Cnt=BUZZ_LongTIME;
          BUZZ1_Control.BUZZ_Cnt1=BUZZ_LongTIME*2;   
        }break;
      case 3:
        {
          BUZZ1_Control.BUZZ_Status=BUZZ_ON;
          BUZZ1_Control.BUZZ_Cnt=BUZZ_XLTIME;
          BUZZ1_Control.BUZZ_Cnt1=BUZZ_XLTIME*2;  
          
        }break;
      default :
        {
          BUZZ1_Control.BUZZ_Status=BUZZ_IDLE;
          BUZZ1_Control.Buzz_Send_cnt=4;
        }break;
      }
      BUZZ1_Control.Buzz_Send_cnt++;
    }  
  }

  if (BUZZ1_Control.BUZZ_Status!=BUZZ1_Control.BUZZ_OldStatus)
  {
    BUZZ1_Control.BUZZ_OldStatus= BUZZ1_Control.BUZZ_Status;
    if (BUZZ1_Control.BUZZ_OldStatus==BUZZ_ON)
    {
      BUZZ_ON();      
    }
    else if (BUZZ1_Control.BUZZ_OldStatus==BUZZ_OFF)
    {
      BUZZ_OFF();      
    }
  }
    if (BUZZ1_Control.Buzz_Send_cnt>4)//闲时
  {
    BUZZ1_Control.BUZZ_Status=BUZZ_IDLE;
    BUZZ1_Control.Buzz_Send_cnt=0;
  }
}


#endif

BUZZ.h

#ifndef _BUZZ_H
#define _BUZZ_H

#define  BUZZ_ON()     TIM2_Pulse(TIM_CHANNEL1,500);
#define  BUZZ_OFF()    TIM2_Pulse(TIM_CHANNEL1,0);

#define BUZZ_XXXLTIME      20000000
#define BUZZ_XLTIME      2000
#define BUZZ_LongTIME      500
#define BUZZ_ShortTIME      200
#define BUZZ_Compare   400


#define BUZZ_size 5

typedef enum 
{
  
  BUZZ_IDLE= 0,
  BUZZ_ON= 1,  //开
  BUZZ_STON= 2,
  BUZZ_OFF= 3,  //开
  BUZZ_STOFF=4,   //关 
//  BUZZ_Toogle=5,
}BUZZ_Switch;

typedef struct 
{
  BUZZ_Switch BUZZ_Status;
  BUZZ_Switch BUZZ_OldStatus;
  
  unsigned char BUZZ_ControlStatus;//1蜂鸣1次 
  unsigned char BUZZ_RunStatus;//1蜂鸣1次  
  unsigned short BUZZ_Cnt;//f蜂鸣器蜂鸣计数器
  unsigned short BUZZ_Cnt1;//蜂鸣器停止计数器
  unsigned char Buzz_Send_cnt; //扫描次数
  unsigned char BUZZ_Buff[BUZZ_size];
}BUZZ_Control;
extern BUZZ_Control BUZZ1_Control;

extern unsigned int BUZZ_Count1;
extern unsigned int BUZZ_Count2;
extern unsigned short Df_cnt;
extern unsigned short Scan_cnt;
//extern unsigned int Buzz_Continue;
extern unsigned char Flag_Scan;
void Buzz_init(void);
void Buzz_Control(void);

#endif

e、MMit.c
#ifndef _MM32F0XX_C
#define _MM32F0XX_C

/* Includes ------------------------------------------------------------------*/
#include "sys.h"
#include "mm32_it.h"
#include "BUZZ.h"
#include "ADC.h"
#include "KEY.h"
#include "TIM.h"

void SysTick_Handler(void)
{
  //  ADC_TVul=ADC_Value-ADC_Temp;
  if(Sys_DelayCnt)
    Sys_DelayCnt--;
  if (BUZZ1_Control.BUZZ_Cnt1)
    BUZZ1_Control.BUZZ_Cnt1--;
  if (BUZZ1_Control.BUZZ_Cnt)
    BUZZ1_Control.BUZZ_Cnt--; 
  if(KEY1_SCANF)  
  {
    Key1_Mode.Key_PressCnt++;
  }
  else if (Key1_Mode.Key_Status!=NoClick)
  {
    Key1_Mode.Key_LossenCnt++;
  } 
  
  if((ADC_Result>30)&&(Scan1_Flag1_Mode.BUZZ_Flag1==Scan_IDLE))
  {
    Scan_cnt++;//持续60毫秒以上 进入判断YES 、NO;
    if(Scan_cnt>60)
    {
      Scan1_Flag1_Mode.BUZZ_Flag1=Scan_Start;
      BUZZ_Count1=0;
      BUZZ_Count2=0;
      Scan_cnt=0;
    }
  }
  else if ((ADC_Result<10)&&(ADC_Result>0)&&(Scan1_Flag1_Mode.BUZZ_Flag1!=Scan_IDLE))//检测电流 在55-65之间 持续500mS 判定为IDLE状态
  {
    Df_cnt++;
    if (Df_cnt>=20)
    {
      Df_cnt=0;
      Scan1_Flag1_Mode.BUZZ_Flag1=Scan_IDLE;
      BUZZ_Count1=0;
      BUZZ_Count2=0;
      Scan_cnt=0;
    }
  }
  
  if((ADC_Result<=400)&&(ADC_Result>20)&&(Scan1_Flag1_Mode.BUZZ_Flag1==Scan_Start))
  {
    BUZZ_Count1++;
    BUZZ_Count2=0;
    Df_cnt=0;
    Scan_cnt=0;
  }
  else if((ADC_Result>500)&& (Scan1_Flag1_Mode.BUZZ_Flag1==Scan_Start))
  {
    Df_cnt=0;
    BUZZ_Count1=0;
    BUZZ_Count2++;
    Scan_cnt=0;
  }
  if (ADC1_Collection.Time_Cnt<7)
  {
    ADC1_Collection.Time_Cnt++;
  }
    
    
  
}

void ADC1_COMP_IRQHandler(void)
{
  if(ADC_GetFlagStatus(ADC1,ADC_IT_EOC)!=RESET)
  {
    ADC1_Collection.Sample_Cnt++;
    ADC_ClearFlag(ADC1,ADC_IT_EOC);
    ADC_Temp = 0xFFF & ADC_GetConversionValue(ADC1);
    if ((ADC_Value-ADC_Temp)>=0)
    {   
      ADC_TVul=ADC_Value-ADC_Temp;
    }
    else if ((ADC_Value-ADC_Temp)<0)
    {
      ADC_TVul=ADC_Temp-ADC_Value;
    }
    
    
   ADC1_Collection.ADC_DATA_Temp_BUFF[ADC1_Collection.count++]=ADC_TVul;
//    if (ADC1_Collection.count>=ADC_N)
//    {
//      for (unsigned int i=0;i<ADC1_Collection.count;i++)
//      {
//        ADC1_Collection.sum+=ADC1_Collection.ADC_DATA_Temp_BUFF[i];
//      }
//      ADC_Result=ADC1_Collection.sum/ADC1_Collection.count;
//      ADC1_Collection.sum=0;
//      ADC1_Collection.count=0;
//    }    
    ADC1_Collection.Sample_Cnt=0;
  }
}



#endif

 MMit.h

#ifndef _MM32F0XX_H
#define _MM32F0XX_H

#ifdef __cplusplus
 extern "C" {
#endif 
#define N 10 
   
void NMI_Handler(void);
void HardFault_Handler(void);
void SVC_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void ADC1_IRQHandler(void);
void UART1_IRQHandler(void);
void EXTI4_15_IRQHandler(void);
void TIM16_IRQHandler(void);
void TIM16_IRQHandler(void);


#ifdef __cplusplus
}
#endif        

					 
#endif /* */
f、main.c 

加入了平均值滤波

#include <stdio.h>
#include <string.h>
#include "TIM.h"
#include "GPIOSet.h"
#include "BUZZ.h"
#include "sys.h"
#include "ADC.h"
#include "MM32_it.h"
#include "KEY.h"


 int main(void)
 {
   Systick_Init();  
   KEY_Init();
   SysDelay_ms(1000);
   AD1_Configration();
   PWM_TIM2_Configuration();
   Buzz_init();
   KEY_Init();
   SysDelay_ms(10);
   
//   ADC_Result=ADC_TVul;
   BUZZ1_Control.Buzz_Send_cnt=0;
   BUZZ1_Control.BUZZ_Buff[0]=2;
   BUZZ1_Control.BUZZ_Status=BUZZ_STON;
   Scan1_Flag1_Mode.BUZZ_Flag1=Scan_IDLE;
   //shijia ADvalue    ADC_Temp
   //ADC_Value = mid value
   ADC_Value=ADC_Temp;
 
   
   while(1)
   {
     
     Buzz_Control();
     KEY_Process();
     if((BUZZ_Count1>300))
     {
       Scan1_Flag1_Mode.BUZZ_Flag1=Scan_yes;
       BUZZ1_Control.Buzz_Send_cnt=0;
       BUZZ1_Control.BUZZ_Buff[0]=1;
       BUZZ1_Control.BUZZ_Status=BUZZ_STON;
       BUZZ_Count1=0;
     }
     else if(BUZZ_Count2>300)//计时
     { 
       Scan1_Flag1_Mode.BUZZ_Flag1=Scan_no;
       BUZZ_ON(); 
       BUZZ_Count2=0;
       
     }
     if ((ADC1_Collection.count>=ADC_N)||(ADC1_Collection.Time_Cnt>=7))
     {
       for (unsigned int i=0;i<ADC1_Collection.count;i++)
       {
         ADC1_Collection.sum+=ADC1_Collection.ADC_DATA_Temp_BUFF[i];
       }
       ADC_OldResult=ADC1_Collection.sum/ADC1_Collection.count;
       ADC_Result=((ADC_OldResult*7)+(ADC_Result*3))/10;   
       ADC1_Collection.sum=0;
       ADC1_Collection.count=0;
       ADC1_Collection.Time_Cnt=0;
     }    
     //tianjia 20次取平均值
     
   }
 }

三、 基础知识(大部分基于江科大视频)

3.1 C基础

3.1.1 c语言数据类型

3.2 TIM定时器 

3.2.1 输出比较 OC

(1)

3.2.2 输入捕获 IC 

(1)描述:当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中

(2)作用:可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数

3.3 ADC 模数转换

3.3.1 ADC函数理解
(1)GPIO_Mode配置:

GIPO模式配置为GPIO_MODE_AIN模拟输入,此模式下GPIO口无效,即断开GPIO口,防止GPIO的输入输出对模拟电压造成干扰,所以GPIO_MODE_AIN模拟输入为ADC的专属模式

(2)ADC转换四种模式

ADC转换中有两个函数,分别对应四种模式

ADC_ContinuousConvMode();//连续转换模式 可选择ENABLE或DISABLE

ADC_ScanConvMode();//扫描模式  可选择ENABLE或DISABLE

① 非扫描模式下 单次转换模式 

  此模式下,只有序列1有效

如图,在序列1的位置指定我们想转换的通道(例如通道2),然后触发转换,ADC对通道2进行模式转换,一段时间后转换结束,结果存放在数据寄存器中,同时EOC标志位置1;判断标志位状态可知道转换是否完成,若完成就可以读取寄存器里的数据。

若想再启动一次转换,就要再触发一次。

此模式需要手动开启转换

② 非扫描模式下 连续转换模式 

此模式与模式①大体相同,只是该模式转换一次后不会停止,会继续下一轮的转换。

此模式不需要判断转换是否结束,因为一直都在转换 ,所以想要读取AD值时,直接读取。

③ 扫描模式下 单次转换模式 (扫描模式需配合DMA使用)

为了方便理解,可以类比菜单点菜,通道数目可供选择(可重复),触发转换后,ADC对设定的通道(n)进行模数转换,结果放在数据寄存器。

为防止数据被覆盖,需配合DMA及时将数据挪走,n个通道转换完成后,产生EOC信号,转换结束。

若想再启动一次转换,就要再触发一次。

④扫描模式下 连续转换模式 (扫描模式需配合DMA使用)

此模式与模式③大体相同,只是该模式转换一次后不会停止,会继续下一轮的转换。

(3)ADC触发源
(4)STM32ADC  T(总转换时间)=T(采样)+T(12.5个ADC周期)

例如:当ADCCLK=14MHz,采样时间为1.5个周期,则T=1.5+12.5=14个周期,即1us

(5)使用定时器触发ADC转换(可实现定时采样)

 令T(采样)=15个周期 

则T(总转换时间)=15+12=27个周期

此时配置定时器的时钟为30MHz,且将采样频率设置为定时器频率

则T(转换)=27/30MHz=0.9us<1us(一般情况下,采样间隔时间需要大于转换时间,否则有可能AD转化还没完成就被采出来了)

3.3.2 DMA (Direct Memory Acess)直接通道读取

(1)DMA可提供外设与存储器或存储器与存储器之间的高速数据传输,无需CPU的干预,节省CPU资源

(2)存储器映像

 3.3 USART串口通信

3.3.1 串口参数

波特率(每秒传输码元的个数,bit/s或bps)、

起始位(固定为低电平)、电平由高电平被拉为

数据位(低位先行)、

校验位、

停止位(固定为高电平)

3.3.2 通信方式

异步通信

所以双方要约定一个速率,ns发送一位,则ns接收一位

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嵌入式软件学习的原理图可以根据引用的内容进行总结。嵌入式软件工程师的学习路线主要包括以下几个阶段和步骤: 1. 学习嵌入式知识:首先,学习者需要系统地学习嵌入式知识,包括硬件和软件方面的内容,掌握嵌入式系统的工作原理和基本概念。 2. 掌握嵌入式基础:在学习嵌入式知识后,学习者可以算是入门了。这时候可以进一步深入研究嵌入式系统的各个方面,包括硬件和软件的设计和开发。 3. 设计嵌入式软件嵌入式软件工程师的主要职责是根据产品的功能需求设计好软件,让硬件工作起来。嵌入式电子产品的硬件部分大部分都是相同的,核心部分由CPU、RAM和FLASH等组成,而软件则承担了实现产品具体功能的重任。 通过以上三个阶段的学习和实践,学习者可以掌握嵌入式软件的基本原理和技能,为应聘嵌入式研发工程师岗位做好准备。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [嵌入式软件工程师学习路线图](https://blog.csdn.net/m0_70888041/article/details/127242771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值