当前位置:   article > 正文

初学DSP(2)-TMS320F280049C代码探究_c2000ware查找库函数例程

c2000ware查找库函数例程

 

英文缩写

  • C28X CPU+FPU(floating-point processor)
  • Trigonometric Math Unit (TMU)
  • Viterbi, Complex Math and CRC Unit (VCU)
  • Cyclic Redundancy Check (CRC)
  • start-of-conversion (SOC)

外设或通信协议

  • local interconnect network (LIN)
  • serial communication interface (SCI)
  • Controller Area Network (CAN)
  • Fast Serial Interface (FSI)
  • inter-integrated circuit (I2C)
  • serial peripheral interface (SPI)
  • enhanced pulse width modulator (ePWM)
     

寄存器编程的例程在C:\ti\c2000\C2000Ware_2_01_00_00\device_support\f28004x,

库函数编程的例程在C:\ti\c2000\C2000Ware_2_01_00_00\driverlib\f28004x\examples。

 

示例工程研究

实验参考的例程库函数版,主要针对ADC和CAN

例程是针对ControlCARD开发的,如果想将其应用到LaunchPad上,自然需要更改引脚映射。具体的代码可以在devices.h中找到。

芯片在上电或复位后会自动使能看门狗,所以初始化函数的第一句是将其关闭。

Register protection is enabled by default at startup. While protected, all writes to protected registers by the CPU
are ignored.
 

研究三个例子代码

  • // FILE:   led_ex1_blinky.c

//! This example demonstrates how to blink a LED.
//! If using LaunchPad, select build configuration for LAUNCHXL.

  • // FILE:   adc_ex1_soc_software.c

//! This example converts some voltages on ADCA and ADCB based on a software
//! trigger.

  • // FILE:   adc_ex3_temp_sensor.c

//! This example sets up the ePWM to periodically trigger the ADC.  The
//! ADC converts the internal connection to the temperature sensor,
//! which is then interpreted as a temperature by calling the
//! ADC_getTemperatureC() function.

 

 

  • // FILE:   can_ex1_loopback.c

