STM32L476多通道TIM+DMA+ADC采样(LL库)

本代码适合定时采集N个点然后处理的场合,比如定时采集电池电压,每次采集64次采集完后计算64次平均值。本代码已经用于项目,本代码ADC的启动和停止对于功耗控制较为严格的场合特别适用。

/*
 * 函数名称: Samp_TIM_Init
 * 函数说明: TIM4初始化,此定时器用于采样触发(采样率可以设置,这里设置的是1K)
 * 输入参数: 无
 * 返回参数: 无
 */
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=79;
	LL_TIM_Struct.Autoreload=999;  /* 1KHz */
	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);
}
/*
 * 函数名称: DMA_Channel1_Init
 * 函数说明: DMA_Channel1初始化,用于ADC采样数据传输
 * 输入参数: srcaddr, 源存储器地址
 *           destaddr, 目的存储器地址
 *           count, DMA一次传输大小
 * 返回参数: 无
 */
void DMA_Channel1_Init(uint32_t srcaddr, uint32_t destaddr, uint16_t count)
{
	LL_DMA_InitTypeDef LL_DMA_Struct;
	
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
	
	LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_1);
  LL_DMA_Struct.PeriphRequest=LL_DMA_REQUEST_0;
  LL_DMA_Struct.Direction=LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
  LL_DMA_Struct.Mode=LL_DMA_MODE_NORMAL;  /* 单次 */ 
  LL_DMA_Struct.Priority=LL_DMA_PRIORITY_HIGH;
  LL_DMA_Struct.NbData=count;
  LL_DMA_Struct.PeriphOrM2MSrcAddress=(uint32_t)srcaddr;
  LL_DMA_Struct.MemoryOrM2MDstAddress=(uint32_t)destaddr;
  LL_DMA_Struct.PeriphOrM2MSrcDataSize=LL_DMA_PDATAALIGN_HALFWORD;
  LL_DMA_Struct.MemoryOrM2MDstDataSize=LL_DMA_MDATAALIGN_HALFWORD;
  LL_DMA_Struct.PeriphOrM2MSrcIncMode=LL_DMA_PERIPH_NOINCREMENT;
  LL_DMA_Struct.MemoryOrM2MDstIncMode=LL_DMA_MEMORY_INCREMENT;
  LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &LL_DMA_Struct);
 	
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
  NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), SAMPLE_PRIORITY, 0));
  NVIC_EnableIRQ(DMA1_Channel1_IRQn);  
  
  LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
 
}

/*
 * 函数名称: Adc1_CH_Init
 * 函数说明: ADC通道配置
 * 输入参数: 无
 * 返回参数: 无
 */
void Adc1_CH_Init(void)
{
	uint32_t wait_loop_index;
	LL_GPIO_InitTypeDef GPIO_InitStruct={0};
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
	
	/* 使能相应时钟 */
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);  
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC);
	LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK);        /* 选择ADC的时钟源为sysclk->80M */	
	
	/* 配置ADC1采样通道 */
  /* 
      PA4->CH9 -> 电流
      PA5->CH10-> 导线温度
      PA7->CH12-> 太阳能电压
      PC4->CH13-> CT电压
      PC5->CH14-> 电池电压
   */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_4|LL_GPIO_PIN_5|LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_4|LL_GPIO_PIN_5;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  LL_GPIO_EnablePinAnalogControl(GPIOA, LL_GPIO_PIN_4|LL_GPIO_PIN_5|LL_GPIO_PIN_7);
  LL_GPIO_EnablePinAnalogControl(GPIOC, LL_GPIO_PIN_4|LL_GPIO_PIN_5);
  
	/* ADC1初始化 */
	/* 设置ADC分频系数 */
  ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;  
  ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV4; /* 将ADC内核时钟频率设置为20M */
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);	
  
	/* 采样率设置 */
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  LL_ADC_Init(ADC1, &ADC_InitStruct);

	/* 规则采样参数配置 */
	ADC_REG_InitStruct.TriggerSource=LL_ADC_REG_TRIG_EXT_TIM4_TRGO; /* 定时器4触发采样 */
	ADC_REG_InitStruct.DMATransfer=LL_ADC_REG_DMA_TRANSFER_LIMITED; /* DMA单次模式 */
	ADC_REG_InitStruct.ContinuousMode=LL_ADC_REG_CONV_SINGLE;       /* 单次转换模式 */
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_5RANKS;
  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_9);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_9, LL_ADC_SAMPLINGTIME_92CYCLES_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_9, LL_ADC_SINGLE_ENDED);

  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_10);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_10, LL_ADC_SAMPLINGTIME_92CYCLES_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_10, LL_ADC_SINGLE_ENDED);

  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_12);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_12, LL_ADC_SAMPLINGTIME_92CYCLES_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_12, LL_ADC_SINGLE_ENDED);

  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_4, LL_ADC_CHANNEL_13);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_13, LL_ADC_SAMPLINGTIME_92CYCLES_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_13, LL_ADC_SINGLE_ENDED);

  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_5, LL_ADC_CHANNEL_14);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_14, LL_ADC_SAMPLINGTIME_92CYCLES_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_14, LL_ADC_SINGLE_ENDED);

