ADC/DMA_ADC/IT_ADC
  pbfHt7yP3Hym 2023年11月12日 60 0

STM32的ADC是12位的,且采样时钟速度不能超过14M.

单独使用AD:

1:初始化相关GPIO,(看手册的ADC引脚配置)

2:初始化ADC

3;配置采样时钟

函数:RCC_ADCCLKConfig(RCC_PCLK2_Div8);//采样时钟 最大14M时钟

4:ADC通道选择

函数:ADC_RegularChannelConfig();ADC几/通道几/转换顺序/采样频率

5:ADC_CMD

6:进行ADC效准

 ADC_ResetCalibration(ADC1);//初始化效准寄存器,ADC效验初始化

   while(ADC_GetResetCalibrationStatus(ADC1));//是否效验初始化完成

   ADC_StartCalibration(ADC1);//开始效准

   while(ADC_GetCalibrationStatus(ADC1));//效准完成    手册有描述  

7:开启软件转换

 ADC_SoftwareStartConvCmd(ADC1,ENABLE);//不要 ADC_SoftwareStartInjectedConvCmd这个函数以为是启动函数哇,

GPIO初始化:

static void ADC_GPIOC_INIT(void)

{   GPIO_InitTypeDef ADC1_GPIOC_InitStruct;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

   ADC1_GPIOC_InitStruct.GPIO_Mode=GPIO_Mode_AIN;

   ADC1_GPIOC_InitStruct.GPIO_Pin|=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;

   ADC1_GPIOC_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;

   GPIO_Init(GPIOC,&ADC1_GPIOC_InitStruct);

}

ADC初始化:

static  void adc1_init(void)

{

   ADC_InitTypeDef ADC1_InitStruct;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC外设时钟

 ADC1_InitStruct.ADC_ContinuousConvMode=ENABLE; //是否连续转换  就是时间到了就更新新的数据不靠软件在去触发

   ADC1_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐  

 ADC1_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //触发源选择 为软件  

   ADC1_InitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式1 很多模式看手册描述 这里是独立

   ADC1_InitStruct.ADC_NbrOfChannel=3;//几个通道

   ADC1_InitStruct.ADC_ScanConvMode=ENABLE;//通道扫描模式一个一个去采 采集完后是不是去下一个通道采,一般用于多通道

   ADC_Init(ADC1, &ADC1_InitStruct);//初始化结构体

   RCC_ADCCLKConfig(RCC_PCLK2_Div8);//采样时钟 最大14M时钟

   ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_55Cycles5); //选择采集通道,转换顺序1,和采样时钟

   ADC_RegularChannelConfig(ADC1,ADC_Channel_12,2,ADC_SampleTime_55Cycles5);

   ADC_RegularChannelConfig(ADC1,ADC_Channel_13,3,ADC_SampleTime_55Cycles5);

  ADC_DMACmd(ADC1, ENABLE);//开启DMA  

//  ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);

   ADC_Cmd(ADC1,ENABLE);//开启ADC

 //也可以开中断 DMA 但是ADC的EOC的标志位是要把通道转完了就产生中断 用DMA搬运好多了

   ADC_ResetCalibration(ADC1);//初始化效准寄存器,ADC效验初始化

   while(ADC_GetResetCalibrationStatus(ADC1));//是否效验初始化完成

   ADC_StartCalibration(ADC1);//开始效准

   while(ADC_GetCalibrationStatus(ADC1));//效准完成    手册有描述  

 ADC_SoftwareStartConvCmd(ADC1,ENABLE);//不要 ADC_SoftwareStartInjectedConvCmd这个函数以为是启动函数哇,

 //要多通道必须是中断或DMA直接用会3个乱掉

}

ADC_SoftwareStartConvCmd启动ADC转换:

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);可以获取ADC的值

中断就判断EOC位;


//static void nvic_init(void)

//{

// NVIC_InitTypeDef  NVIC_ADC1_InitStruct;

// NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);

// NVIC_ADC1_InitStruct.NVIC_IRQChannel= ADC1_2_IRQn;

// NVIC_ADC1_InitStruct.NVIC_IRQChannelCmd= ENABLE;

// NVIC_ADC1_InitStruct.NVIC_IRQChannelPreemptionPriority=2;

// NVIC_ADC1_InitStruct.NVIC_IRQChannelSubPriority=2;

// NVIC_Init(&NVIC_ADC1_InitStruct);

//}


//__IO  u16 adc_value1[4]={0};

//__IO  u16 adc_value1_temp[4]={0};

//u8 temp=0;

//void ADC1_2_IRQHandler(void)

//{

//  

// if(ADC_GetITStatus(ADC1,ADC_IT_EOC))

// {

//  adc_value1_temp[temp]=ADC1->DR;

//  if(temp++>=2)

