HWD32F407-HAL_RCC时钟

image

 

image

image

image

 

 

 1 /**
 2   * @brief System Clock Configuration
 3   * @retval None
 4   */
 5 void SystemClock_Config(void)
 6 {
 7   RCC_OscInitTypeDef RCC_OscInitStruct         = {0};
 8   RCC_ClkInitTypeDef RCC_ClkInitStruct         = {0};
 9   RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
10 
11   /** Configure the main internal regulator output voltage
12   */
13   __HAL_RCC_PWR_CLK_ENABLE();
14   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
15   /** Initializes the RCC Oscillators according to the specified parameters
16   * in the RCC_OscInitTypeDef structure.
17   */
18   RCC_OscInitStruct.OscillatorType      = RCC_OSCILLATORTYPE_HSI;
19   RCC_OscInitStruct.HSIState            = RCC_HSI_ON;
20   RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
21   RCC_OscInitStruct.PLL.PLLState        = RCC_PLL_ON;
22   RCC_OscInitStruct.PLL.PLLSource       = RCC_PLLSOURCE_HSI;
23   RCC_OscInitStruct.PLL.PLLM            = 8;
24   RCC_OscInitStruct.PLL.PLLN            = 180;
25   RCC_OscInitStruct.PLL.PLLP            = RCC_PLLP_DIV2;
26   RCC_OscInitStruct.PLL.PLLQ            = 2;
27   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
28   {
29     Error_Handler();
30   }
31   /** Initializes the CPU, AHB and APB buses clocks
32   */
33   RCC_ClkInitStruct.ClockType      = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
34   RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_PLLCLK;
35   RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;
36   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
37   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
38 
39   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
40   {
41     Error_Handler();
42   }
43   PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
44   PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
45   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
46   {
47     Error_Handler();
48   }
49   HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_1);
50 }
HAL_内部时钟

内部高速时钟是16MHZ,排查问题时候,使用内部可以排除外部时钟引起的大部分问题。

 

 1 /**
 2   * @brief System Clock Configuration
 3   * @retval None
 4   */
 5 void SystemClock_Config(void)
 6 {
 7   RCC_OscInitTypeDef RCC_OscInitStruct         = {0};
 8   RCC_ClkInitTypeDef RCC_ClkInitStruct         = {0};
 9   RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
10 
11   /** Configure the main internal regulator output voltage
12   */
13   __HAL_RCC_PWR_CLK_ENABLE();
14   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
15   /** Initializes the RCC Oscillators according to the specified parameters
16   * in the RCC_OscInitTypeDef structure.
17   */
18   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
19   RCC_OscInitStruct.HSEState       = RCC_HSE_BYPASS;
20   RCC_OscInitStruct.LSEState       = RCC_LSE_OFF;
21   RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_ON;
22   RCC_OscInitStruct.PLL.PLLSource  = RCC_PLLSOURCE_HSE;
23   RCC_OscInitStruct.PLL.PLLM       = 25;
24   RCC_OscInitStruct.PLL.PLLN       = 360;
25   RCC_OscInitStruct.PLL.PLLP       = RCC_PLLP_DIV2;
26   RCC_OscInitStruct.PLL.PLLQ       = 2;
27   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
28   {
29     Error_Handler();
30   }
31   /** Initializes the CPU, AHB and APB buses clocks
32   */
33   RCC_ClkInitStruct.ClockType      = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
34   RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_PLLCLK;
35   RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;
36   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
37   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
38 
39   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
40   {
41     Error_Handler();
42   }
43   PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
44   PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
45   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
46   {
47     Error_Handler();
48   }
49 }
HAL_高速外部时钟(bypass)

外部高速时钟是有源的话,可以设置RCC_HSE_ON,也可以设置成RCC_HSE_BYPASS。以25MHZ举例

 

 1 void SystemClock_Config_HSE_ON(uint32_t pll_m, uint32_t pll_n)
 2 {
 3     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 4     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 5 
 6     __HAL_RCC_PWR_CLK_ENABLE();
 7     __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 8 
 9     __HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
10 
11     // 等待HSE稳定(超时时间可以根据需要调整)
12     uint32_t timeout = 10000;  // 5ms超时
13     while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) 
14     {
15         if (timeout-- == 0) 
16         {
17             // HSE未就绪,关闭HSE
18             __HAL_RCC_HSE_CONFIG(RCC_HSE_OFF);
19             Error_Handler();  // 切换失败
20         }
21     }
22 
23     RCC_OscInitStruct.OscillatorType      = RCC_OSCILLATORTYPE_HSE;
24     RCC_OscInitStruct.HSEState            = RCC_HSE_ON;
25     RCC_OscInitStruct.HSIState            = RCC_HSI_ON;
26     RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
27 
28     RCC_OscInitStruct.PLL.PLLState        = RCC_PLL_ON;
29     RCC_OscInitStruct.PLL.PLLSource       = RCC_PLLSOURCE_HSE;
30 
31     RCC_OscInitStruct.PLL.PLLM = pll_m; //25
32     RCC_OscInitStruct.PLL.PLLN = pll_n;
33     RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
34     RCC_OscInitStruct.PLL.PLLQ = 4;
35     if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
36     {
37         Error_Handler();
38     }
39 
40     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
41     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
42     RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
43     RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
44     RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
45 
46     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK)
47     {
48         Error_Handler();
49     }
50 }
HAL_高速外部时钟(HSE)

外部高速时钟是无源的话,可以设置成RCC_HSE_ON。

 

 1 void MCO_Config_GPIO(void)
 2 {
 3     __HAL_RCC_GPIOA_CLK_ENABLE();
 4     __HAL_RCC_GPIOC_CLK_ENABLE();
 5     
 6     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
 7     HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);
 8     
 9     GPIO_InitTypeDef GPIO_InitStruct = {0};
