【英飞凌 - UART - 波特率】

设备

  • 硬件: 英飞凌XMC4200Platform2Go开发板
  • 软件: DAVE

意图

在工业领域中,可能会出现需要修改通信波特率的情况。下面是一些常见的案例:

  1. 设备更换或升级: 当工业控制系统中的某些设备需要更换或升级时,新设备可能具有不同的通信参数,包括波特率。因此,需要根据新设备的要求修改通信波特率,以确保设备之间的通信正常进行。

  2. 通信距离变化: 如果在工业控制系统中,某些设备之间的通信距离发生变化,可能需要调整通信波特率。通常情况下,较长的通信距离需要较低的波特率,以确保信号稳定传输。

  3. 通信质量优化: 有时候,由于外部干扰或通信线路质量等因素影响,工业控制系统中的通信可能会出现问题。此时,通过调整通信波特率来优化通信质量,提高通信稳定性和可靠性是一种常见的解决方案。

  4. 多设备协同工作: 在一些工业应用中,可能会有多个设备协同工作,它们之间需要进行数据交换和通信。为了最大程度地提高通信效率,可能需要根据不同设备的性能和需求调整通信波特率。

  5. 网络拓扑结构变化: 工业控制系统中的网络拓扑结构可能会随着系统需求的变化而调整。例如,新增或移除了一些设备,或者改变了设备之间的连接方式。在这种情况下,可能需要重新评估通信参数,包括波特率。

  6. 特定应用需求: 有些特定的工业应用可能对通信性能有特殊要求。例如,实时性要求较高的应用可能需要较高的通信速率,而对于一些节能环保型应用,可能会采用较低的通信速率以降低功耗。

在以上情况下,需要仔细评估系统需求和通信环境,并根据实际情况调整通信波特率。在进行波特率调整时,应确保所有相关设备的通信参数保持一致,以确保通信的稳定性和可靠性。

方法一:baud rate detection

/*
 * Copyright (C) 2014 Infineon Technologies AG. All rights reserved.
 *
 * Infineon Technologies AG (Infineon) is supplying this software for use with
 * Infineon's microcontrollers.
 * This file can be freely distributed within development tools that are
 * supporting such microcontrollers.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 */

#include <XMC4200.h>
#include <DAVE.h>			//Declarations from DAVE Code Generation (includes SFR declaration)
#include "xmc_gpio.h"
#include "xmc_uart.h"
#include "xmc_scu.h"

/**
 * @brief main() - Application entry point
 *
 * <b>Details of function</b><br>
 * This routine is the application entry point. It is invoked by the device startup code. It is responsible for
 * invoking the App initialization dispatcher routine - DAVE_Init() and hosting the place-holder for user application
 * code.
 */


 Macro and variable for 1. the basic UART LLD test SW: "Hallo!"
/* UART Tx and Rx Pin */
#define UART_RX_PIN      P1_4
#define UART_TX_PIN      P1_5

#define UART_SYNC_DATA   0x80

#define TIMEOUT_CNT  (SystemCoreClock)

XMC_GPIO_CONFIG_t        rx_pin_config;
XMC_GPIO_CONFIG_t        tx_pin_config;

/* UART configuration */
XMC_USIC_CH_t           *uart = XMC_UART0_CH0;
XMC_UART_CH_CONFIG_t     uart_config =
{
		.baudrate = 115200U,
		.oversampling = 16U,
		.data_bits = 8U,
		.frame_length = 8U,
		.stop_bits = 1U,
		.parity_mode = XMC_USIC_CH_PARITY_MODE_NONE
};

uint8_t BaudrateDetect(XMC_USIC_CH_t *const channel, uint8_t sync_data, uint8_t oversampling);

uint8_t do_calibration;

 macro and ISR for 2. the advanced UART LLD test SW: receive date from keyboard using interrupt (USIC0_SR5)
#define USIC0_SR4          4
#define USIC0_SR5          5