/* 采样频率设置 */
	Samp_TIM_Init();
/* DMA配置 */	
  DMA_Channel1_Init((uint32_t)&ADC1->DR, (uint32_t)Device.buff, SAMPLE_NUM);

  /* 退出掉电模式 */
  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 */
  LL_ADC_StartCalibration(ADC1, LL_ADC_SINGLE_ENDED); 
  /* 等待校准完成 */
  while (LL_ADC_IsCalibrationOnGoing(ADC1) != 0)
  {
  }
  /* 读取校准系数并保存,省的下次启动时需要花费很多时间去校准 */
  Device.calfact=LL_ADC_GetCalibrationFactor(ADC1, LL_ADC_SINGLE_ENDED);
  /* 校准完成之后需要等待一段时间才能使能ADC */
  wait_loop_index = ((LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES * 32) >> 1);
  while(wait_loop_index != 0)
  {
    wait_loop_index--;
  }
  /* 进入深度掉电模式 */
  LL_ADC_EnableDeepPowerDown(ADC1);
  LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_DMA1);  
	LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_ADC);
	LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM4);  
}

/*
 * 函数名称: ADC1_Sample_Start
 * 函数说明: 开始ADC1采样
 * 输入参数: 无
 * 返回参数: 无
 */
void ADC1_Sample_Start(void)
{
  uint32_t wait_loop_index;
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);  
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC);
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
  /* 退出掉电模式 */
  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 */
  LL_ADC_Enable(ADC1);
  /* 等待ADC使能 */
	while(LL_ADC_IsActiveFlag_ADRDY(ADC1) != SET)
  {
  }
  /* 写入初始化时保存的校准系数 */
  LL_ADC_SetCalibrationFactor(ADC1, LL_ADC_SINGLE_ENDED, Device.calfact);
  LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, SAMPLE_NUM);
  LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);  
	LL_TIM_EnableCounter(TIM4);  
	LL_ADC_REG_StartConversion(ADC1);
}

/*
 * 函数名称: ADC1_Sample_Stop
 * 函数说明: 停止ADC1采样
 * 输入参数: 无
 * 返回参数: 无
 */
void ADC1_Sample_Stop(void)
{
	LL_TIM_DisableCounter(TIM4);
  /* 停止转换 */
	LL_ADC_REG_StopConversion(ADC1);
	while(LL_ADC_REG_IsConversionOngoing(ADC1) != RESET)
  {
  }
  /* 失能ADC */
	LL_ADC_Disable(ADC1);
	while(LL_ADC_IsEnabled(ADC1) != RESET)
  {
  }
  /* 失能DMA通道 */
  LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
  /* 进入深度掉电模式 */
  LL_ADC_EnableDeepPowerDown(ADC1);
  LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_DMA1);  
	LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_ADC);
	LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM4);  
}


/**
  * @brief  This function handles DMA1_Channel1 Handler, for Sample.
  * @param  None
  * @retval None
  */
void DMA1_Channel1_IRQHandler(void)
{
  if(LL_DMA_IsActiveFlag_TC1(DMA1) != RESET)
  {
    LL_DMA_ClearFlag_TC1(DMA1);
    Device.samp_flag=1; /* 采样完成了,准备处理数据了 */
  }
}

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103是一款具有多通道ADCTIMDMA和FFT功能的微控制器。 首先,多通道ADC允许我们同时采集多个不同通道的模拟信号。这对于需要同时监测多个传感器或信号源的应用非常有用。通过配置ADC的多个通道,并设置相应的采样速率和分辨率,可以轻松实现高效的数据采集。 其次,TIM(定时器)模块允许我们生成精确的时间基准。在实时系统和定时器应用中,我们可以配置TIM来实现各种定时和计时功能。通过设置预分频器、计数器和比较器,我们可以准确地生成周期性的、定时的或脉冲宽度可变的信号。这对于控制和调度其他外设非常有用。 接下来,DMA(直接内存访问)控制器允许我们实现高速数据传输,而不需要CPU的干预。通过配置DMA通道并定义源和目标的地址、传输长度和传输方向,我们可以实现高效的数据传输操作。这对于处理大量数据、高速数据流或实时响应的应用非常有用。 最后,FFT(快速傅里叶变换)是一种用于信号处理和频谱分析的重要算法。通过使用STM32F103的FFT,我们可以对采集到的模拟信号进行频谱分析,以提取信号的频率和幅度特征。这对于音频处理、通信系统、传感器数据分析等应用非常有用。 总之,STM32F103的多通道ADCTIMDMA和FFT功能为我们提供了丰富的数据采集、定时、数据传输和信号处理能力,使得我们可以设计出高度灵活、高效的嵌入式系统。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值