ADC简介
ADC(Analog-to-Digital Converte,模/数转换),是指将连续变量的模拟信号转换为离散的数字信号的器件。Stm32上集成的ADC其功能十分强大,有如下的技术指标与特性:
- 12位分辨率,逐次逼近型,那么转换数据的最大值为大就是
- 0-3.6v的转换范围,那么模拟量计算公式为
- 多达18个通道,可测量16个外部和2个内部信号源,各通道的A/D转换可以单次、连续、扫描或间断模式执行
- 规则通道转换期间有DMA请求产生。
- ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。
ADC工作过程分析
上图中展示18个通道,其中2个测量内内部信号源(芯片内部温度),注意只有测量外部信号源的通道会进入注入通道与规则通道,如下图。
其中规则通道是最平常的通道、也是最常用的通道,平时的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得到的,下图截图自用户参考手册。
接下来看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