stm32 嵌入式开发 中三重ADC交替模式采集数据总结

发布时间:2024-07-29  

// ADC 宏定义


#ifndef __BSP_ADC_H

#define    __BSP_ADC_H


#include "stm32f4xx.h"


// ADC GPIO 宏定义

#define RHEOSTAT_ADC_GPIO_PORT    GPIOC

#define RHEOSTAT_ADC_GPIO_PIN     GPIO_Pin_3

#define RHEOSTAT_ADC_GPIO_CLK     RCC_AHB1Periph_GPIOC


// ADC 序号宏定义

#define RHEOSTAT_ADC1             ADC1

#define RHEOSTAT_ADC1_CLK         RCC_APB2Periph_ADC1

#define RHEOSTAT_ADC2             ADC2

#define RHEOSTAT_ADC2_CLK         RCC_APB2Periph_ADC2

#define RHEOSTAT_ADC3             ADC3

#define RHEOSTAT_ADC3_CLK         RCC_APB2Periph_ADC3

#define RHEOSTAT_ADC_CHANNEL      ADC_Channel_13

// ADC CDR寄存器宏定义,ADC转换后的数字值则存放在这里

#define RHEOSTAT_ADC_CDR_ADDR    ((uint32_t)0x40012308)


// ADC DMA 通道宏定义,这里我们使用DMA传输

#define RHEOSTAT_ADC_DMA_CLK      RCC_AHB1Periph_DMA2

#define RHEOSTAT_ADC_DMA_CHANNEL  DMA_Channel_0

#define RHEOSTAT_ADC_DMA_STREAM   DMA2_Stream0


//#define RHEOSTAT_ADC_DR_ADDR                    ((u32)ADC3 + 0X4C)//模数转



void Rheostat_Init(void);


#endif /* __BSP_ADC_H */


// ADC 初始化


#include "./adc/bsp_adc.h"




__IO uint32_t ADC_ConvertedValue[3];


static void Rheostat_ADC_GPIO_Config(void)

{

        GPIO_InitTypeDef GPIO_InitStructure;

    

    // 使能 GPIO 时钟

    RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);

        

    // 配置 IO

    GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉

    GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);        

}


static void Rheostat_ADC_Mode_Config(void)

{

    DMA_InitTypeDef DMA_InitStructure;

    ADC_InitTypeDef ADC_InitStructure;

  ADC_CommonInitTypeDef ADC_CommonInitStructure;

    

  // ------------------DMA Init 结构体参数 初始化--------------------------

  // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的

  // 开启DMA时钟

  RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_DMA_CLK, ENABLE); 

    // 外设基址为:ADC 数据寄存器地址

    DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_CDR_ADDR;    

  // 存储器地址,实际上就是一个内部SRAM的变量    

    DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue;  

  // 数据传输方向为外设到存储器    

    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_Word; 

  //    存储器数据大小也为半字,跟外设数据大小相同

    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Word;    

    // 循环传输模式

    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  // 禁止DMA FIFO    ,使用直连模式

  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  

  // FIFO 大小,FIFO模式禁止时,这个不用配置    

  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  

    // 选择 DMA 通道,通道存在于流中

  DMA_InitStructure.DMA_Channel = RHEOSTAT_ADC_DMA_CHANNEL; 

  //初始化DMA流,流相当于一个大的管道,管道里面有很多通道

    DMA_Init(RHEOSTAT_ADC_DMA_STREAM, &DMA_InitStructure);

    // 使能DMA流

  DMA_Cmd(RHEOSTAT_ADC_DMA_STREAM, ENABLE);

    

    // 开启ADC时钟

    RCC_APB2PeriphClockCmd(RHEOSTAT_ADC1_CLK , ENABLE);

  RCC_APB2PeriphClockCmd(RHEOSTAT_ADC2_CLK , ENABLE);

    RCC_APB2PeriphClockCmd(RHEOSTAT_ADC3_CLK , ENABLE);

    

  // -------------------ADC common 结构体 参数 初始化--------------------------

    ADC_StructInit(&ADC_InitStructure);

    // 独立ADC模式

  ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;

  // 时钟为fpclk x分频    

  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;

  // 禁止DMA直接访问模式    

  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;

  // 采样时间间隔    

  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;  

  ADC_CommonInit(&ADC_CommonInitStructure);

    

  // -------------------ADC Init 结构体 参数 初始化--------------------------

  // ADC 分辨率

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

  // 禁止扫描模式,多通道采集才需要    

  ADC_InitStructure.ADC_ScanConvMode = DISABLE; 

  // 连续转换    

  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;

  //转换通道 1个

  ADC_InitStructure.ADC_NbrOfConversion = 1; 

    

  ADC_Init(RHEOSTAT_ADC1, &ADC_InitStructure);

  //---------------------------------------------------------------------------

    

   // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期

  ADC_RegularChannelConfig(RHEOSTAT_ADC1, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_3Cycles);   

  //---------------------------------------------------------------------------

    

    ADC_Init(RHEOSTAT_ADC2, &ADC_InitStructure);

  // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期

  ADC_RegularChannelConfig(RHEOSTAT_ADC2, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_3Cycles);   

  //---------------------------------------------------------------------------

    

    ADC_Init(RHEOSTAT_ADC3, &ADC_InitStructure);

  // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期

  ADC_RegularChannelConfig(RHEOSTAT_ADC3, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_3Cycles); 

    


  // 使能DMA请求 after last transfer (multi-ADC mode)

  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

  // 使能ADC DMA

  ADC_DMACmd(RHEOSTAT_ADC1, ENABLE);

    

  // 使能ADC

  ADC_Cmd(RHEOSTAT_ADC1, ENABLE);  

  ADC_Cmd(RHEOSTAT_ADC2, ENABLE);  

  ADC_Cmd(RHEOSTAT_ADC3, ENABLE);  

  

  //开始adc转换,软件触发

  ADC_SoftwareStartConv(RHEOSTAT_ADC1);