//! This example shows the basic setup of CAN in order to transmit and receive
//! messages on the CAN bus.  The CAN peripheral is configured to transmit
//! messages with a specific CAN ID.  A message is then transmitted once per
//! second, using a simple delay loop for timing.  The message that is sent is
//! a 2 byte message that contains an incrementing pattern.

 

  1. //led_ex1_blinky.c
  2. void main(void)
  3. {
  4. //设备初始化
  5. Device_init();
  6. //设备引脚初始化
  7. Device_initGPIO();
  8. //设备引脚配置
  9. GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
  10. GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
  11. //初始化并清除 PIE registers. 关闭 CPU interrupts.
  12. Interrupt_initModule();
  13. // 初始化 PIE vector table ,指向 the shell Interrupt
  14. Interrupt_initVectorTable();
  15. // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
  16. EINT;
  17. ERTM;
  18. for(;;)
  19. {
  20. // Turn on LED
  21. GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
  22. // Delay for a bit.
  23. DEVICE_DELAY_US(500000);
  24. // Turn off LED
  25. GPIO_writePin(DEVICE_GPIO_PIN_LED1, 1);
  26. // Delay for a bit.
  27. DEVICE_DELAY_US(500000);
  28. }
  29. }
  1. FILE:   adc_ex1_soc_software.c
  2. void main(void)
  3. {
  4. Device_init();
  5. Device_initGPIO();
  6. Interrupt_initModule();
  7. Interrupt_initVectorTable();
  8. // Set up ADCs, initializing the SOCs to be triggered by software
  9. initADCs();
  10. initADCSOCs();
  11. EINT;
  12. ERTM;
  13. while(1)
  14. {
  15. //
  16. // Convert, wait for completion, and store results
  17. //
  18. ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
  19. ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER1);
  20. ADC_forceSOC(ADCB_BASE, ADC_SOC_NUMBER0);
  21. ADC_forceSOC(ADCB_BASE, ADC_SOC_NUMBER1);
  22. //
  23. // Wait for ADCA to complete, then acknowledge flag
  24. //
  25. while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false)
  26. {
  27. }
  28. ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
  29. //
  30. // Wait for ADCB to complete, then acknowledge flag
  31. //
  32. while(ADC_getInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1) == false)
  33. {
  34. }
  35. ADC_clearInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1);
  36. //
  37. // Store results
  38. //
  39. adcAResult0 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
  40. adcAResult1 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
  41. adcBResult0 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER0);
  42. adcBResult1 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER1);
  43. //
  44. // Software breakpoint. At this point, conversion results are stored in
  45. // adcAResult0, adcAResult1, adcBResult0, and adcBResult1.
  46. //
  47. // Hit run again to get updated conversions.
  48. //
  49. ESTOP0;
  50. }
  51. }

 

  1. //FILE:   adc_ex3_temp_sensor.c
  2. void main(void)
  3. {
  4. Device_init();
  5. Device_initGPIO();
  6. Interrupt_initModule();
  7. Interrupt_initVectorTable();
  8. //
  9. // Interrupts that are used in this example are re-mapped to ISR functions
  10. // found within this file.
  11. //
  12. Interrupt_register(INT_ADCB1, &adcB1ISR);
  13. //
  14. // Set up the ADC and the ePWM and initialize the SOC
  15. //
  16. initADC();
  17. initEPWM();
  18. initADCSOC();
  19. // Enable the temperature sensor and give it 500 us to power up
  20. ASysCtl_enableTemperatureSensor();
  21. DEVICE_DELAY_US(500);
  22. // Enable ADC interrupt
  23. Interrupt_enable(INT_ADCB1);
  24. // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
  25. EINT;
  26. ERTM;
  27. // Start ePWM1, enabling SOCA and putting the counter in up-count mode
  28. EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
  29. EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
  30. while(1)
  31. {
  32. ;
  33. }
  34. }
  1. void main(void)
  2. {
  3. uint16_t txMsgData[2], rxMsgData[2];
  4. Device_init();
  5. Device_initGPIO();
  6. GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
  7. GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);
  8. //
  9. // Initialize the CAN controller
  10. //
  11. CAN_initModule(CANA_BASE);
  12. //
  13. // Set up the CAN bus bit rate to 500kHz
  14. // Refer to the Driver Library User Guide for information on how to set
  15. // tighter timing control. Additionally, consult the device data sheet
  16. // for more information about the CAN module clocking.
  17. //
  18. CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
  19. Interrupt_initModule();
  20. Interrupt_initVectorTable();
  21. EINT;
  22. ERTM;
  23. //
  24. // Enable CAN test mode with external loopback
  25. //
  26. CAN_enableTestMode(CANA_BASE, CAN_TEST_EXL);
  27. //
  28. // Initialize the transmit message object used for sending CAN messages.
  29. // Message Object Parameters:
  30. // Message Object ID Number: 1
  31. // Message Identifier: 0x1234
  32. // Message Frame: Standard
  33. // Message Type: Transmit
  34. // Message ID Mask: 0x0
  35. // Message Object Flags: None
  36. // Message Data Length: 2 Bytes
  37. //
  38. CAN_setupMessageObject(CANA_BASE, 1, 0x1234, CAN_MSG_FRAME_STD,
  39. CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_NO_FLAGS,
  40. MSG_DATA_LENGTH);
  41. //
  42. // Initialize the receive message object used for receiving CAN messages.
  43. // Message Object Parameters:
  44. // Message Object ID Number: 2
  45. // Message Identifier: 0x1234
  46. // Message Frame: Standard
  47. // Message Type: Receive
  48. // Message ID Mask: 0x0
  49. // Message Object Flags: None
  50. // Message Data Length: 2 Bytes
  51. //
  52. CAN_setupMessageObject(CANA_BASE, 2, 0x1234, CAN_MSG_FRAME_STD,
  53. CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_NO_FLAGS,
  54. MSG_DATA_LENGTH);
  55. //
  56. // Start CAN module operations
  57. //
  58. CAN_startModule(CANA_BASE);
  59. //
  60. // Setup send and receive buffers
  61. //
  62. txMsgData[0] = 0x01;
  63. txMsgData[1] = 0x02;
  64. *(uint16_t *)rxMsgData = 0;
  65. //
  66. // Loop Forever - Send and Receive data continuously
  67. //
  68. for(;;)
  69. {
  70. //
  71. // Send CAN message data from message object 1
  72. //
  73. CAN_sendMessage(CANA_BASE, 1, MSG_DATA_LENGTH, txMsgData);
  74. //
  75. // Delay before receiving the data
  76. //
  77. DEVICE_DELAY_US(500000);
  78. //
  79. // Read CAN message object 2 and check for new data
  80. //
  81. if (CAN_readMessage(CANA_BASE, 2, rxMsgData))
  82. {
  83. //
  84. // Check that received data matches sent data.
  85. // Device will halt here during debug if data doesn't match.
  86. //
  87. if((txMsgData[0] != rxMsgData[0]) ||
  88. (txMsgData[1] != rxMsgData[1]))
  89. {
  90. Example_Fail = 1;
  91. asm(" ESTOP0");
  92. }
  93. else
  94. {
  95. //
  96. // Increment message received counter
  97. //
  98. msgCount++;
  99. Example_PassCount++;
  100. }
  101. }
  102. else
  103. {
  104. //
  105. // Device will halt here during debug if no new data was received.
  106. //
  107. Example_Fail = 1;
  108. asm(" ESTOP0");
  109. }
  110. //
  111. // Increment the value in the transmitted message data.
  112. //
  113. txMsgData[0] += 0x01;
  114. txMsgData[1] += 0x01;
  115. //
  116. // Reset data if exceeds a byte
  117. //
  118. if(txMsgData[0] > 0xFF)
  119. {
  120. txMsgData[0] = 0;
  121. }
  122. if(txMsgData[1] > 0xFF)
  123. {
  124. txMsgData[1] = 0;
  125. }
  126. }
  127. }