void USIC0_5_IRQHandler(void)      // USIC0_5_IRQHandler
{
	uint16_t received_data;
	uint16_t status;
	uint8_t error = 0;

	status = XMC_UART_CH_GetStatusFlag(uart);
	received_data = XMC_UART_CH_GetReceivedData(uart);  // receive data

	if(status & XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0) // Format error ?
	{
		error = 1;
		XMC_UART_CH_ClearStatusFlag(uart, XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0);
		return;
	}

	if(status & XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION) // Data lost error ?
	{
		error = 1;
		XMC_UART_CH_ClearStatusFlag(uart, XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION);
		return;
	}

	if((error == 1) || received_data != UART_SYNC_DATA)
	{
		XMC_USIC_CH_DisableEvent(uart, XMC_USIC_CH_EVENT_STANDARD_RECEIVE);
		XMC_USIC_CH_DisableEvent(uart, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE);
		XMC_UART_CH_DisableEvent(uart, 0x00000040); // Set frame error interrupt enable
		NVIC_DisableIRQ(USIC0_5_IRQn);       // CMSIS function for NVIC control: enable IRQn
		do_calibration = 1;
		XMC_GPIO_SetOutputLevel(P2_1, XMC_GPIO_OUTPUT_LEVEL_LOW);
	}
	else
	{
	//    XMC_UART_CH_Transmit(uart, '\n');
		XMC_UART_CH_Transmit(uart, received_data);          // and send it back
	}


}

void delay(uint32_t cnt)
{
	while(cnt--);
}

int main(void)
{
  uint8_t ret;
  uint8_t uart_ready = 0;

  XMC_GPIO_SetHardwareControl(P2_1, XMC_GPIO_HWCTRL_DISABLED);
  XMC_GPIO_SetMode(P2_1, XMC_GPIO_MODE_OUTPUT_PUSH_PULL);
  XMC_GPIO_SetOutputLevel(P2_1, XMC_GPIO_OUTPUT_LEVEL_HIGH);

  /*UART initialization sequence*/
  XMC_UART_CH_Init(uart, &uart_config);

  XMC_UART_CH_SetInputSource(uart, XMC_UART_CH_INPUT_RXD , USIC0_C0_DX0_P1_4);

//  XMC_USIC_CH_EnableInputDigitalFilter(uart, XMC_USIC_CH_INPUT_DX0); // Enbale digital filter
  XMC_UART_CH_Start(uart);  // uart.CCR.mode=UART-> USIC0_CH0 is switched for UART operation mode


  /*UART Rx pin configuration*/
  rx_pin_config.mode = XMC_GPIO_MODE_INPUT_PULL_UP;          // Rx input with internal pull-up
  XMC_GPIO_Init(UART_RX_PIN, &rx_pin_config);
  /*UART Tx pin configuration*/
  tx_pin_config.output_level = XMC_GPIO_OUTPUT_LEVEL_HIGH;
  tx_pin_config.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2;  // Tx output in ALT2
  XMC_GPIO_Init(UART_TX_PIN, &tx_pin_config);

  XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_STANDARD_RECEIVE);                                            // enable interrupt RI
  XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_RECEIVE, USIC0_SR5);             // set USIC0 SR5 for RI
  XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE);                                         // 'USIC_AI.007' -> AIR ON
  XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE, USIC0_SR5);

  XMC_UART_CH_EnableEvent(uart, 0x00000040); // Set frame error interrupt enable
  XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_PROTOCOL, USIC0_SR5);

  NVIC_SetPriority(USIC0_5_IRQn,2);   // CMSIS function for NVIC control: NVIC_SetPriority(IRQn_t IRQn, uint32_t priority): priority=0..63
  NVIC_EnableIRQ(USIC0_5_IRQn);       // CMSIS function for NVIC control: enable IRQn

  while(1U)
  {

	  if(do_calibration == 1)
	  {
		  delay(SystemCoreClock/100);
		  do_calibration = 0;
		  ret = BaudrateDetect(uart, UART_SYNC_DATA,uart_config.oversampling);
		  if(ret != 0)
		  {
			  while(1);
		  }
		  else
		  {
			  uart_ready = 1;
		  }
	  }

	  if(uart_ready == 1)
	  {
		   XMC_GPIO_SetOutputLevel(P2_1, XMC_GPIO_OUTPUT_LEVEL_HIGH);

		    XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_STANDARD_RECEIVE);                                            // enable interrupt RI
		    XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_RECEIVE, USIC0_SR5);             // set USIC0 SR5 for RI
		    XMC_USIC_CH_EnableEvent(uart, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE);                                         // 'USIC_AI.007' -> AIR ON
		    XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE, USIC0_SR5);

		    XMC_UART_CH_EnableEvent(uart, 0x00000040); // Set frame error interrupt enable
		    XMC_USIC_CH_SetInterruptNodePointer(uart, XMC_USIC_CH_INTERRUPT_NODE_POINTER_PROTOCOL, USIC0_SR5);

		    NVIC_SetPriority(USIC0_5_IRQn,2);   // CMSIS function for NVIC control: NVIC_SetPriority(IRQn_t IRQn, uint32_t priority): priority=0..63
		    NVIC_EnableIRQ(USIC0_5_IRQn);       // CMSIS function for NVIC control: enable IRQn
		    uart_ready = 2;
	  }

  }

  return 1;
}

