STM32H743,基于LL库实现adc双重采样(ADC+DMA+TIM)

直接上代码:

/*
 * 双重采样要保证两个ADC的参数一致,双重采样的开始由主ADC控制,触发信号来自同一个触发源
 * 
 */
#define USE_ADC_WORK_MODE         1 /* 0表示独立模式,1表示双重模式 */
/*
 * 函数名称: Samp_TIM_Init
 * 函数说明: TIM4初始化,此定时器用于采样触发(采样率1M)
 * 输入参数: 无
 * 返回参数: 无
 */
static void Samp_TIM_Init(void)
{
	LL_TIM_InitTypeDef LL_TIM_Struct={0};
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
	
	LL_TIM_Struct.Prescaler=19;
	LL_TIM_Struct.Autoreload=9;
	LL_TIM_Struct.CounterMode=LL_TIM_COUNTERDIRECTION_UP;
	LL_TIM_Struct.ClockDivision=LL_TIM_CLOCKDIVISION_DIV1;
	LL_TIM_Init(TIM4, &LL_TIM_Struct);
	LL_TIM_EnableARRPreload(TIM4);
	LL_TIM_SetClockSource(TIM4, LL_TIM_CLOCKSOURCE_INTERNAL);
	LL_TIM_SetTriggerOutput(TIM4, LL_TIM_TRGO_UPDATE);
	LL_TIM_DisableCounter(TIM4);
}

/*
 * 函数名称: Samp_Adc_Init
 * 函数说明: 采样ADC初始化
 * 输入参数: buff_Addr1, 采样数据缓存地址1
 *           buff_Addr2, 采样数据缓存地址2
 *           trans_Num, DMA一次传输大小
 * 返回参数: 无
 */
void Samp_Adc_Init(uint32_t buff_Addr1, uint32_t buff_Addr2, uint32_t trans_Num)
{
	uint32_t wait_loop_index;
	LL_GPIO_InitTypeDef LL_GPIO_Struct={0};
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
	LL_DMA_InitTypeDef LL_DMA_Struct={0};	
	/* 使能相应时钟 */
	LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
	LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOC);	
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);
	__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);        /* 选择ADC的时钟源为per_ck->HSI=64M */
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
	/* 配置ADC1采样通道 */
	LL_GPIO_Struct.Pin=LL_GPIO_PIN_6;
	LL_GPIO_Struct.Mode=LL_GPIO_MODE_ANALOG;
	LL_GPIO_Struct.Pull=LL_GPIO_PULL_NO;
	LL_GPIO_Init(GPIOA, &LL_GPIO_Struct);	
#if USE_ADC_WORK_MODE	
	/* 配置ADC2采样通道 */	
	LL_GPIO_Struct.Pin=LL_GPIO_PIN_4;
	LL_GPIO_Struct.Mode=LL_GPIO_MODE_ANALOG;
	LL_GPIO_Struct.Pull=LL_GPIO_PULL_NO;
	LL_GPIO_Init(GPIOC, &LL_GPIO_Struct);		
#endif /* USE_ADC_WORK_MODE */
  /* DMA配置 */
  LL_DMA_Struct.PeriphRequest=LL_DMAMUX1_REQ_ADC1;
  LL_DMA_Struct.Direction=LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
  LL_DMA_Struct.Mode=LL_DMA_MODE_CIRCULAR;
  LL_DMA_Struct.Priority=LL_DMA_PRIORITY_MEDIUM;
  LL_DMA_Struct.NbData=trans_Num;
	
#if USE_ADC_WORK_MODE
  LL_DMA_Struct.PeriphOrM2MSrcAddress=(uint32_t)&ADC12_COMMON->CDR;
  LL_DMA_Struct.MemoryOrM2MDstAddress=(uint32_t)buff_Addr1;
  LL_DMA_Struct.PeriphOrM2MSrcDataSize=LL_DMA_PDATAALIGN_WORD;
  LL_DMA_Struct.MemoryOrM2MDstDataSize=LL_DMA_MDATAALIGN_WORD;
#else
  LL_DMA_Struct.PeriphOrM2MSrcAddress=(uint32_t)&ADC1->DR;
  LL_DMA_Struct.MemoryOrM2MDstAddress=(uint32_t)buff_Addr;
  LL_DMA_Struct.PeriphOrM2MSrcDataSize=LL_DMA_PDATAALIGN_HALFWORD;
  LL_DMA_Struct.MemoryOrM2MDstDataSize=LL_DMA_MDATAALIGN_HALFWORD;
#endif /* USE_ADC_WORK_MODE */

  LL_DMA_Struct.PeriphOrM2MSrcIncMode=LL_DMA_PERIPH_NOINCREMENT;
  LL_DMA_Struct.MemoryOrM2MDstIncMode=LL_DMA_MEMORY_INCREMENT;
  LL_DMA_Init(DMA1, LL_DMA_STREAM_0, &LL_DMA_Struct); 
	/* DMA双缓冲模式配置 */
	LL_DMA_SetMemory1Address(DMA1, LL_DMA_STREAM_0, buff_Addr1);
  LL_DMA_EnableDoubleBufferMode(DMA1, LL_DMA_STREAM_0);	
  /* 开启DMA传输完成中断 */
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_0);
	/* 配置中断优先级 */
  NVIC_SetPriority(DMA1_Stream0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
  NVIC_EnableIRQ(DMA1_Stream0_IRQn);
	LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_0);

	/* ADC1初始化 */
	/* 退出掉电模式 */
	LL_ADC_DisableDeepPowerDown(ADC1);
	/* 启动内部稳压器 */
	LL_ADC_EnableInternalRegulator(ADC1);
  /* 等待内部稳压器启动 */
  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
  while(wait_loop_index != 0)
  {
    wait_loop_index--;
  }  	
	/* 设置ADC分频系数 */
  ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV2;
#if USE_ADC_WORK_MODE
    /* 双重模式配置 */
	ADC_CommonInitStruct.Multimode=LL_ADC_MULTI_DUAL_REG_SIMULT;/* 仅常规同步模式 */
	ADC_CommonInitStruct.MultiDMATransfer=LL_ADC_MULTI_REG_DMA_RES_32_10B;/* 字传输 */
	ADC_CommonInitStruct.MultiTwoSamplingDelay=LL_ADC_MULTI_TWOSMP_DELAY_1CYCLE_5;
#endif /* USE_ADC_WORK_MODE */
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);	
	/* BOOST 位控制 */
	LL_ADC_SetBoostMode(ADC1, LL_ADC_BOOST_MODE_50MHZ);
	/* 采样率设置 */
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
  ADC_InitStruct.LeftBitShift=LL_ADC_LEFT_BIT_SHIFT_NONE;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  LL_ADC_Init(ADC1, &ADC_InitStruct);
	/* 启动校准 */
  LL_ADC_StartCalibration(ADC1, LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED);  
	/* 等待校准完成 */
	while(LL_ADC_IsCalibrationOnGoing(ADC1) != 0UL);		
	/* 规则采样参数配置 */
	ADC_REG_InitStruct.TriggerSource=LL_ADC_REG_TRIG_EXT_TIM4_TRGO;
	ADC_REG_InitStruct.DataTransferMode=LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
	ADC_REG_InitStruct.ContinuousMode=LL_ADC_REG_CONV_SINGLE;
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;	
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
  LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_RISING);
	/* 配置规则通道 */
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_3);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SINGLE_ENDED);
	/* 通道预选设置,这个很关键 */
  ADC1->PCSEL |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_3) & 0x1FUL));  	

#if USE_ADC_WORK_MODE
	/* ADC2初始化 */
	/* 退出掉电模式 */
	LL_ADC_DisableDeepPowerDown(ADC2);
	/* 启动内部稳压器 */
	LL_ADC_EnableInternalRegulator(ADC2);
  /* 等待内部稳压器启动 */
  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
  while(wait_loop_index != 0)
  {
    wait_loop_index--;
  }  	
	/* BOOST 位控制 */
	LL_ADC_SetBoostMode(ADC2, LL_ADC_BOOST_MODE_50MHZ);
	/* 采样率设置 */
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
  ADC_InitStruct.LeftBitShift=LL_ADC_LEFT_BIT_SHIFT_NONE;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  LL_ADC_Init(ADC2, &ADC_InitStruct);
	/* 启动校准 */
  LL_ADC_StartCalibration(ADC2, LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED);  
	/* 等待校准完成 */
	while(LL_ADC_IsCalibrationOnGoing(ADC2) != 0UL);		
	/* 规则采样参数配置 */
	ADC_REG_InitStruct.TriggerSource=LL_ADC_REG_TRIG_EXT_TIM4_TRGO;
	ADC_REG_InitStruct.DataTransferMode=LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
	ADC_REG_InitStruct.ContinuousMode=LL_ADC_REG_CONV_SINGLE;
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;	
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  LL_ADC_REG_Init(ADC2, &ADC_REG_InitStruct);
  LL_ADC_REG_SetTriggerEdge(ADC2, LL_ADC_REG_TRIG_EXT_RISING);
	/* 配置规则通道 */
  LL_ADC_REG_SetSequencerRanks(ADC2, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_4);
  LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC2, LL_ADC_CHANNEL_4, LL_ADC_SINGLE_ENDED);
	/* 通道预选设置,这个很关键 */
  ADC2->PCSEL |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_4) & 0x1FUL)); 
#endif /* USE_ADC_WORK_MODE */

	/* 初始化采样定时器 */
	Samp_TIM_Init();
}

/*
 * 函数名称: Start_Sample
 * 函数说明: 开始采样
 * 输入参数: 无
 * 返回参数: 无
 */
void Start_Sample(void)
{
	LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_0);
  LL_ADC_Enable(ADC1);
	while(LL_ADC_IsActiveFlag_ADRDY(ADC1) != SET);
	LL_ADC_REG_StartConversion(ADC1);
	
#if USE_ADC_WORK_MODE
  LL_ADC_Enable(ADC2);
	while(LL_ADC_IsActiveFlag_ADRDY(ADC2) != SET);
	LL_ADC_REG_StartConversion(ADC2);	
#endif /* USE_ADC_WORK_MODE */
	
	LL_TIM_EnableCounter(TIM4);
}

/*
 * 函数名称: Stop_Sample
 * 函数说明: 停止采样
 * 输入参数: 无
 * 返回参数: 无
 */
void Stop_Sample(void)
{
	LL_TIM_DisableCounter(TIM4);
	LL_ADC_REG_StopConversion(ADC1);/* 待测试 */
	while(LL_ADC_REG_IsConversionOngoing(ADC1) != 0);
	LL_ADC_Disable(ADC1);
//	LL_ADC_EnableDeepPowerDown(ADC1);/* 完全关闭ADC,再次开启需要重新初始化ADC */
#if USE_ADC_WORK_MODE
	LL_ADC_REG_StopConversion(ADC2);
	while(LL_ADC_REG_IsConversionOngoing(ADC2) != 0);
	LL_ADC_Disable(ADC2);
//	LL_ADC_EnableDeepPowerDown(ADC2);/* 完全关闭ADC,再次开启需要重新初始化ADC */
#endif /* USE_ADC_WORK_MODE */
	LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_0);
	LL_DMA_ClearFlag_TC0(DMA1);
}

/*
 * 函数名称: DMA1_Stream0_IRQHandler
 * 函数说明: DMA1_Stream0中断服务函数
 * 输入参数: 无
 * 返回参数: 无
 */
void DMA1_Stream0_IRQHandler(void)
{
	if(LL_DMA_IsActiveFlag_TC0(DMA1) != RESET)
	{
		LL_DMA_ClearFlag_TC0(DMA1);
		LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_1);
	}
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值