STM32 adc

原文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 = GPIO_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事件

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值