uint8_t CalDetectDataLength(uint8_t u8Data)
{
	uint8_t i;
	for(i=0; i<8; i++)
	{
		if((u8Data & (1ul<<i)) == 0)
		{
			//i++;
		}
		else
		{
			break;
		}
	}

	return (i+1); // Return measure length
}

uint8_t CalEdgeTimes(uint8_t u8Data, uint8_t *fall, uint8_t *rise)
{
	uint8_t i;
	uint8_t fall_cnt = 0, rise_cnt = 0;
	uint8_t pre_level = 1;
	uint16_t data = 0;

	data = (u8Data << 1) | (1ul << 9);

	for(i=0; i<10; i++)
	{
		if( ((data & (1ul<<i)) == 0) && (pre_level == 1))
		{
			fall_cnt++;
			pre_level = 0;
		}

		if(((data & (1ul<<i)) == (1ul<<i)) && (pre_level == 0))
		{
			rise_cnt++;
			pre_level = 1;
		}
	}

	*fall = fall_cnt;
	*rise = rise_cnt;

	return 0;
}

uint32_t TrimBaudrate(uint32_t Baudrate)
{
	uint32_t rate[9] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400};
	uint8_t i;

	for ( i = 0; i<8; i++)
	{
		if(rate[i] > Baudrate)
		{
			break;
		}
	}

	if(rate[i] - Baudrate  < Baudrate - rate[i-1])
		return rate[i];

	return rate[i-1];
}

uint8_t BaudrateDetect(XMC_USIC_CH_t *const channel, uint8_t sync_data, uint8_t oversampling)
{
	uint8_t detect_times = 0;
	uint8_t detect_bit_length;
	uint32_t detect_data;
	float f_detect_baudrate;
	uint32_t detect_baudrate;
	uint32_t step;
	uint32_t Pin;
	uint32_t overflow_times = 0;
	uint32_t  timeout = TIMEOUT_CNT;
	uint8_t falling_times, rising_times, total_edge_times;
	uint8_t calibration_finish = 0;
	static uint8_t dummy;
	uint8_t baudrate_correct_result = 0;
    detect_bit_length = CalDetectDataLength(sync_data);
    CalEdgeTimes(sync_data, &falling_times, &rising_times);
    total_edge_times = falling_times + rising_times;

    step = 1024 - SystemCoreClock/1000000;
    channel->FDR = (step | (1ul << 14)); // STEP = 944, fin = 80MHz / (1024 - 944) = 1MHz @ SystemCoreClock=80000000
    Pin = 1000000;

    detect_times = 0;
    overflow_times = 0;
    XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
    XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
    XMC_USIC_CH_SetInputTriggerCombinationMode(channel, XMC_USIC_CH_INPUT_DX0, XMC_USIC_CH_INPUT_COMBINATION_MODE_BOTH_EDGES);
    XMC_USIC_CH_EnableTimeMeasurement(channel); // enable time measurement

    while(1)
    {
    	timeout--;

		if(XMC_UART_CH_GetStatusFlag(channel) & XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION)
		{

			if(detect_times == 0)
			{
				detect_times++;
				total_edge_times--;
			}
			else if(detect_times == 1)
			{
				detect_data = channel->CMTR;
				detect_times = 2;
				total_edge_times--;
			}
			else
			{
				total_edge_times--;
			}

			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
		}

		if(XMC_UART_CH_GetStatusFlag(channel) & XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION)
		{
			if(detect_times == 1)
			{
				XMC_USIC_CH_EnableTimeMeasurement(channel); // enable time measurement
				XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
				overflow_times++;
			}
		}


		if(total_edge_times == 0)
		{
			XMC_USIC_CH_SetInputTriggerCombinationMode(channel, XMC_USIC_CH_INPUT_DX0, XMC_USIC_CH_INPUT_COMBINATION_MODE_TRIGGER_DISABLED);
			XMC_USIC_CH_DisableTimeMeasurement(channel); // enable time measurement

			// Calculate baudrate
			detect_data = overflow_times*1024 + detect_data;
			f_detect_baudrate = (float)(Pin*detect_bit_length)/(float)detect_data;
			detect_baudrate = (uint32_t)f_detect_baudrate;
//					detect_baudrate = TrimBaudrate(detect_baudrate);

			XMC_USIC_CH_SetBaudrate(channel, detect_baudrate, oversampling);

//					XMC_USIC_CH_EnableTimeMeasurement(channel); // enable time measurement

			dummy =XMC_UART_CH_GetReceivedData(channel);
			dummy =XMC_UART_CH_GetReceivedData(channel);

			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0);
			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION);

			calibration_finish = 1;
			//break;
		}

		if(timeout == 0)
		{
			XMC_USIC_CH_DisableTimeMeasurement(channel); // enable time measurement

			dummy =XMC_UART_CH_GetReceivedData(channel);
			dummy =XMC_UART_CH_GetReceivedData(channel);

			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION);
			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_BAUD_RATE_GENERATOR_INDICATION);
			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_FORMAT_ERROR_IN_STOP_BIT_0);
			XMC_UART_CH_ClearStatusFlag(channel, XMC_UART_CH_STATUS_FLAG_DATA_LOST_INDICATION);

			baudrate_correct_result = 1;

			break;
		}

		if(calibration_finish == 1)
		{
			break;
		}
    }

    return baudrate_correct_result;
}



