STM32H743VIT6配置ADC为1M采样率

外设总结

1M的采样率,对于32而言已经很高了,所以这边我们必然是需要使用DMA的,除此之外,我们选用定时器1作为触发源,方便随时修改采样频率的同时,也更为精准的设置采样频率为1M。

配置过程

首先是定时器的初始化过程。

static void ADC_TIME_Config(void){
	TIM_HandleTypeDef TIM_HandleADC_TRIG = {0};
	TIM_OC_InitTypeDef TIM_OC_InitADC_TRIG = {0};
	
	HAL_TIM_Base_DeInit(&TIM_HandleADC_TRIG);
	TIM_HandleADC_TRIG.Instance = TIM1;
	TIM_HandleADC_TRIG.Init.Period = ADC_DMA_PWM_PERIODVALUE - 1;
	TIM_HandleADC_TRIG.Init.Prescaler = 0;
	TIM_HandleADC_TRIG.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM_HandleADC_TRIG.Init.RepetitionCounter = 0;
	HAL_TIM_Base_Init(&TIM_HandleADC_TRIG);
	
	TIM_OC_InitADC_TRIG.OCMode = TIM_OCMODE_PWM1;
	TIM_OC_InitADC_TRIG.OCPolarity = TIM_OCPOLARITY_LOW;
	TIM_OC_InitADC_TRIG.Pulse = ADC_DMA_PWM_PERIODVALUE / 2;
	if(HAL_TIM_OC_ConfigChannel(&TIM_HandleADC_TRIG, &TIM_OC_InitADC_TRIG, TIM_CHANNEL_1) != HAL_OK)
		while(1);
	if(HAL_TIM_OC_Start(&TIM_HandleADC_TRIG, TIM_CHANNEL_1) != HAL_OK)
		while(1);
}

上面的重装载值和分频系数大伙自行根据自己工程的时钟频率修改即可,配置成1MHz即可。这边如果有朋友需要将输出比较的PWM引出到外部引脚上,可以在回调函数中加上下面这段程序,当然,不需要的话也可以不加,不影响触发ADC采集。

	if(htim->Instance == TIM1){
		__HAL_RCC_TIM1_CLK_ENABLE();
		__HAL_RCC_GPIOE_CLK_ENABLE();
		
		GPIO_Initure.Pin = GPIO_PIN_9;           	//PB0
		GPIO_Initure.Mode = GPIO_MODE_AF_PP;  	//复用推完输出
		GPIO_Initure.Pull = GPIO_PULLUP;          //上拉
		GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
		GPIO_Initure.Alternate = GPIO_AF1_TIM1;	
		HAL_GPIO_Init(GPIOE,&GPIO_Initure);
	}

然后就是重头戏,ADC+DMA配置代码。