10     
11     GPIO_InitStruct.Pin = GPIO_PIN_8;
12     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
13     GPIO_InitStruct.Pull = GPIO_NOPULL;
14     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; // 高速
15     GPIO_InitStruct.Alternate = GPIO_AF0_MCO; // AF0: MCO
16     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
17     
18     GPIO_InitStruct.Pin = GPIO_PIN_9;
19     GPIO_InitStruct.Alternate = GPIO_AF0_MCO; // AF0: MCO
20     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
21     
22     // 配置 MCO1 (PA8) 输出 SYSCLK
23     HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_PLLCLK, RCC_MCODIV_2); // /2 分频
24     // 配置 MCO2 (PC9) 输出 SYSCLK
25     HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_2); // /2 分频
26 }
HAL_MCO(PA8和PC9)

可以在PA8和PC9上输出时钟频率,时钟源和分频系数如下,输出时钟频率到GPIO后,可以间接验证RCC时钟工作频率。

 1 #define RCC_MCO1SOURCE_HSI             ((uint32_t)0x00000000U)
 2 #define RCC_MCO1SOURCE_LSE             RCC_CFGR_MCO1_0
 3 #define RCC_MCO1SOURCE_HSE             RCC_CFGR_MCO1_1
 4 #define RCC_MCO1SOURCE_PLLCLK          RCC_CFGR_MCO1
 5 
 6 #define RCC_MCODIV_1                   ((uint32_t)0x00000000U)
 7 #define RCC_MCODIV_2                   RCC_CFGR_MCO1PRE_2
 8 #define RCC_MCODIV_3                   ((uint32_t)RCC_CFGR_MCO1PRE_0 | RCC_CFGR_MCO1PRE_2)
 9 #define RCC_MCODIV_4                   ((uint32_t)RCC_CFGR_MCO1PRE_1 | RCC_CFGR_MCO1PRE_2)
10 #define RCC_MCODIV_5                   RCC_CFGR_MCO1PRE
11 
12 #define RCC_MCO2SOURCE_SYSCLK          ((uint32_t)0x00000000U)
13 #define RCC_MCO2SOURCE_PLLI2SCLK       RCC_CFGR_MCO2_0
14 #define RCC_MCO2SOURCE_HSE             RCC_CFGR_MCO2_1
15 #define RCC_MCO2SOURCE_PLLCLK          RCC_CFGR_MCO2
16 
17 #define RCC_MCODIV_1                   ((uint32_t)0x00000000U)
18 #define RCC_MCODIV_2                   RCC_CFGR_MCO1PRE_2
19 #define RCC_MCODIV_3                   ((uint32_t)RCC_CFGR_MCO1PRE_0 | RCC_CFGR_MCO1PRE_2)
20 #define RCC_MCODIV_4                   ((uint32_t)RCC_CFGR_MCO1PRE_1 | RCC_CFGR_MCO1PRE_2)
21 #define RCC_MCODIV_5                   RCC_CFGR_MCO1PRE
MCO1(PA8)和MCO2(PC9)

 

 1 void led_init(GPIO_TypeDef *GPIOx, uint32_t Pin)
 2 {
 3     __HAL_RCC_GPIOI_CLK_ENABLE();
 4     __HAL_RCC_GPIOG_CLK_ENABLE();
 5     __HAL_RCC_GPIOE_CLK_ENABLE();
 6     
 7     GPIO_InitTypeDef GPIO_InitStruct = {0};
 8     GPIO_InitStruct.Pin = Pin;
 9     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出                 
10     GPIO_InitStruct.Pull = GPIO_NOPULL;                         
11     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
12     
13     HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
14     
15     HAL_GPIO_WritePin(GPIOx, Pin , GPIO_PIN_RESET);
16 }
17 
18 
19 void main(void)
20 {
21     GPIO_TypeDef *port = GPIOA;
22     uint32_t pin = GPIO_PIN_6;
23     
24     led_init(port, pin);
25     
26     while(1)
27     {
28         HAL_GPIO_TogglePin(port, pin);
29         HAL_Delay(50-1);
30     }
31 }
HAL_灯闪烁

在排查问题时候,可以通过在特定GPIO上周期性输出高低电平来验证MCU是否在运行。

 

1 if (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSI)
2 {
3     for (int i = 0; i < 6; i++) {
4         HAL_GPIO_TogglePin(port, pin);
5         HAL_Delay(1000-1);
6     }
7     HAL_RCC_DeInit();
8     SystemClock_Config_HSE_ON(25, 128);
9 }
内部时钟切换到外部高速时钟

从内部高速时钟切换到外部时钟,切换先可以判断当前的PLL时钟源是内部高速时钟时,就切换到外部高速时钟,切换之前要调用HAL_RCC_DeInit。

之前解决过一个问题,是客户软件工程将系统频率配置成了540MHZ,远超MCU的最高工作频率180MHZ,导致了MCU下载、单步调试等各种异常问题,最后是下载了一个内部时钟到外部外设的切换程序后,MCU恢复了正常:程序首先以HSI工作3秒左右,然后切换HSE。

 

 1     
 2 if (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE)
 3 {
 4     for (int i = 0; i < 6; i++) {
 5         HAL_GPIO_TogglePin(port, pin);
 6         HAL_Delay(1000-1);
 7     }
 8     HAL_RCC_DeInit();
 9     SystemClock_Config_HSI();
10 }
外部高速时钟切换到内部时钟

从外部高速时钟切换到内部时钟。

 

posted on 2026-03-30 10:06  LiveWithACat  阅读(0)  评论(0)    收藏  举报