stc5 采集adc值越来越小_Stm32之ADC配置方法及其基本工作原理分析

ADC简介

ADC(Analog-to-Digital Converte,模/数转换),是指将连续变量的模拟信号转换为离散的数字信号的器件。Stm32上集成的ADC其功能十分强大,有如下的技术指标与特性:

  • 12位分辨率,逐次逼近型,那么转换数据的最大值为大就是
  • 0-3.6v的转换范围,那么模拟量计算公式为
  • 多达18个通道,可测量16个外部和2个内部信号源,各通道的A/D转换可以单次、连续、扫描或间断模式执行
  • 规则通道转换期间有DMA请求产生。
  • ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。

ADC工作过程分析

v2-c69dde552319e35f9d9e6afe17647d81_b.jpg
ADC输入

上图中展示18个通道,其中2个测量内内部信号源(芯片内部温度),注意只有测量外部信号源的通道会进入注入通道规则通道,如下图。

v2-05da530d3e389a88a9fb13e4c962718b_b.jpg
ADC的两个转换通道

其中规则通道是最平常的通道、也是最常用的通道,平时的ADC转换都是用规则通道实现的。而注入通道是相对于规则通道的,注入通道可以在规则通道转换时,强行插入转换,相当于一个“中断通道”吧。当有注入通道需要转换时,规则通道的转换会停止,优先执行注入通道的转换,当注入通道的转换执行完毕后,再回到之前规则通道进行转换。

之后模拟信号会按照一定的可编程的规则(见数据手册)在ADCCLK的驱动下进行转换,将转换后的数据储存在16位的规则/注入通道的寄存器中,可以通过DMA请求或者CPU指令读取到内存(SRAM)中。

代码分析(DMA方式)

假设PA4引脚输入了一个模拟信号,我们要将其进行转换。首先分析adc.h

#ifndef __ADC_H
#define __ADC_H                
#include "sys.h"

#define ADC1_DR_Address    ((uint32_t)0x4001244C) /*ADC_DR的地址(查参考手册得出),
                                                    其值等于0x4001240+0x4c*/

#define ADCPORT     GPIOA   //定义ADC接口
#define ADC_CH4     GPIO_Pin_4  //定义ADC接口 

void ADC_DMA_Init(void);
void ADC_GPIO_Init(void);
void ADC_Configuration(void);

#endif

其中ADC_DR储存了ADC转换后的数据,将其作为DMA传递的源地址,他是由ADC1外设的基地址加上地址偏移0x4c得到的,下图截图自用户参考手册。

v2-1599189728a1bb17fab9997637f2e83c_b.jpg
ADC_DR地址

v2-aecd5249d96d14b1420e684a818f9c6a_b.png
ADC地址

接下来看adc.c文件

#include "adc.h"

vu16 ADC_DMA_IN4; //ADC数值存放的变量,注意volatile修饰变量,确保读取到实时的数值


/*DMA初始化设置*/
void ADC_DMA_Init(void) 
{ 
    /*定义DMA初始化结构体*/
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA1_Channel1);//复位DMA通道1
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //定义DMA通道外设基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_DMA_IN5; //定义DMA通道ADC数据存储器(其他函数可直接读此变量即是ADC值)
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//指定外设为源地址
    DMA_InitStructure.DMA_BufferSize = 1;//定义DMA缓冲区大小(根据ADC采集通道数量修改)
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//当前外设寄存器地址不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;//当前存储器地址:Disable不变,Enable递增(用于多通道采集)
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//定义外设数据宽度16位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //定义存储器数据宽度16位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA通道操作模式位环形缓冲模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA通道优先级高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止DMA通道存储器到存储器传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化DMA通道1
    DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA通道1
}


/*GPIO初始化设置*/
void ADC_GPIO_Init(void){ 
    GPIO_InitTypeDef  GPIO_InitStructure;   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIO时钟     
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//使能ADC1时钟
    GPIO_InitStructure.GPIO_Pin = ADC_CH4; //选择端口                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //选择为模拟输入方式,这是肯定的       
    GPIO_Init(ADCPORT, &GPIO_InitStructure);//写入寄存器         
}


/*ADC初始化设置*/
void ADC_Configuration(void){ 
    ADC_InitTypeDef ADC_InitStructure;//定义ADC初始化结构体变量
    ADC_GPIO_Init();//GPIO初始化设置
    ADC_DMA_Init();//DMA初始化设置
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC1和ADC2工作在独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; //有多个通道需要转换可开启扫描转换
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC转换工作在连续模式,若只读取1次数据就不开启此功能
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//有软件控制转换,不使用外部触发ADC功能,如外部中断
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//转换数据右对齐保存在16位变量中,读取更加方便
    ADC_InitStructure.ADC_NbrOfChannel = 1;//顺序进行规则转换的ADC通道的数目(根据ADC采集通道数量修改)
    ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器

    //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
    //ADC1,ADC通道x,规则采样顺序值为y,采样时间为28周期        
    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_28Cycles5);//ADC1选择信道x,采样顺序y,采样时间n个周期

    ADC_DMACmd(ADC1, ENABLE);// 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
    ADC_Cmd(ADC1, ENABLE);//使能ADC1
    ADC_ResetCalibration(ADC1); //重置ADC1校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1));//等待ADC1校准重置完成
    ADC_StartCalibration(ADC1);//开始ADC1校准
    while(ADC_GetCalibrationStatus(ADC1));//等待ADC1校准完成
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能ADC1软件开始转换,由于没有采用外部触发,所以使用软件触发方式
}

关于volatile关键字:

volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据,而且读取的数据立刻被保存。

小结

ADC配置过程如下:

  • 宏定义端口,及ADC_DR地址
  • 配置GPIO端口,使能时钟
  • 配置DMA,使能时钟
  • 配置ADC工作模式及其时钟,开启DMA支持,开启ADC验证以及软件触发ADC
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值