您的位置:首页 > 其它

STM32 adc

2016-01-18 21:35 288 查看
原文http://www.cnblogs.com/zyqgold/archive/2013/05/22/3093681.html

折腾了两天ADC多通道采样,采样的结果都很乱,完全不是预期值。在amobbs求助也没有找到结果。于是决定从简单开始,一步步折腾着破ADC。

【ADC试验1实验说明】

            1、这个实验仅仅是初始化一个ADC,对其输入进行采样。

            2、使用STM32F4的ADC1进行采样,采样值不输出之在编译器里边观察。

            3、使用ST外设库进行实验

            4、本实验只为采集到数据,采样周期、采样间隔设置为最大。

【ADC试验1实验结果】

             成功采集到了ADC1,通道1引脚PA1上的输入。数据稳定不跳变。

【ADC试验1实验步骤】

1、首先怀疑是工程中使用的USART、EXTI什么的影响了ADC的。重建工程,加入ST外设库,添加引用位置。这一步就不说了。

2、开启GPIOA、ADC时钟。因为使用ADC1的通道1,对应的PA1引脚作为输入。

ADC挂接在APB2时钟上,GPIOA挂接在AHB1时钟上。所以要开启这两个时钟。

代码如下:

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

3、输入引脚配置

          输入端口PA,引脚1.模拟输入,引脚时钟100M

//PA1 PA2 PA3,模拟输入

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_InitStructure.GPIO_Pin = GPIO_PinSource1 | GPIO_PinSource2 | GPIO_PinSource3;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

4、ADC通用的初始化

        这是F4系列新出来的东西,与F1不同。这里通过库函数配置一个新增的寄存器ADC_CCR,这个配置将影响片上所有的ADC。

//ADC通用配置

ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;  //不用DMA

ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;  //独立采样

ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;  //速度尽可能低

ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;

ADC_CommonInit(&ADC_CommonInitStructure);

5、ADC1初始化

        之后对单独的ADC1进行配置,设定一些参数。最后的ADC_RegularChannelConfig完成通道选择和扫描顺序设置

主要参数:连续采样/数据右对齐/不用外部触发/采样通道数1/12位精度

//ADC1配置

ADC_InitStructyre.ADC_ContinuousConvMode = ENABLE;

ADC_InitStructyre.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStructyre.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;

ADC_InitStructyre.ADC_NbrOfConversion = 1;  //通道数

ADC_InitStructyre.ADC_Resolution = ADC_Resolution_12b;

ADC_InitStructyre.ADC_ScanConvMode = ENABLE;

ADC_Init(ADC1,&ADC_InitStructyre);

  

ADC_Cmd(ADC1,ENABLE);

ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_144Cycles);

6、手动开始ADC采样,由于配置为连续扫描所有只需要开启一次即可:

     使用函数ADC_SoftwareStartConv(ADC1);完成

7、获取ADC采样数据:

    可以通过读ADC的DR或者使用库函数ADC_GetConversionValue来完成。我使用的是库函数。

adcvalue1 = ADC_GetConversionValue(ADC1);

adcvota = adcvalue1 *3300 / 0xfff;

8、最后加上串口功能,让数据回显

while(1)

{

   adcvalue1 = ADC_GetConversionValue(ADC1);

   adcvota = adcvalue1 *3300 / 0xfff;

  

  for(i = 0;i<10000;i++)

  {

      sum += adcvota;

    if(i ==9999)

    {

       avgvota = sum/10000;

       sum = 0;

      printf("avg vota is: %d\r\n",avgvota);

    }

  }

}

9、完整的代码:

#include <stm32f4xx.h>

#include "stm32f4xx_rcc.h"

#include "stm32f4xx_gpio.h"

#include "stm32f4xx_adc.h"

#include "stm32f4xx_conf.h"
#include "usart.h"
#include <stdio.h>
NVIC_InitTypeDef NVIC_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

ADC_CommonInitTypeDef ADC_CommonInitStructure;

ADC_InitTypeDef ADC_InitStructyre;
int adcvalue1,adcvalue2,adcvalue3;

int adcvota ;
int i,sum,avgvota;
int main()