void hy_ADC_DMA_Init(void){
	ADC_Config_Choose |= 0x02;
	
	DMA_HandleTypeDef DMA_HandleADC_Str = {0};
	ADC_ChannelConfTypeDef ADC_ChannelConfADCDMA_Str = {0};
	
	__HAL_RCC_DMA1_CLK_ENABLE();
	HAL_DMA_DeInit(&DMA_HandleADC_Str);
	DMA_HandleADC_Str.Instance = DMA1_Stream1;
	DMA_HandleADC_Str.Init.Request = DMA_REQUEST_ADC1;
	DMA_HandleADC_Str.Init.Direction = DMA_PERIPH_TO_MEMORY;
	DMA_HandleADC_Str.Init.Mode = DMA_CIRCULAR;
	DMA_HandleADC_Str.Init.MemInc = DMA_MINC_ENABLE;
	DMA_HandleADC_Str.Init.PeriphInc = DMA_PINC_DISABLE;
	DMA_HandleADC_Str.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
	DMA_HandleADC_Str.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
	DMA_HandleADC_Str.Init.Priority = DMA_PRIORITY_LOW;		//优先级低
	
	DMA_HandleADC_Str.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
	DMA_HandleADC_Str.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
	DMA_HandleADC_Str.Init.MemBurst = DMA_MBURST_SINGLE;
	DMA_HandleADC_Str.Init.PeriphBurst = DMA_PBURST_SINGLE;
	
	if(HAL_DMA_Init(&DMA_HandleADC_Str) != HAL_OK)
		while(1);
	
	HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 2, 0);
	HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
	
	__HAL_LINKDMA(&ADC_HandleDMA_Str, DMA_Handle, DMA_HandleADC_Str);
	
	HAL_ADC_DeInit(&ADC_HandleDMA_Str);
	ADC_HandleDMA_Str.Instance = ADC1;
	ADC_HandleDMA_Str.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
	ADC_HandleDMA_Str.Init.Resolution = ADC_RESOLUTION_16B;
	ADC_HandleDMA_Str.Init.ScanConvMode = ADC_SCAN_DISABLE;
	ADC_HandleDMA_Str.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	ADC_HandleDMA_Str.Init.LowPowerAutoWait = DISABLE;
	ADC_HandleDMA_Str.Init.ContinuousConvMode = DISABLE;
	ADC_HandleDMA_Str.Init.NbrOfConversion = 1;
	ADC_HandleDMA_Str.Init.DiscontinuousConvMode = DISABLE;
	ADC_HandleDMA_Str.Init.NbrOfDiscConversion = 1;
	ADC_HandleDMA_Str.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1;
	ADC_HandleDMA_Str.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
	ADC_HandleDMA_Str.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR; /* DMA 循环模式接收 ADC转换的数据 */
	ADC_HandleDMA_Str.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
	ADC_HandleDMA_Str.Init.OversamplingMode = DISABLE;
	
	if(HAL_ADC_Init(&ADC_HandleDMA_Str) != HAL_OK)
		while(1);
	
	HAL_ADCEx_Calibration_Start(&ADC_HandleDMA_Str, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
	
	ADC_ChannelConfADCDMA_Str.Channel = ADC_CHANNEL_3;
	ADC_ChannelConfADCDMA_Str.Offset = 0;
	ADC_ChannelConfADCDMA_Str.Rank = ADC_REGULAR_RANK_1;
	ADC_ChannelConfADCDMA_Str.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
	ADC_ChannelConfADCDMA_Str.SingleDiff = ADC_SINGLE_ENDED;
	ADC_ChannelConfADCDMA_Str.OffsetNumber = ADC_OFFSET_NONE;
	
	if(HAL_ADC_ConfigChannel(&ADC_HandleDMA_Str, &ADC_ChannelConfADCDMA_Str) != HAL_OK)
		while(1);
	
	ADC_TIME_Config();
	
	if(HAL_ADC_Start_DMA(&ADC_HandleDMA_Str, (uint32_t *)adc_dma_read_data, 1040) != HAL_OK)
		while(1);
}

可以看出,上面我设置的是1040个数据,也就是说传输完成1040个数据之后我们会进入到DMA中断中,下面贴上DMA中断代码。

void DMA1_Stream1_IRQHandler(void){
	static uint8_t dma_test_data[1] = {0};
	/* 传输完成中断 */
	if((DMA1->LISR & DMA_FLAG_TCIF1_5) != RESET){
		DMA1->LIFCR = DMA_FLAG_TCIF1_5;
		dma_test_data[0]++;
		if(dma_test_data[0] == 5){
			HAL_NVIC_DisableIRQ(DMA1_Stream1_IRQn);
			ADC_Disable(&ADC_HandleDMA_Str);
			collect_flag = 1;
		}
	}
	/* 半传输完成中断 */
	if((DMA1->LISR & DMA_FLAG_HTIF1_5) != RESET){
		DMA1->LIFCR = DMA_FLAG_HTIF1_5;
		
	}
	/* 传输错误中断 */
	if((DMA1->LISR & DMA_FLAG_TEIF1_5) != RESET){
		DMA1->LIFCR = DMA_FLAG_TEIF1_5;
		
	}
	/* 直接模式错误中断 */
	if((DMA1->LISR & DMA_FLAG_DMEIF1_5) != RESET){
		DMA1->LIFCR = DMA_FLAG_DMEIF1_5;
		
	}
}

其他中断我们暂时不需要写中断处理,清除标志位即可,传输完成中断,我们可以在里边关闭ADC采集和DMA中断,然后设置一个标志位,标志位被置位后我们在主函数中对数据进行处理。

	if(collect_flag){
		collect_flag = 0;
		for(i = 0; i < 1024; i++){
			printf("data is:%d \n", adc_dma_read_data[i]);
			delay_ms(1);
		}
	}

以上就是配置的全部过程。

问题所在

经过实测,1MHz的采样率是没问题的,我用这个频率去采集50KHz以及100KHz的正弦波是没有问题的,波形如下所示:
在这里插入图片描述
在这里插入图片描述
上面的波形看出,采集效果还是ok的,除开100k的时候可能是外界干扰的原因造成波形失真,这个大伙加上滤波电路之后或者软件再滤个波即可,但是当我把输入信号设置成10k之后,发现波形如下所示:
在这里插入图片描述
没错,1MHz采集10KHz的正弦波,波形失真,啥也不是。。。对此本人也是感到比较奇怪,当我把采样频率降为100k之后,波形就正常了,对此,有知道的朋友欢迎在评论区指出,谢谢。

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值