//   temp=0;

// }

// ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);

//}


这里是DMA搬运ADC

ADC_DMA:

void adc1_out3_init(void)

{

//nvic_init();

ADC_GPIOC_INIT();

adc1_init();

}


static void ADC_GPIOC_INIT(void)

{   GPIO_InitTypeDef ADC1_GPIOC_InitStruct;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

   ADC1_GPIOC_InitStruct.GPIO_Mode=GPIO_Mode_AIN;

   ADC1_GPIOC_InitStruct.GPIO_Pin|=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;

   ADC1_GPIOC_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;

   GPIO_Init(GPIOC,&ADC1_GPIOC_InitStruct);

}


static  void adc1_init(void)

{

   ADC_InitTypeDef ADC1_InitStruct;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC外设时钟

 ADC1_InitStruct.ADC_ContinuousConvMode=ENABLE; //是否连续转换  就是时间到了就更新新的数据不靠软件在去触发

   ADC1_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐  

 ADC1_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //触发源选择 为软件  

   ADC1_InitStruct.ADC_Mode=ADC_Mode_Independent;//独立模式1 很多模式看手册描述 这里是独立

   ADC1_InitStruct.ADC_NbrOfChannel=3;//几个通道

   ADC1_InitStruct.ADC_ScanConvMode=ENABLE;//通道扫描模式一个一个去采 采集完后是不是去下一个通道采,一般用于多通道

   ADC_Init(ADC1, &ADC1_InitStruct);//初始化结构体

   RCC_ADCCLKConfig(RCC_PCLK2_Div8);//采样时钟 最大14M时钟

   ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_55Cycles5); //选择采集通道,转换顺序1,和采样时钟

   ADC_RegularChannelConfig(ADC1,ADC_Channel_12,2,ADC_SampleTime_55Cycles5);

   ADC_RegularChannelConfig(ADC1,ADC_Channel_13,3,ADC_SampleTime_55Cycles5);

  ADC_DMACmd(ADC1, ENABLE);//开启DMA  

//  ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);

   ADC_Cmd(ADC1,ENABLE);//开启ADC

 //也可以开中断 DMA 但是ADC的EOC的标志位是要把通道转完了就产生中断 用DMA搬运好多了

   ADC_ResetCalibration(ADC1);//初始化效准寄存器,ADC效验初始化

   while(ADC_GetResetCalibrationStatus(ADC1));//是否效验初始化完成

   ADC_StartCalibration(ADC1);//开始效准

   while(ADC_GetCalibrationStatus(ADC1));//效准完成    手册有描述  

 ADC_SoftwareStartConvCmd(ADC1,ENABLE);//不要 ADC_SoftwareStartInjectedConvCmd这个函数以为是启动函数哇,

 //要多通道必须是中断或DMA直接用会3个乱掉

}

DMA配置:

#define ADC1_ADDR  0x4001244C

__IO  u16 adc_value1[3]={0};

__IO  float adc_value1_temp[4]={0};

void dma1_adc1_init(void)

{

DMA_InitTypeDef DMA1_line1_InitStruct;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA1_line1_InitStruct.DMA_PeripheralBaseAddr=(u32)ADC1_ADDR;  //有坑 尽量不要用ADC->DR数据有问题 外饰地址  

DMA1_line1_InitStruct.DMA_MemoryBaseAddr=(u32)adc_value1; //变量地址

DMA1_line1_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;//方向 外设-》变量

DMA1_line1_InitStruct.DMA_BufferSize=3;//DMA一次循环菜几次

DMA1_line1_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord ;//变量宽度

DMA1_line1_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;////外设宽度

DMA1_line1_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;//变量地址是不是自增

DMA1_line1_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址是不是自增

DMA1_line1_InitStruct.DMA_Priority=DMA_Priority_High  ;//优先级

DMA1_line1_InitStruct.DMA_M2M=DMA_M2M_Disable;//是不是内存到内存

DMA1_line1_InitStruct.DMA_Mode=DMA_Mode_Circular;//循环搬运

DMA_Init(DMA1_Channel1,&DMA1_line1_InitStruct);//通道选择,看手册

DMA_Cmd(DMA1_Channel1,ENABLE); //开启DMA

}

这样子就可以通过DMA获取ADC的值了


备注:

//电压计算公式

//ADC=采来的值/4096*3.3    或采来的值*3.3/4096+补偿      3.3为VREF+和VREF-的引脚值   以实际为主

//ADC放大就成倍  

//ADC显示比例 ADC=实际电压/VREF+和VREF-的引脚值(3.3)*要的比例 例100 实际电压3.3/3.3*100

int main(void)

{

dma1_adc1_init();

 adc1_out3_init();//调用

while(1)

{

}

}




【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
pbfHt7yP3Hym