{

  USART_Config();

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

  //PA1 PA2 PA3,模拟输入

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

//   GPIO_InitStructure.GPIO_OType = GPI
cb11
O_OType_PP;

  GPIO_InitStructure.GPIO_Pin = GPIO_PinSource1 | GPIO_PinSource2 | GPIO_PinSource3;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_Init(GPIOA,&GPIO_InitStructure);

  //ADC通用配置

  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;  //不用DMA

  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;  //独立采样

  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;  //速度尽可能低

  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;

  ADC_CommonInit(&ADC_CommonInitStructure);

  

  //ADC1配置

  ADC_InitStructyre.ADC_ContinuousConvMode = ENABLE;

  ADC_InitStructyre.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructyre.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;

  ADC_InitStructyre.ADC_NbrOfConversion = 1;

  ADC_InitStructyre.ADC_Resolution = ADC_Resolution_12b;

  ADC_InitStructyre.ADC_ScanConvMode = ENABLE;

  ADC_Init(ADC1,&ADC_InitStructyre);

    

  ADC_Cmd(ADC1,ENABLE);

  ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_144Cycles);

  

  ADC_SoftwareStartConv(ADC1);

  

  sum = 0;

  while(1)

  {

     adcvalue1 = ADC_GetConversionValue(ADC1);

     adcvota = adcvalue1 *3300 / 0xfff;

    

    for(i = 0;i<10000;i++)

    {

        sum += adcvota;

      if(i ==9999)

      {

         avgvota = sum/10000;

         sum = 0;

        printf("avg vota is: %d\r\n",avgvota);

      }

    }

  }

}

  

  //重定义printf

int fputc(int ch,FILE *f)

{

  //检查发送寄存器为空之后再往里边放数据 

  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)

  {}

  //USART发送一个字符

  USART_SendData(USART1, (uint8_t) ch);

  return ch;

}
1:混合同步注入+快速交替模式 
    #define ADC_Mode_InjecSimult_SlowInterl ((uint32_t)0x00040000) 0100:混合同步注入+慢速交替模式 
    #define ADC_Mode_InjecSimult ((uint32_t)0x00050000) 0101:注入同步模式 
    #define ADC_Mode_RegSimult ((uint32_t)0x00060000) 0110:规则同步模式 
    #define ADC_Mode_FastInterl ((uint32_t)0x00070000) 0111:快速交替模式 
    #define ADC_Mode_SlowInterl ((uint32_t)0x00080000) 1000:慢速交替模式 
    #define ADC_Mode_AlterTrig ((uint32_t)0x00090000) 1001:交替触发模式 
    */ 
    ADC_InitStructure.ADC_ScanConvMode = ENABLE; 
    /* ADC_ScanConvMode在stm32f10x_adc.h中定义如下: 
    FunctionalState ADC_ScanConvMode; 
    这个参数用来指定转换是扫描(多通道模式)还是单个转换(单通道模式),该参数可以被设置为DISABLE或者ENABLE。 
    在数据手册中,SCAN位是这样描述的:扫描模式 
    该位由软件设置和清除,用于开启或关闭扫描模式。在扫描模式中,由ADC_SQRx或ADC_JSQRx寄存器选中的通道被转换。 
    0:关闭扫描模式 
    1:使用扫描模式 
    注:如果分别设置了EOCIE或JEOCIE位,只在最后一个通道转换完毕才会产生EOC或JEOC中断。 
    这样,如果一次需要对多个通道进行转换,这位就必须设置为ENABLE。 
    */ 
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
    /* FunctionalState ADC_ContinuousConvMode; 
    这个参数用来指定转换是连续进行还是单次进行,它可以设置为ENABLE或者DISABLE。 
    这两个参数中出现了FunctionalState数据类型,那么它是什么呢,顺滕摸瓜,可以看到它的的定义如下: 
    typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; 
    因此,它相当于是一个位变量,我的理解,DISPABLE=0这个没有问题,ENABLE=!DISABLE是否应该确切的是1??否则下面的设置就会有问题。 
    用这两个符号来对寄存器中的位进行设置的话,还需要提供位置信息,如下面的代码所示: 
    tmpreg1 |= (uint32_t)(ADC_InitStruct-》ADC_DataAlign | ADC_InitStruct-》ADC_ExternalTrigConv | 
    ((uint32_t)ADC_InitStruct-》ADC_ContinuousConvMode 《《 1)); 
    这个《《1就是位置信息,CONT是CON2寄存器的位1 
    这样,我们看STM32的库又能多看懂一点了。 
    用于设定CON2的CONT位(位1):是否连续转换 
    该位由软件设置和清除。如果设置了此位,则转换将连续进行直到该位被清除。 
    0:单次转换模式 1:连续转换模式 
    */ 
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 
    /* uint32_t ADC_ExternalTrigConv; 
    定义如何来触发AD转换,一共有8个可选项,以下给出两个来解释一下: 
    #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000) 
    将0x00040000写成二进制,就是: 
    0000 0000 0000 0100 0000 0000 0000 0000 
    对照下面的说明,不难看出,第19:17位是 010,即定时器1的CC3事件触发。 
    #define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) 
    将0x000E0000写成二进制,就是: 
    0000 0000 0000 1110 0000 0000 0000 0000 
    对照下面的说明,是SWSTART方式,即用软件标志来启动转换。 
    关于EXTSEL[2:0]的说明: 
    位19:17 EXTSEL[2:0]:选择启动规则通道组转换的外部事件 
    这些位选择用于启动规则通道组转换的外部事件 
    ADC1和ADC2的触发配置如下 
    000:定时器1的CC1事件 100:定时器3的TRGO事件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: