GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?

这里写自定义目录标题


使用GD32F103单片机设置系统时钟到108MHz,使用定时器、PWM等外设时候都运行正常,但是初始化串口后波特率始终不对。在网上找了一些解决办法均无效,于是开启调试模式,一步一步对照DATASheet来查找问题。在这里做个记录以备后续查看。

首先是设置时钟到108MHz,这个是参考网上代码的。
1.在"system_stm32f10x.c"中添加 #define SYSCLK_HSI_108MHz 108000000
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第1张图片
继续添加
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第2张图片
继续添加
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第3张图片
在SetSysClock()函数中添加SetSysClockHSITo108();的函数
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第4张图片
最后添加void SetSysClockHSITo108(void)的函数
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第5张图片
整个system_stm32f10x.c文件如下

#include “stm32f10x.h”
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE /
#define SYSCLK_FREQ_24MHz 24000000
#else
/
#define SYSCLK_FREQ_HSE HSE_VALUE /
/
#define SYSCLK_FREQ_24MHz 24000000 /
/
#define SYSCLK_FREQ_36MHz 36000000 /
/
#define SYSCLK_FREQ_48MHz 48000000 /
/
#define SYSCLK_FREQ_56MHz 56000000 */
//#define SYSCLK_FREQ_72MHz 72000000

//#define SYSCLK_HSI_64MHz 64000000

#define SYSCLK_HSI_108MHz 108000000
#endif
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
/* #define DATA_IN_ExtSRAM /
#endif
#define VECT_TAB_OFFSET 0x0 /
!< Vector Table base offset field.
This value must be a multiple of 0x200. /
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /
!< System Clock Frequency (Core Clock) /
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /
!< System Clock Frequency (Core Clock) /
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /
!< System Clock Frequency (Core Clock) /
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /
!< System Clock Frequency (Core Clock) /
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /
!< System Clock Frequency (Core Clock) /
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /
!< System Clock Frequency (Core Clock) */

#elif defined SYSCLK_HSI_64MHz
uint32_t SystemCoreClock = SYSCLK_HSI_64MHz;

#elif defined SYSCLK_HSI_108MHz
uint32_t SystemCoreClock = SYSCLK_HSI_108MHz;
#else /*!< HSI Selected as System Clock source /
uint32_t SystemCoreClock = HSI_VALUE; /
!< System Clock Frequency (Core Clock) */
#endif

__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};

static void SetSysClock(void);

#ifdef SYSCLK_FREQ_HSE
static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
static void SetSysClockTo56(void);
#elif defined SYSCLK_FREQ_72MHz
static void SetSysClockTo72(void);

#elif defined SYSCLK_HSI_64MHz
static void SetSysClockHSITo64(void);

#elif defined SYSCLK_HSI_108MHz
static void SetSysClockHSITo108(void);

#endif

#ifdef DATA_IN_ExtSRAM
static void SystemInit_ExtMemCtl(void);
#endif /* DATA_IN_ExtSRAM /
void SystemInit (void)
{
/
Reset the RCC clock configuration to the default reset state(for debug purpose) /
/
Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;

/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits /
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /
STM32F10X_CL */

/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;

/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;

/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
/* Reset PLL2ON and PLL3ON bits */
RCC->CR &= (uint32_t)0xEBFFFFFF;

/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x00FF0000;

/* Reset CFGR2 register /
RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/
Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;

/* Reset CFGR2 register /
RCC->CFGR2 = 0x00000000;
#else
/
Disable all interrupts and clear pending bits /
RCC->CIR = 0x009F0000;
#endif /
STM32F10X_CL */

#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif

/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers /
/
Configure the Flash Latency cycles and enable prefetch buffer */
SetSysClock();

#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. /
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /
Vector Table Relocation in Internal FLASH. /
#endif
}
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0;
#ifdef STM32F10X_CL
uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0;
#endif /
STM32F10X_CL /
#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
uint32_t prediv1factor = 0;
#endif /
STM32F10X_LD_VL or STM32F10X_MD_VL or STM32F10X_HD_VL /
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case 0x00: /
HSI used as system clock /
SystemCoreClock = HSI_VALUE;
break;
case 0x04: /
HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case 0x08:
pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
#ifndef STM32F10X_CL
pllmull = ( pllmull >> 18) + 2;
if (pllsource == 0x00)
{
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
}
else
{
#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
#else
if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET)
{
SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
}
else
{
SystemCoreClock = HSE_VALUE * pllmull;
}
#endif
}
#else
pllmull = pllmull >> 18;

  if (pllmull != 0x0D)
  {
     pllmull += 2;
  }
  else
  {
    pllmull = 13 / 2; 
  }
  if (pllsource == 0x00)
  {
    SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
  }
  else
  {
    prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;
    prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
    if (prediv1source == 0)
    { 
      /* HSE oscillator clock selected as PREDIV1 clock entry */
      SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;          
    }
    else
    {/* PLL2 clock selected as PREDIV1 clock entry */
      /* Get PREDIV2 division factor and PLL2 multiplication factor */
      prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1;
      pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8 ) + 2; 
      SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;                         
    }
  }

#endif /* STM32F10X_CL */
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
SystemCoreClock >>= tmp;
}

/**

  • @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
  • @param None
  • @retval None
    */
    static void SetSysClock(void)
    {
    #ifdef SYSCLK_FREQ_HSE
    SetSysClockToHSE();
    #elif defined SYSCLK_FREQ_24MHz
    SetSysClockTo24();
    #elif defined SYSCLK_FREQ_36MHz
    SetSysClockTo36();
    #elif defined SYSCLK_FREQ_48MHz
    SetSysClockTo48();
    #elif defined SYSCLK_FREQ_56MHz
    SetSysClockTo56();
    #elif defined SYSCLK_FREQ_72MHz
    SetSysClockTo72();

#elif defined SYSCLK_HSI_64MHz
SetSysClockHSITo64();

#elif defined SYSCLK_HSI_108MHz
SetSysClockHSITo108();
#endif
}

#ifdef DATA_IN_ExtSRAM

void SystemInit_ExtMemCtl(void)
{
RCC->AHBENR = 0x00000114;

RCC->APB2ENR = 0x000001E0;

GPIOD->CRL = 0x44BB44BB;
GPIOD->CRH = 0xBBBBBBBB;

GPIOE->CRL = 0xB44444BB;
GPIOE->CRH = 0xBBBBBBBB;

GPIOF->CRL = 0x44BBBBBB;
GPIOF->CRH = 0xBBBB4444;

GPIOG->CRL = 0x44BBBBBB;
GPIOG->CRH = 0x44444B44;

/---------------- FSMC Configuration ---------------------------------------/
/---------------- Enable FSMC Bank1_SRAM Bank ------------------------------/

FSMC_Bank1->BTCR[4] = 0x00001011;
FSMC_Bank1->BTCR[5] = 0x00000200;
}
#endif /* DATA_IN_ExtSRAM */

#ifdef SYSCLK_FREQ_HSE
/**

  • @brief Selects HSE as System clock source and configure HCLK, PCLK2
  •      and PCLK1 prescalers.
    
  • @note This function should be used only after reset.
  • @param None
  • @retval None
    */
    static void SetSysClockToHSE(void)
    {
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------/
/
Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);

/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}

if (HSEStatus == (uint32_t)0x01)
{

#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 0 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

#ifndef STM32F10X_CL
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
#else
if (HSE_VALUE <= 24000000)
{
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
}
else
{
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;
}
#endif /* STM32F10X_CL */
#endif

/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;

/* Select HSE as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSE;    

/* Wait till HSE is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x04)
{
}

}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error /
}
}
#elif defined SYSCLK_FREQ_24MHz
/
*

  • @brief Sets System clock frequency to 24MHz and configure HCLK, PCLK2
  •      and PCLK1 prescalers.
    
  • @note This function should be used only after reset.
  • @param None
  • @retval None
    */
    static void SetSysClockTo24(void)
    {
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------/
/
Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);

/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}

if (HSEStatus == (uint32_t)0x01)
{
#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 0 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;    

#endif

/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;

#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------/
/
PLL configuration: PLLCLK = PREDIV1 * 6 = 24 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL6);

/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 10 = 4 MHz */       
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                          RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                         RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV10);

/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}   

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
/* PLL configuration: = (HSE / 2) * 6 = 24 MHz /
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1_Div2 | RCC_CFGR_PLLMULL6);
#else
/
PLL configuration: = (HSE / 2) * 6 = 24 MHz /
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL6);
#endif /
STM32F10X_CL */

/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;

/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}

}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error /
}
}
#elif defined SYSCLK_FREQ_36MHz
/
*

  • @brief Sets System clock frequency to 36MHz and configure HCLK, PCLK2
  •      and PCLK1 prescalers. 
    
  • @note This function should be used only after reset.
  • @param None
  • @retval None
    */
    static void SetSysClockTo36(void)
    {
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------/
/
Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);

/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}

if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 1 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;    

/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;

#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/

/* PLL configuration: PLLCLK = PREDIV1 * 9 = 36 MHz */ 
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                        RCC_CFGR_PLLMULL9); 

/*!< PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 10 = 4 MHz */
    
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                          RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                         RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV10);

/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}

#else
/* PLL configuration: PLLCLK = (HSE / 2) * 9 = 36 MHz /
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL9);
#endif /
STM32F10X_CL */

/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;

/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}

}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error /
}
}
#elif defined SYSCLK_FREQ_48MHz
/
*

  • @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2
  •      and PCLK1 prescalers. 
    
  • @note This function should be used only after reset.
  • @param None
  • @retval None
    */
    static void SetSysClockTo48(void)
    {
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------/
/
Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);

/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}

if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 1 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;    

/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------/
/
PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz /
/
PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                          RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                         RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}


/* PLL configuration: PLLCLK = PREDIV1 * 6 = 48 MHz */ 
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                        RCC_CFGR_PLLMULL6); 

#else
/* PLL configuration: PLLCLK = HSE * 6 = 48 MHz /
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6);
#endif /
STM32F10X_CL */

/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;

/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}

}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}

#elif defined SYSCLK_FREQ_56MHz
/**

  • @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2
  •      and PCLK1 prescalers. 
    
  • @note This function should be used only after reset.
  • @param None
  • @retval None
    */
    static void SetSysClockTo56(void)
    {
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------/
/
Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);

/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}

if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------/
/
PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz /
/
PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                          RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                         RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}


/* PLL configuration: PLLCLK = PREDIV1 * 7 = 56 MHz */ 
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                        RCC_CFGR_PLLMULL7); 

#else
/* PLL configuration: PLLCLK = HSE * 7 = 56 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL7);

#endif /* STM32F10X_CL */

/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;

/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}

}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}

#elif defined SYSCLK_FREQ_72MHz
/**

  • @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2
  •      and PCLK1 prescalers. 
    
  • @note This function should be used only after reset.
  • @param None
  • @retval None
    */
    static void SetSysClockTo72(void)
    {
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------/
/
Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);

/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}

if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    


/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------/
/
PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz /
/
PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                          RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                         RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}


/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                        RCC_CFGR_PLLMULL9); 

#else
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz /
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /
STM32F10X_CL */

/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;

/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}

}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}

#elif defined SYSCLK_HSI_64MHz
/**

  • @brief 使用内部时钟倍频到64MHz

  • @note This function should be used only after reset.

  • @param None

  • @retval None
    */
    static void SetSysClockHSITo64(void)
    {

    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;

    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

    /* PLL configuration: PLLCLK = HSI * 16 = 64 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLMULL16);

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
    }

#elif defined SYSCLK_HSI_108MHz
/**

  • @brief 使用内部时钟倍频到108MHz

  • @note This function should be used only after reset.

  • @param None

  • @retval None
    /
    #define RCC_CFGR_PLLMULL27 ((uint32_t)0x08280000)
    static void SetSysClockHSITo108(void)
    {
    /
    Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;

    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

    /* PLL configuration: PLLCLK = HSI * 27 = 108 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLMULL27);

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
    }
    #endif

配置完时钟,以108M的频率设置一个PWM输出用示波器测量确实是108MHz,但配置串口输出时钟不对。。。。。。。
网上搜索到https://blog.csdn.net/liaofeifly/article/details/78470112
这篇文章提到需要改void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks)这个函数,我改的试了下,串口依然乱码。。。。。。。
于是打开串口初始化,找下波特率设置函数看是哪的问题。
最终在USART_Init函数中找到了RCC_GetClocksFreq(&RCC_ClocksStatus);函数
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第6张图片
仿真运行到这里怎么获取到的PCLK2和PCLK1的时钟是48MHz和24MHz
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第7张图片
查看了GD32F103的系统时钟树,应该是108MHz和54MHz才对啊。。。。。。
继续到RCC_GetClocksFreq(&RCC_ClocksStatus);函数里面看看。。。。。。
我这里的RCC_GetClocksFreq()函数已经替换成上面那个连接里的RCC_GetClocksFreq();函数了
源代码如下

void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, presc = 0;

/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & CFGR_SWS_Mask;

switch (tmp)
{
case 0x00: /* HSI used as system clock /
RCC_Clocks->SYSCLK_Frequency = HSI_VALUE;
break;
case 0x04: /
HSE used as system clock /
RCC_Clocks->SYSCLK_Frequency = HSE_VALUE;
break;
case 0x08: /
PLL used as system clock */

  /* Get PLL clock source and multiplication factor ----------------------*/
  pllmull = RCC->CFGR &((uint32_t)0x203C0000);
  pllsource = RCC->CFGR & CFGR_PLLSRC_Mask;
  
if(((pllmull)&(0x20000000)) != 0)
      pllmull = (((pllmull)&(0x003C0000)) >> 18) + 17;
  else
      pllmull = ( pllmull >> 18) +2;
  
  if (pllsource == 0x00)
  {/* HSI oscillator clock divided by 2 selected as PLL clock entry */
    RCC_Clocks->SYSCLK_Frequency = (HSI_VALUE >> 1) * pllmull;
  }
  else
  {
    /* HSE selected as PLL clock entry */
    if ((RCC->CFGR & CFGR_PLLXTPRE_Mask) != (uint32_t)RESET)
    {/* HSE oscillator clock divided by 2 */
      RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE >> 1) * pllmull;
    }
    else
    {
      RCC_Clocks->SYSCLK_Frequency = HSE_VALUE * pllmull;
    }
  }
  break;
default:
  RCC_Clocks->SYSCLK_Frequency = HSI_VALUE;
  break;

}

/* Compute HCLK, PCLK1, PCLK2 and ADCCLK clocks frequencies ----------------/
/
Get HCLK prescaler /
tmp = RCC->CFGR & CFGR_HPRE_Set_Mask;
tmp = tmp >> 4;
presc = APBAHBPrescTable[tmp];
/
HCLK clock frequency /
RCC_Clocks->HCLK_Frequency = RCC_Clocks->SYSCLK_Frequency >> presc;
/
Get PCLK1 prescaler /
tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
tmp = tmp >> 8;
presc = APBAHBPrescTable[tmp];
/
PCLK1 clock frequency /
RCC_Clocks->PCLK1_Frequency = RCC_Clocks->HCLK_Frequency >> presc;
/
Get PCLK2 prescaler /
tmp = RCC->CFGR & CFGR_PPRE2_Set_Mask;
tmp = tmp >> 11;
presc = APBAHBPrescTable[tmp];
/
PCLK2 clock frequency /
RCC_Clocks->PCLK2_Frequency = RCC_Clocks->HCLK_Frequency >> presc;
/
Get ADCCLK prescaler /
tmp = RCC->CFGR & CFGR_ADCPRE_Set_Mask;
tmp = (tmp >> 14)+(tmp >> 26);
presc = ADCPrescTable[tmp];
/
ADCCLK clock frequency */
RCC_Clocks->ADCCLK_Frequency = RCC_Clocks->PCLK2_Frequency / presc;
}

仔细分析发现这个函数里红框中的代码应该是GD单片机独有的,参考数据手册也能对应上
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第8张图片

GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第9张图片
其中pllmull = RCC->CFGR &((uint32_t)0x203C0000);这句话就是取PLLMF的第29为和18到21位呀
if(((pllmull)&(0x20000000)) != 0)这句话就是判断第29位的值,按理说倍频到108MHz这一位应该是1的,仿真却发现
这一位是0啊。。。。。
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第10张图片
于是回到"system_stm32f10x.c"文件找到void SetSysClockHSITo108(void)函数
找到RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLMULL27);
其中 #define RCC_CFGR_PLLMULL27 ((uint32_t)0x08280000)
这里和我找到的数据手册上对不上啊,按照数据手册上应该是29、21、20、19、18这几位组成PLLMF
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第11张图片
这个定义的确是27、21、20、19、18这几位组成PLLMF,
如果是29、21、20、19、18这几位组成PLLMF那RCC_CFGR_PLLMULL27应该定义成0x20280000才对啊,我还是相信数据手册上的吧,把这个定义改成0x20280000下载进去发现原本108MHZ的时钟却不对了,再仿真看
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第12张图片
执行完RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLMULL27);这一句CFGR寄存器里的值确是0x00280400,
说明第29位根本没写进去,时钟肯定没法到108MHz。我又试了下把RCC_CFGR_PLLMULL27改成0x08280000,发现这个可以到108MHz而且CFGR寄存器也显示正常,可是这明明写的是第CFGR寄存器的第27位啊。。。。我看的是个假的数据手册吗?这是我才从兆易创新官网上下载的啊。。。。那好吧我就当这是第27位去算吧。。。。
回到void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks)函数发现这里面都是按照第29位来算的,
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第13张图片
那我就改成第27位来试试,
pllmull = RCC->CFGR &((uint32_t)0x203C0000);改成 pllmull = RCC->CFGR &((uint32_t)0x083C0000);

if(((pllmull)&(0x20000000)) != 0)改成 if(((pllmull)&(0x08000000)) != 0)
然后编译运行
GD32F103单片机设置时钟到108MHz,串口波特率错误的问题?_第14张图片
这次获取到的PCLK2_Frequency和PCLK1_Frequency是108MHz和54MHz,获取正确,然后看串口打印一切正常。。。。
至此问题解决。但想不通的是数据手册上明明写的是第29位,实际用的确是27位。如果有谁知道麻烦告诉我以下。
总结下,时钟倍频到108MHz需要修改的就是system_stm32f10x.c文件,解决串口波特率问题需要修改的就是stm32f10x_rcc.c文件,下载连接https://download.csdn.net/download/qq_25186745/11289474

你可能感兴趣的:(单片机开发)