STM32主频72Mhz分成48Mhz给自身的USB使用

本文介绍了如何在STM32中将8MHz外部时钟配置为72MHz主频,以及如何根据16MHz外部晶振调整为24MHz主频。关键在于理解SystemInit()初始化过程和SetSysClockTo72(void)函数。由于USB时钟要求为48MHz,系统必须设定为主频48MHz或72MHz,以通过倍频得到所需时钟。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32启动后系统初始化SystemInit()

点击打开链接

    上面连接中对如何把8M的外部时钟配置成72Mhz主频讲解的很清楚。

    接下来重点说一下static void SetSysClockTo72(void)函数。

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 != HSEStartUp_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 ----------------------
<think>好的,用户之前问过关于基于STM32 HAL库使用FFT测量模拟信号频率的问题,现在他们又要求详细配置步骤教程。我需要确保这次回答完全按照用户的要求,特别是用户意图是获取详细的配置步骤说明,所以需要重点突出步骤,并且符合之前设定的格式要求。 首先,回顾之前的回答,已经涵盖了硬件配置、CubeMX设置、代码实现等内容。但用户现在需要更详细的步骤,可能需要将之前的配置流程部分扩展,拆分成更详细的步骤,并确保每一步都有具体的操作指导和代码示例。 要注意用户的要求:避免使用第一人称,用方法或步骤组织内容,每个步骤间换行。同时,需要整合网络搜索的结果,但根据历史记录,引用[1][3][4]提供了ADC配置、FFT实现和采样率计算的信息,需要确保这些信息被正确引用到步骤中。 接下来,需要将CubeMX配置流程分解为更详细的步骤,比如时钟树配置、ADC参数、DMA设置等,每一步都给出具体的配置参数和代码片段。还要检查是否需要加入更多细节,比如如何安装CMSIS-DSP库,如何在工程中启用FPU等,这些可能在之前的回答中提到过,但需要更明确的步骤。 另外,用户可能需要知道如何验证配置是否正确,比如通过调试或测量实际信号。因此,可能需要在步骤中加入验证环节,比如使用示波器检查采样率,或者通过调试查看FFT结果。 还要注意代码和公式的格式是否正确,数学公式要用$或$$包裹,代码要用三个反引号注明语言类型。确保没有使用“首先”、“然后”这样的步骤词汇,而是用分点或编号。 最后,生成相关问题时要基于配置步骤,可能涉及常见错误、优化方法或扩展应用。比如如何解决ADC采样不准的问题,或者如何提高FFT的频率分辨率。 现在需要组织内容,确保每个步骤清晰,并且包含必要的代码示例和公式,同时引用之前的资料。例如,ADC时钟配置和采样率计算的公式需要正确呈现,DMA配置的代码示例要准确,FFT初始化的代码也要正确无误。 可能还需要加入一些注意事项,比如确保内存足够,调整堆栈大小,或者如何避免频谱泄漏等。这些都是在配置过程中常见的问题,用户可能会遇到。 最后,检查是否符合所有格式要求,特别是问题部分必须位于最后,使用指定的标题,并且问题与配置步骤相关。例如,问题可能涉及具体配置错误、优化方法或其他相关应用。</think>### 基于STM32 HAL库的FFT配置详细步骤教程 --- #### 硬件准备阶段 - 开发板型号选择:STM32F4系列(推荐F407/F429支持FPU) - 最小系统要求:64KB RAM(运行1024点FFT) - 信号输入范围:0-3.3V(对应ADC量程) --- #### CubeMX配置步骤 **1. 时钟树配置** ```c // System Clock 配置 RCC_OscInitStruct.PLL.PLLM = 8; // HSE=8MHz RCC_OscInitStruct.PLL.PLLN = 336; // 主频=168MHz RCC_OscInitStruct.PLL.PLLP = 2; // APB1=42MHz RCC_OscInitStruct.PLL.PLLQ = 7; // 48MHz时钟用于USB ``` **2. ADC配置** ```mermaid graph TD A[ADC1] --> B[通道选择] B --> C{参数设置} C --> D[采样时间=84周期] C --> E[连续转换模式] C --> F[DMA使能] ``` **3. DMA配置** ```c hdma_adc1.Instance = DMA2_Stream0; hdma_adc1.Init.Channel = DMA_CHANNEL_0; hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_adc1.Init.Mode = DMA_CIRCULAR; ``` --- #### 软件工程配置 **1. CMSIS-DSP库添加** ```makefile # 在Makefile中添加 LIBS = -larm_cortexM4lf_math LIBPATH = -L"Drivers/CMSIS/Lib/GCC" ``` **2. 工程选项设置** - 启用FPU:`Project → Properties → C/C++ Build → Settings → Target Processor` ```c # 在代码中启用 __FPU_PRESENT = 1 __FPU_USED = 1 ``` --- #### 核心代码实现 **1. 全局变量定义** ```c #define FFT_LENGTH 1024 float32_t fft_input[FFT_LENGTH*2]; // 实部+虚部 float32_t fft_output[FFT_LENGTH]; arm_rfft_fast_instance_f32 fft_handler; ``` **2. FFT初始化** ```c void FFT_Init(void) { if (arm_rfft_fast_init_f32(&fft_handler, FFT_LENGTH) != ARM_MATH_SUCCESS) { Error_Handler(); } } ``` **3. ADC启动代码** ```c HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, FFT_LENGTH); ``` **4. DMA传输完成回调** ```c void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { // 数据格式转换 for(int i=0; i<FFT_LENGTH; i++) { fft_input[i] = (adc_buffer[i] / 4095.0f) * 3.3f; } // 执行FFT变换 arm_rfft_fast_f32(&fft_handler, fft_input, fft_input, 0); // 计算幅值 arm_cmplx_mag_f32(fft_input, fft_output, FFT_LENGTH); // 触发频率计算 Calculate_Frequency(); } ``` --- #### 频率计算函数 ```c void Calculate_Frequency(void) { float32_t maxValue; uint32_t maxIndex; // 寻找最大幅值(忽略直流分量) arm_max_f32(&fft_output[1], (FFT_LENGTH/2)-1, &maxValue, &maxIndex); maxIndex += 1; // 补偿直流分量偏移 // 计算实际频率 float signalFreq = (float)maxIndex * (ADC_SAMPLE_RATE) / FFT_LENGTH; // 显示处理 printf("Detected Frequency: %.2f Hz\n", signalFreq); } ``` --- #### 校准与验证步骤 **1. ADC参考电压校准** ```c HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); while(HAL_ADCEx_Calibration_GetValue(&hadc1, ADC_SINGLE_ENDED) != HAL_OK); ``` **2. 采样率验证方法** - 使用信号发生器输入标准1kHz方波 - 测量ADC的DRDY引脚波形 - 计算实际采样周期:$T_s = \frac{1}{f_s}$ **3. 频谱精度测试** ```c // 输入标准正弦波时,应满足 $$ \frac{|f_{measured} - f_{real}|}{f_{real}} \leq 1\% $$ ``` --- #### 关键配置参数表 | 参数项 | 推荐值 | 计算公式 | |----------------|-------------|-------------------------| | ADC采样周期 | 84 cycles | $T_{conv} = \frac{SampleTime + 12.5}{ADC\_CLK}$ | | FFT点数 | 1024 | $N = 2^n, n\geq10$ | | 采样率 | 200kHz | $f_s \geq 2.56 \times f_{max}$ | | 汉宁窗系数 | 0.5 | $w(n) = 0.5(1 - \cos(\frac{2\pi n}{N-1}))$ | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值