stm32 --- ADC,DMA,多路,单次/连续转换(标准外设库)

今天回答一个朋友的问题吧,ADC如何使用DMA采集多通道模拟电压。

 

一. 写在前面

这个问题其实之前写过一些相关文章,原理我之前也有相关描述。如果想要彻底弄明白其原理,建议阅读《参考手册》、结合标准外设库来理解。

 

现在很多人习惯使用STM32CubeMX来直接生成初始化代码,如果没有掌握STM32CubeMX、HAL库,使用STM32CubeMX生成的代码,或许就不能满足你的应用。

 

同时,STM32CubeMX生成的代码,想要根据代码进一步了解其原理,其实很难

 

ADC转换一些基础原理,我这里就不过多描述了,请直接看下面标准外设库源码、及后面给的注释。

 

下面写2点:ADC软件单次触发转换,和连续转换。

 

 

二. ADC,DMA,单次触发转换

这里以ADC,使用DMA,通过软件单次触发转换为例。主要需注意几个相关参数即可。

 

1.GPIO配置

 

2.DMA配置

 

3.ADC配置

 

4.ADC单次触发转换

 

5.源代码

/* 静态变量 ------------------------------------------------------------------*/
static volatile uint16_t sADC_Buf[3];

/************************************************
函数名称 : ADC_GPIO_Configuration
功    能 : ADC引脚配置
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* 使能时钟 */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                      //模拟输入
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/************************************************
函数名称 : ADC_DMA_Configuration
功    能 : ADC DMA配置
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_DMA_Configuration(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  /* 使能时钟 */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

  /* 配置DMA */
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));//外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&sADC_Buf[0]);  //内存地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;            //传输方向:外设 -> 内存
  DMA_InitStructure.DMA_BufferSize = 3;                              //传输长度
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;   //外设递增:关闭
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;            //内存递增:打开
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                      //正常模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;              //优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
}

/************************************************
函数名称 : ADC_Configuration
功    能 : ADC参数配置
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_Configuration(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;

  /* 使能时钟 */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  /* ADC配置 */
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;                       //浏览模式(多通道)
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                //连续转化模式
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;             //数据右对齐
  ADC_InitStructure.ADC_NbrOfConversion = 3;                         //转换通道数
  ADC_Init(ADC1, &ADC_InitStructure);

  /* 通道配置 */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_3Cycles);

  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  ADC_DMACmd(ADC1, ENABLE);                                          //使能ADC的DMA功能
  ADC_Cmd(ADC1, ENABLE);                                             //使能ADC
}

/************************************************
函数名称 : ADC_Initializes
功    能 : ADC初始化
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_Initializes(void)
{
  ADC_GPIO_Configuration();
  ADC_DMA_Configuration();
  ADC_Configuration();
}

/************************************************
函数名称 : ADC_Get
功    能 : 转换
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_Get(void)
{
  DMA_Cmd(DMA2_Stream0, DISABLE);                                    //关闭DMA
                                                                     //内存地址
  DMA_MemoryTargetConfig(DMA2_Stream0, (uint32_t)sADC_Buf, DMA_Memory_0);
  DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);                       //清除标志位
  DMA_Cmd(DMA2_Stream0, ENABLE);                                     //使能DMA

  ADC_SoftwareStartConv(ADC1);                                       //启动转换

  while(RESET == DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0));   //等待转换完成

  //得到3条通道转换结果:sADC_Buf
  //进行相关换算,处理...
}

 

提示:以上源代码只为方便学习和理解,请结合实际应用修改、或增减代码。

 

 

三. ADC,DMA,连续转换

我这里写的连续,是ADC连续转换,同时,DMA循环存储。大部分配置和上面差不多,这种方式也用的比较多,写给大家。

 

1.DMA配置

 

2.ADC配置

 

3.源代码

 

/* 静态变量 ------------------------------------------------------------------*/
static volatile uint16_t sADC_Buf[3];

/************************************************
函数名称 : ADC_GPIO_Configuration
功    能 : ADC引脚配置
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* 使能时钟 */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                      //模拟输入
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/************************************************
函数名称 : ADC_DMA_Configuration
功    能 : ADC DMA配置
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_DMA_Configuration(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  /* 使能时钟 */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

  /* 配置DMA */
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));//外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&sADC_Buf[0]);  //内存地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;            //传输方向:外设 -> 内存
  DMA_InitStructure.DMA_BufferSize = 3;                              //传输长度
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;   //外设递增:关闭
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;            //内存递增:打开
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                    //循环模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;              //优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
}

/************************************************
函数名称 : ADC_Configuration
功    能 : ADC参数配置
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_Configuration(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;

  /* 使能时钟 */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  /* ADC配置 */
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;                       //浏览模式(多通道)
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                 //连续转化模式
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;             //数据右对齐
  ADC_InitStructure.ADC_NbrOfConversion = 3;                         //转换通道数
  ADC_Init(ADC1, &ADC_InitStructure);

  /* 通道配置 */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_3Cycles);

  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  ADC_DMACmd(ADC1, ENABLE);                                          //使能ADC的DMA功能
  ADC_Cmd(ADC1, ENABLE);                                             //使能ADC

  ADC_SoftwareStartConv(ADC1);                                       //启动转换
}

/************************************************
函数名称 : ADC_Initializes
功    能 : ADC初始化
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_Initializes(void)
{
  ADC_GPIO_Configuration();
  ADC_DMA_Configuration();
  ADC_Configuration();
}

/************************************************
函数名称 : ADC_Get
功    能 : 转换
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void ADC_Get(void)
{
  //得到3条通道转换结果:sADC_Buf
  //进行相关换算,处理...
}

 

这种方式比较简单,直接去读取转换结果就行。实际应用需要滤波,求平均之类的操作。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值