方法二:master send change request

void ChangeBaudRate(uint32_t ReqBaudRate)
{
	uint32_t CurrBaudRate;

	/* UART_0 is defined in generatd code uart_conf.c */
	extern UART_t UART_0;
	/* Function definition can be found in library code */
	CurrBaudRate = XMC_USIC_CH_GetBaudrate(UART_0.channel);
	/* the method in line below cannot work, because UART_0 is defined constant initially */
	/* CurrBaudRate = UART_0.config->channel_config->baudrate; */

	if(ReqBaudRate != CurrBaudRate)
	{
	/* Function definition can be found in generatd code uart_conf.c */
		XMC_UART_CH_SetBaudrate(UART_0.channel, ReqBaudRate);
	}
}

在使用APP UART后生成的代码中,UART_0如下定义:
在这里插入图片描述

/*USIC channel configuration*/
const XMC_UART_CH_CONFIG_t UART_0_channel_config =
{
  .baudrate      = 19200U,
  .data_bits     = 8U,
  .frame_length  = 8U,
  .stop_bits     = 1U,
  .oversampling  = 16U,
  .parity_mode   = XMC_USIC_CH_PARITY_MODE_NONE
};
/*Transmit pin configuration*/
const XMC_GPIO_CONFIG_t UART_0_tx_pin_config   = 
{ 
  .mode             = XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2, 
  .output_level     = XMC_GPIO_OUTPUT_LEVEL_HIGH,
  .output_strength  = XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE
};

/*Transmit pin configuration used for initializing*/
const UART_TX_CONFIG_t UART_0_tx_pin = 
{
  .port = (XMC_GPIO_PORT_t *)PORT2_BASE,
  .config = &UART_0_tx_pin_config,
  .pin = 14U
};

/*UART APP configuration structure*/
const UART_CONFIG_t UART_0_config = 
{
  .channel_config   = &UART_0_channel_config,
  .fptr_uart_config = UART_0_init,
  .rx_cbhandler = Callback_EndofRX,  
  .sync_error_cbhandler = NULL,  
  .rx_noise_error_cbhandler = NULL,  
  .format_error_bit0_cbhandler = NULL,  
  .format_error_bit1_cbhandler = NULL,  
  .collision_error_cbhandler = NULL,
  .tx_pin_config    = &UART_0_tx_pin,
  .mode             = UART_MODE_FULLDUPLEX,
  .transmit_mode = UART_TRANSFER_MODE_DIRECT,
  .receive_mode = UART_TRANSFER_MODE_INTERRUPT,
  .tx_fifo_size     = XMC_USIC_CH_FIFO_SIZE_32WORDS,
  .rx_fifo_size     = XMC_USIC_CH_FIFO_SIZE_32WORDS,
};