//  ADC_SoftwareStartConv(RHEOSTAT_ADC2);

//  ADC_SoftwareStartConv(RHEOSTAT_ADC3);

}




void Rheostat_Init(void)

{

    Rheostat_ADC_GPIO_Config();

    Rheostat_ADC_Mode_Config();

}


// 主函数

  

#include "stm32f4xx.h"

#include "./usart/bsp_debug_usart.h"

#include "./adc/bsp_adc.h"



// ADC1转换的电压值通过MDA方式传到SRAM

extern __IO uint32_t ADC_ConvertedValue[3];


// 局部变量,用于保存转换计算后的电压值      

float ADC_ConvertedValueLocal[3]; 


static void Delay(__IO uint32_t nCount)     //简单的延时函数

{

    for(; nCount != 0; nCount--);

}


/**

  * @brief  主函数

  * @param  无

  * @retval 无

  */

int main(void)

{    

  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/

  Debug_USART_Config();

    Rheostat_Init();    

    printf("RHEOSTAT_ADC_DR_ADDR 的地址 %Xn",RHEOSTAT_ADC_DR_ADDR);

  while (1)

  {

    Delay(0xffffee);  

    

    ADC_ConvertedValueLocal[0] =(float)((uint16_t)ADC_ConvertedValue[0]*3.3/4096); 

    ADC_ConvertedValueLocal[1] =(float)((uint16_t)ADC_ConvertedValue[1]*3.3/4096);

    ADC_ConvertedValueLocal[2] =(float)((uint16_t)ADC_ConvertedValue[2]*3.3/4096);

    

    printf("rn The current AD value = 0x%08X rn", ADC_ConvertedValue[0]); 

    printf("rn The current AD value = 0x%08X rn", ADC_ConvertedValue[1]); 

    printf("rn The current AD value = 0x%08X rn", ADC_ConvertedValue[2]); 

    

    printf("rn The current ADC1 value = %f V rn",ADC_ConvertedValueLocal[0]); 

    printf("rn The current ADC2 value = %f V rn",ADC_ConvertedValueLocal[1]);

    printf("rn The current ADC3 value = %f V rn",ADC_ConvertedValueLocal[2]);

  }

}


 

 

掉坑提示:1、三个 ADC 共用一个通道 与数据流 :通道0、数据流0,是不是很奇怪

     2、DMA数据的存储地址为 通用ADC专用地址 为((uint32_t)0x40012308) ADC_CDR

     3、DAM传输数据大小为一个字即4个字节,分别为ADC1/2/3的高或低16位组合,因为采样的是同一个通道所以数据值相同,没有应为数据传输先后的影响

     4、ADC设置为三重ADC交替模式

      5、 // 禁止DMA直接访问模式    

        ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;

      查看数据手册:

                  

 

     6、三个ADC 同时设置成通道转换顺序为1,影响不大

    7、 三重模式只需使能 ADC1 的 DMA 通道,ADC软件触发三个需要同时使能。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>