总结基本共同的步骤

1、 Device_init(); //看门狗时钟

2、Device_initGPIO();  //实际只是解除锁定,没有真正配置

2.1  设置引脚模式

  •     GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
  •     GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);

 

  •     GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
  •     GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);

3、外设初始化(可以包括引脚复用)

4、Interrupt_initModule();

5、Interrupt_initVectorTable();

6、// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)  //开全局中断
    EINT;
    ERTM;

7、使能外设

 

通用函数说明

1、Device_init()函数的说明


// Function to initialize the device. Primarily initializes system control to a
// known state by disabling the watchdog, setting up the SYSCLKOUT frequency,
// and enabling the clocks to the peripherals.
// The function also configures the GPIO pins 22 and 23 in digital mode.
// To configure these pins as analog pins, use the function GPIO_setAnalogMode
 

2、GPIO引脚说明

在文件  FILE:   pin_map.h  定义了每个引脚并用的模式

在device.h里面的引脚宏定义都是来自  pin_map.h,往下就是寄存器地址了,寄存器编程。

以CAN协议为例

  1. //from device.h
  2. // CAN External Loopback
  3. //
  4. #define DEVICE_GPIO_CFG_CANRXA GPIO_30_CANA_RX // "pinConfig" for CANA RX
  5. #define DEVICE_GPIO_CFG_CANTXA GPIO_31_CANA_TX // "pinConfig" for CANA TX
  6. #define DEVICE_GPIO_CFG_CANRXB GPIO_10_CANB_RX // "pinConfig" for CANB RX
  7. #define DEVICE_GPIO_CFG_CANTXB GPIO_8_CANB_TX // "pinConfig" for CANB TX
  1. // form pin_map.h
  2. #define GPIO_30_GPIO30 0x00081C00U
  3. #define GPIO_30_CANA_RX 0x00081C01U
  4. #define GPIO_30_SPIB_SIMO 0x00081C03U
  5. #define GPIO_30_OUTPUTXBAR7 0x00081C05U
  6. #define GPIO_30_EQEP1_STROBE 0x00081C06U
  7. #define GPIO_30_SD1_D4 0x00081C07U
  8. #define GPIO_31_GPIO31 0x00081E00U
  9. #define GPIO_31_CANA_TX 0x00081E01U
  10. #define GPIO_31_SPIB_SOMI 0x00081E03U
  11. #define GPIO_31_OUTPUTXBAR8 0x00081E05U
  12. #define GPIO_31_EQEP1_INDEX 0x00081E06U
  13. #define GPIO_31_SD1_C4 0x00081E07U
  14. #define GPIO_31_FSIRXA_D1 0x00081E09U

GPIO配置函数细究

GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);

  1. from device.h
  2. #define DEVICE_GPIO_CFG_CANRXA GPIO_30_CANA_RX // "pinConfig" for CANA RX
  3. #define DEVICE_GPIO_CFG_CANTXA GPIO_31_CANA_TX // "pinConfig" for CANA TX
  4. #define DEVICE_GPIO_CFG_CANRXB GPIO_10_CANB_RX // "pinConfig" for CANB RX
  5. #define DEVICE_GPIO_CFG_CANTXB GPIO_8_CANB_TX // "pinConfig" for CANB TX

GPIO_setPinConfig(uint32_t pinConfig);

//! Configures the alternate function of a GPIO pin.
//!
//! \param pinConfig is the pin configuration value, specified as only one
//! of the \b GPIO_#_???? values.
//!
//! This function configures the pin mux that selects the peripheral function
//! associated with a particular GPIO pin.  Only one peripheral function at a
//! time can be associated with a GPIO pin, and each peripheral function should
//! only be associated with a single GPIO pin at a time (despite the fact that
//! many of them can be associated with more than one GPIO pin).

 

GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);

  1. from device.h
  2. #define DEVICE_GPIO_PIN_LED1        31U  // GPIO number for LD2
  3. #define DEVICE_GPIO_PIN_LED2        34U  // GPIO number for LD3
  4. #define DEVICE_GPIO_CFG_LED1        GPIO_31_GPIO31  // "pinConfig" for LD2
  5. #define DEVICE_GPIO_CFG_LED2        GPIO_34_GPIO34  // "pinConfig" for LD3

GPIO_setPadConfig(uint32_t pin, uint32_t pinType)

//! Sets the pad configuration for the specified pin.
//!
//! \param pin is the identifying GPIO number of the pin.
//! \param pinType specifies the pin type.
//!
//! This function sets the pin type for the specified pin. The parameter
//! \e pinType can be the following values:
//!
//! - \b GPIO_PIN_TYPE_STD specifies a push-pull output or a floating input
//! - \b GPIO_PIN_TYPE_PULLUP specifies the pull-up is enabled for an input
//! - \b GPIO_PIN_TYPE_OD specifies an open-drain output pin
//! - \b GPIO_PIN_TYPE_INVERT specifies inverted polarity on an input

 

GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);

GPIO_setDirectionMode(uint32_t pin, GPIO_Direction pinIO);

//*****************************************************************************
//
//! Sets the direction and mode of the specified pin.
//!
//! \param pin is the identifying GPIO number of the pin.
//! \param pinIO is the pin direction mode.
//!
//! This function configures the specified pin on the selected GPIO port as
//! either input or output.
//!
//! The parameter \e pinIO is an enumerated data type that can be one of the
//! following values:
//!
//! - \b GPIO_DIR_MODE_IN
//! - \b GPIO_DIR_MODE_OUT
//!
//! where \b GPIO_DIR_MODE_IN specifies that the pin is programmed as an input
//! and \b GPIO_DIR_MODE_OUT specifies that the pin is programmed as an output.
//!
//! The pin is specified by its numerical value. For example, GPIO34 is
//! specified by passing 34 as \e pin.
 

  1. #define DEVICE_GPIO_PIN_CANTXA      31U  // GPIO number for CANTXA(引脚号)
  2. #define DEVICE_GPIO_CFG_CANRXA      GPIO_30_CANA_RX  // "pinConfig" for CANA RX(引脚配置,pin_map.h文件中)
  3. //*****************************************************************************
  4. #define GPIO_PIN_TYPE_STD       0x0000U //!< Push-pull output or floating input
  5. #define GPIO_PIN_TYPE_PULLUP    0x0001U //!< Pull-up enable for input
  6. #define GPIO_PIN_TYPE_INVERT    0x0002U //!< Invert polarity on input
  7. #define GPIO_PIN_TYPE_OD        0x0004U //!< Open-drain on output
  8. #endif
  9. //*****************************************************************************
  10. //
  11. //! Values that can be passed to GPIO_setDirectionMode() as the \e pinIO
  12. //! parameter and returned from GPIO_getDirectionMode().
  13. //
  14. //*****************************************************************************
  15. typedef enum
  16. {
  17.     GPIO_DIR_MODE_IN,                   //!< Pin is a GPIO input
  18.     GPIO_DIR_MODE_OUT                   //!< Pin is a GPIO output
  19. } GPIO_Direction;

 

设置引脚GPIO和设置引脚复用,gpio.h

GPIO输入输出:

    GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);

GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);

GPIO_readPin(uint32_t pin)

GPIO复用:

    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);

 

C2000 驱动文件层次研究

(最好把文件打开对比着看,对文件结构里理解很到位,再配合上一篇建立工程,更好的理解了)

device.c,device.h ,driverlib.h 都是是TI做好的库函数  