/*Runtime handler*/
UART_RUNTIME_t UART_0_runtime = 
{
  .tx_busy = false,  
  .rx_busy = false,
};

/*APP handle structure*/
UART_t UART_0 = 
{
  .channel = XMC_UART1_CH0,
  .config  = &UART_0_config,
  .runtime = &UART_0_runtime
};

/*Receive pin configuration*/
const XMC_GPIO_CONFIG_t UART_0_rx_pin_config   = {
  .mode             = XMC_GPIO_MODE_INPUT_TRISTATE,
  .output_level     = XMC_GPIO_OUTPUT_LEVEL_HIGH,
  .output_strength  = XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE
};

在xmc_usic.c中,XMC_USIC_CH_GetBaudrate函数定义为:

uint32_t XMC_USIC_CH_GetBaudrate(XMC_USIC_CH_t *const channel)
{
  uint32_t divider;
  if ((channel->BRG & USIC_CH_BRG_CTQSEL_Msk) == USIC_CH_BRG_CTQSEL_Msk)
  {
    // CTQSEL = 3
    divider = 2;
  }
  else
  {
    // CTQSEL = 0, 1, or 2
    divider = (channel->BRG & USIC_CH_BRG_PPPEN_Msk) ? 2 : 1;

    if ((((channel->BRG & USIC_CH_BRG_CTQSEL_Msk) >> USIC_CH_BRG_CTQSEL_Pos) & 0x1) == 0)
    {
      // CTQSEL = 0 or 2
      divider *= ((channel->BRG & USIC_CH_BRG_PDIV_Msk) >> USIC_CH_BRG_PDIV_Pos) + 1;
      if ((((channel->BRG & USIC_CH_BRG_CTQSEL_Msk) >> USIC_CH_BRG_CTQSEL_Pos) & 0x2) != 0)
      {
        // CTQSEL = 2
        divider *= 2;
      }
    }
  }

  divider *= ((channel->BRG & USIC_CH_BRG_PCTQ_Msk) >> USIC_CH_BRG_PCTQ_Pos) + 1;
  divider *= ((channel->BRG & USIC_CH_BRG_DCTQ_Msk) >> USIC_CH_BRG_DCTQ_Pos) + 1;

  uint32_t fperi = XMC_SCU_CLOCK_GetPeripheralClockFrequency();
  float baudrate;
  if ((channel->FDR & USIC_CH_FDR_DM_Msk) == XMC_USIC_CH_BRG_CLOCK_DIVIDER_MODE_FRACTIONAL)
  {
    baudrate = fperi * (((channel->FDR & USIC_CH_FDR_STEP_Msk) >> USIC_CH_FDR_STEP_Pos) / 1024.0F);
  }
  else
  {
    /* Normal divider mode */
    baudrate = fperi * (1.0F / (1024 - ((channel->FDR & USIC_CH_FDR_STEP_Msk) >> USIC_CH_FDR_STEP_Pos)));
  }

  baudrate /= divider;

  return (uint32_t)baudrate;
}

在xmc_uart.c中,函数XMC_UART_CH_SetBaudrate被定义

XMC_UART_CH_STATUS_t XMC_UART_CH_SetBaudrate(XMC_USIC_CH_t *const channel, uint32_t rate, uint32_t oversampling)
{
  XMC_UART_CH_STATUS_t status;

  status = XMC_UART_CH_STATUS_ERROR;

  if ((rate <= (XMC_SCU_CLOCK_GetPeripheralClockFrequency() >> 2U)) && (oversampling >= XMC_UART_CH_OVERSAMPLING_MIN_VAL))
  {
    if (XMC_USIC_CH_SetBaudrate(channel, rate, oversampling) == XMC_USIC_CH_STATUS_OK)
    {
      status = XMC_UART_CH_STATUS_OK;
    }
  }
  return status;
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

六月悉茗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值