2021年电子设计竞赛A题 信号失真度测量装置 做题笔记

本文单片机主控采用的是野火霸天虎V2 STM32 F407ZGT6系列单片机。 

作者主要负责单片机主控部分,因此本文将记录我在做此题的具体过程,也便于以后查阅(UP本身也是小白,久了不用真的会忘😭)。由于做题需要一定时间,所以这篇笔记会每天更新一次。

 一、在STM32CubeMX进行基本参数配置

(1)RCC配置

(2)时钟树配置

(3)ADC+DMA配置

ADC的几个关键参数配置及其原因如下:

1、Scan Conversion Mode:DISABLE,因为这里ADC1只进行单通道转换;

2、External Trigger Conversion Source:Timer 2 Trigger Out Event,我们需要利用Timer 2 生成触发事件,通过TRGO Trigger Line控制ADC1以一个固定的采样频率去进行采样;

3、Continuous Conversion Mode:MUST BE DISABLE,because it is the TRGO Line that fires the conversion, otherwise the ADC performs conversions by its own without waiting the timer trigger;

4、DMA Continuous Requests:ENABLE,so that the DMA keep it's registers unchanged(to think more abstractly,regard this as all the working status of DMA,for example the Target Memory Address) and continue to work when the next ADC conversion sequence ends. If not,we must call the HAL_ADC_Stop_DMA() at the end of every conversion sequence,and then call the HAL_ADC_Start_DMA() again,otherwise the next conversion will simply not start.

5、DMA Request Mode:Normal,because we want to stop after N conversions are performed. If we want to endlessly perform N conversions,then set this field to be Circular,so that the DMA's register will be re-initialized after every N conversions are completed.

更多ADC、Timer、DMA工作模式配置讲解,详见《Mastering STM32 --2nd Edition》第12.2.6 ~ 12.2.8节。

(4)Timer定时器配置

(5)USART串口配置

二、代码编写与调试

(1)CMSIS DSP库函数简介

对 float32 FFT_Inputs[] 进行FFT运算:arm_rfft_fast_f32(const arm_rfft_fast_instance_f32* S,float32_t* p,float32_t* pOut,uint8_t* ifftFlag);

初始化arm_rfft_fast_instance_f32* S结构体:arm_rfft_fast_init_f32(arm_rfft_fast_instance_f32* S,uint16_t fftLen);

详细讲解见CMSIS DSP: Real_FFT Functions API

对复数数组float32 FFT_Outputs[] 取模:arm_cmplx_mag_f32 (const float32_t *pSrc, float32_t *pDst, uint32_t numSamples);

(2)main.c:

启动TIM2、DMA模式ADC1,当ADC1转化完4096个点后,进行FFT运算
/* USER CODE BEGIN PV */

uint8_t convCompleted = 0;
uint16_t convCounter = 0;
uint16_t ADC_Values[4096] = {0};
float32_t FFT_Inputs[4096] = {0};
float32_t FFT_Outputs[4096] = {0};
float32_t FFT_Results[4096] = {0};
arm_rfft_fast_instance_f32 S;

/* USER CODE END PV */

int main(void)
{
/* USER CODE BEGIN 1 */
    float32_t pResult;
	uint32_t pIndex;
/* USER CODE END 1 */
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();
    MX_TIM2_Init();
    MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
    arm_rfft_fast_init_f32(&S, 4096);
	HAL_TIM_Base_Start(&htim2);
	HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Values, 4096);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1){
        if(convCompleted == 1){
			for(int i = 0; i < 4096; i++){
				FFT_Inputs[i] = ADC_Values[i] * 3.3 / 4095.0;
			}
			
			arm_rfft_fast_f32(&S, FFT_Inputs, FFT_Outputs, 0);
			
			arm_cmplx_mag_f32(FFT_Outputs, FFT_Results, 4096);  //根据FFT原始输出的复数数组,取模计算出对应的实数数组,得到幅频响应
			for(int i = 0; i < 4096; i++){
				printf("%.4f, ", FFT_Results[i]);
			}
			
			printf("\r\n%d \r\n", sizeof(FFT_Outputs)/sizeof(FFT_Outputs[0]));
			
			for(int i = 0; i < 4096; i++){
				printf("%d, ", ADC_Values[i]);
			}
			
			convCompleted = 0;
		}
    /* USER CODE END WHILE */
  }
}

(3)stm32f4xx_it.c:

/* USER CODE BEGIN 1 */
extern uint8_t convCompleted;
extern uint16_t convCounter;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef*hadc) {
	convCompleted = 1;
}
/* USER CODE END 1 */

三、结果分析

以1MHz的ADC采样频率对100KHz正弦信号采样了4096个点,并将计算的FFT_Output[0:4096],FFT_Result[0:4096]通过UART串口发送,然后Python数据可视化后,可以看到结果如下:

目前FFT可以完成频率的粗测,但是误差仍较大,因为FFT分辨率仅达到1000 000/4096 = 244Hz,部分FFT计算结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值