device.h  设备的引脚宏定义

driverlib.h 设备外设驱动的声明

  1. //from devicelib.h
  2. #include "inc/hw_memmap.h"
  3. #include "adc.h"
  4. #include "asysctl.h"
  5. #include "can.h"
  6. #include "cla.h"
  7. #include "clb.h"
  8. #include "clapromcrc.h"
  9. #include "cmpss.h"
  10. #include "cpu.h"
  11. #include "cputimer.h"
  12. #include "dac.h"
  13. #include "dcc.h"
  14. #include "dcsm.h"
  15. #include "debug.h"
  16. #include "dma.h"
  17. #include "ecap.h"
  18. #include "epwm.h"
  19. #include "eqep.h"
  20. #include "flash.h"
  21. #include "fsi.h"
  22. #include "gpio.h"
  23. #include "hrcap.h"
  24. #include "hrpwm.h"
  25. #include "i2c.h"
  26. #include "interrupt.h"
  27. #include "lin.h"
  28. #include "memcfg.h"
  29. #include "pga.h"
  30. #include "pin_map.h"
  31. #include "pin_map_legacy.h"
  32. #include "pmbus.h"
  33. #include "sci.h"
  34. #include "sdfm.h"
  35. #include "spi.h"
  36. #include "sysctl.h"
  37. #include "version.h"
  38. #include "xbar.h"

开头的 hw_memmap.h

// FILE:    hw_memmap.h
//
// TITLE:   Macros defining the memory map of the C28x.

最底层的寄存器宏定义,是E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib\inc,hw前缀的文件

// FILE:    hw_adc.h
//
// TITLE:   Definitions for the ADC registers.

再往上是 E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib  各种外设驱动文件

往上又是 E:\ti\c2000\C2000Ware_3_03_00_00\device_support\f28004x\common\include  的各种外设应用文件

编程时,写这两句,就把外设的驱动包括进来了

#include "driverlib.h"
#include "device.h"

再在工程中添加文件索引

E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib

在driverlib.h里面开头,#include "inc/hw_memmap.h",表示当前路径下inc文件夹里的hw_memmap.h,所以复制文件需要整个E:\ti\c2000\C2000Ware_3_03_00_00\driverlib\f28004x\driverlib下 的文件

再可以打开被#include "driverlib.h"引用的adc.h文件 ,开头就声明了,

  1. #include <stdbool.h>
  2. #include <stdint.h>
  3. #include "inc/hw_adc.h"
  4. #include "inc/hw_asysctl.h"
  5. #include "inc/hw_memmap.h"
  6. #include "inc/hw_types.h"
  7. #include "cpu.h"
  8. #include "debug.h"

发现 #include <stdbool.h> 这个文件就是编译器带的头文件了

所以需要在工程中添加文件索引

E:\ti\ccs1011\ccs\tools\compiler\ti-cgt-c2000_20.2.1.LTS\include

 

 

使用ADC与CAN外设初始化函数细究

  1. //驱动里面没有这个函数,需要自己写
  2. // initADCs - Function to configure and power up ADCs A and B.
  3. //
  4. void initADCs(void)
  5. {
  6. //
  7. // Setup VREF as internal
  8. //
  9. ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
  10. ADC_setVREF(ADCB_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
  11. //
  12. // Set ADCCLK divider to /4
  13. //
  14. ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
  15. ADC_setPrescaler(ADCB_BASE, ADC_CLK_DIV_4_0);
  16. //
  17. // Set pulse positions to late
  18. //
  19. ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
  20. ADC_setInterruptPulseMode(ADCB_BASE, ADC_PULSE_END_OF_CONV);
  21. //
  22. // Power up the ADCs and then delay for 1 ms
  23. //
  24. ADC_enableConverter(ADCA_BASE);
  25. ADC_enableConverter(ADCB_BASE);
  26. DEVICE_DELAY_US(1000);
  27. }
  1. from can.h
  2. //
  3. // Initialize the CAN controller
  4. //
  5. CAN_initModule(CANA_BASE);

 TI的外设初始化也是醉了,ADC初始化自己写个函数,SPI外设,建了个E:\CCS_workplace\spi_ex1_loopback\CPU1_RAM\syscfg  board.c,board.h

使用外设之前可以先看看示例工程,这样还方便一下

 

中断触发方法的研究

中断优先级

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/277953
推荐阅读
相关标签
  

闽ICP备14008679号