本帖最后由 kkhkbb 于 2018-3-19 08:56 编辑
一、概述
1、ADC简介
ADC是A/D转换部件,单片机不能直接处理模拟量,所以需要ADC将模拟量转换为数字量后,在进行处理。在使用单片机进行模拟数据处理的过程中,ADC至关重要。ADC以下几种类型: - 积分型:积分型AD工作原理是将输入电压转换成时间(脉冲宽度信号)或频率(脉冲频率),然后由定时器/计数器获得数字值。其优点是用简单电路就能获得高分辨率,抗干扰能力强,但缺点是由于转换精度依赖于积分时间,因此转换速率极低。初期的单片AD转换器大多采用积分型,现在逐次比较型已逐步成为主流。
- 逐次比较型:逐次比较型AD由一个比较器和DA转换器通过逐次比较逻辑构成,从MSB开始,顺序地对每一位将输入电压与内置DA转换器输出进行比较,经n次比较而输出数字值。其电路规模属于中等。其优点是速度较高、功耗低,在低分辩率(<12位)时价格便宜,但高精度(>12位)时价格很高。
- 并行比较型/串并行比较型:并行比较型AD采用多个比较器,仅作一次比较而实行转换,又称FLash(快速)型。由于转换速率极高,n位的转换需要2n-1个比较器,因此电路规模也极大,价格也高,只适用于视频AD转换器等速度特别高的领域。串并行比较型AD结构上介于并行型和逐次比较型之间,最典型的是由2个n/2位的并行型AD转换器配合DA转换器组成,用两次比较实行转换,所以称为 Half flash(半快速)型。还有分成三步或多步实现AD转换的叫做分级(Multistep/Subrangling)型AD,而从转换时序角度又可称为流水线(Pipelined)型AD,现代的分级型AD中还加入了对多次转换结果作数字运算而修正特性等功能。这类AD速度比逐次比较型高,电路 规模比并行型小。
- Σ-Δ(Sigma delta)调制型:Σ-Δ型AD由积分器、比较器、1位DA转换器和数字滤波器等组成。原理上近似于积分型,将输入电压转换成时间(脉冲宽度)信号,用数字滤波器处理后得到数字值。电路的数字部分基本上容易单片化,因此容易做到高分辨率。主要用于音频和测量。
- 电容阵列逐次比较型:电容阵列逐次比较型AD在内置DA转换器中采用电容矩阵方式,也可称为电荷再分配型。一般的电阻阵列DA转换器中多数电阻的值必须一致,在单芯片上生成高 精度的电阻并不容易。如果用电容阵列取代电阻阵列,可以用低廉成本制成高精度单片AD转换器。最近的逐次比较型AD转换器大多为电容阵列式的。
- 压频变换型:压频变换型(Voltage-Frequency Converter)是通过间接转换方式实现模数转换的。其原理是首先将输入的模拟信号转换成频率,然 后用计数器将频率转换成数字量。从理论上讲这种AD的分辨率几乎可以无限增加,只要采样的时间能够满足输出频率分辨率要求的累积脉冲个数的宽度。其优点是分辩率高、功耗低、价格低,但是需要外部计数电路共同完成AD转换。
2、ADC主要参数介绍 ADC主要参数有以下几点: - 分辨率:数字量变化一个最小量时模拟量的变化量,定义为满刻度与2n的比值。分辩率又称精度,通常以数字信号的位数来表示。
- 转换速率:完成一次A/D转换所需要时间的倒数,值越大表示转换得越快。积分型AD的转换时间是毫秒级属低速AD,逐次比 较型AD是微秒级属中速AD,全并行/串并行型AD可达到纳秒级。
- 量化误差:由于AD的有限分辩率而引起的误差,即有限分辩率AD的阶梯状转移特性曲线与无限分辩率AD(理想AD)的转移特 性曲线(直线)之间的最大偏差。通常是1 个或半个最小数字量的模拟变化量,表示为1LSB、1/2LSB。
- 偏移误差:输入信号为零时输出信号不为零的值,可外接电位器调至最小。
- 满刻度误差:满度输出时对应的输入信号与理想输入信号值之差。
- 线性度:实际转换器的转移函数与理想直线的最大偏移。
3、STM32F407IGT6ADC介绍 STM32F407IGT6具有3个12位逐次逼近式ADC,共24个通道,可以配置成12位、8位、6位使用。可使用软件对对要使用的ADC进行使能和设置,进行模拟量的采集。
二、硬件电路
图9_0 ARM 电源监测ADC使用图 在iCore3双核心开发板中,使用了个ADC进行电源监控分配如下表所示: ADC选用 | 监测内容 | ADC1-14通道 | 5V电压 | ADC1-15通道 | 输入电流 | ADC3-15通道 | 1.2V电压 | ADC3-4通道 | 3.3V电压 | ADC3-5通道 | 2.5V电压 |
表9_0 ARM 电源监测ADC使用分配表 三、实验原理 使用 ADC的5个通道,分别监测5种电源信息,使用程序进行相应的转换后,使用putty串口工具将采集到电源信息打印到PC机屏幕上,了解开发板的电源状态。 STM32 内部集成三个 12 位 ADC, iCore3 的所有电源经过电阻分压或者直接接入 STM32的 ADC 的输出通道内, 输入电流经过高端电流检测芯片 ZXCT1009F 输入到 ADC 的输入通道内,从而实现电源监控功能。 电压监控硬件连接示意图: 图9_1电压监测硬件连接图 由上图可知:VCC =(1 + R1 / R2)*ADC_IN; 故知:VCC = (1 + 49.9K / 10K)*ADC_IN = 6*ADC_IN; 其他电源监控同理可得:D3V3 = 2*ADC_IN; A2V5 =2*ADC_IN; D1V2 =ADC_IN。 电流监控硬件连接示意图如下图: 图9_2电流监测硬件连接图 由 ZXCT1009F 的原理可知:ADC_IN = 0.01 * (VCC - LOAD)*R2;
通过 R1 的电流:I = 100 *ADC_IN /R2 /R1;
带入 R2 = 10K,R1 = 0.02:得出:I =ADC_IN / 2; 四、源代码 1.主函数 //--------------------------- Include ---------------------------//
#include "..\include\led.h"
#include "..\include\main.h"
#include "..\include\usart.h"
#include "..\include\adc.h"
#include "..\fwlib\inc\stm32f4xx_gpio.h"
//---------------------------- Define ---------------------------//
//-------------------------- Variable ---------------------------//
//--------------------- Function Prototype ----------------------//
//--------------------------- Function --------------------------//
/*
* Name : main
* Description : ---
* Author : ysloveivy.
*
* History
* --------------------
* Rev : 0.00
* Date : 11/21/2015
*
* create.
* --------------------
*/
int main(void)
{
int i;
//初始化
led.initialize();
LED_RED_ON;
usart4.initialize(115200);
adc.initialize();
usart4.printf("\x0c"); //清屏
usart4.printf("\033[1;32;40m"); //设置终端字体为绿色
usart4.printf("\r\n\r\nhello! I am iCore3!\r\n\r\n\r\n");
while(1){
for(i = 0;i < 10000000;i++);
//ADC 监控电源
for(i = 0;i < 5;i++){
adc.read(i);
}
//打印系统供电电压,
usart4.printf(" [V] %4.2fV, ",adc.value[0] * 6);
usart4.printf("[I] %3.0fmA , ",adc.value[1] / 2* 1000.);
usart4.printf("[1.2V] %4.2fV, ",adc.value[2]);
usart4.printf("[3.3V] %4.2fV, ",adc.value[3] * 2);
usart4.printf("[2.5V] %4.2fV\r",adc.value[4] * 2);
}
}
2.ADC参数配置 /*
* Name : initialize
* Description : ---
* Author : ysloveivy.
*
* History
* --------------------
* Rev : 0.00
* Date : 11/21/2015
*
* create.
* --------------------
*/
static int initialize(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); //使能ADC3时钟
//ADC1_PC4<----->通道14, ADC1_PC5<----->通� �15
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //模拟输入
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//ADC3_PF5<----->通道15, ADC3_PF6<----->通道4, ADC3_PF7<----->通道5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //模拟输入
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOF, &GPIO_InitStructure);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //ADC为独立模式
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //设置两个采样阶段之间的延迟周期数为5个周期
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //禁止DMA
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div6; //设置分频系数为6分频
ADC_CommonInit(&ADC_CommonInitStructure); //初始化ADC
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //ADC转换分辨率12位
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //非扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //关闭连续转换模式
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止触发检测
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //右对齐方式
ADC_InitStructure.ADC_NbrOfConversion = 1; //1个转换在规则序列中
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC3, &ADC_InitStructure); //使能ADC
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC3, ENABLE);
return 0;
}
/*
* Name : sort
* Description : ---
* Author : XiaomaGee.
*
* History
* ----------------------
* Rev : 0.00
* Date : 11/21/2015
*
* create.
* ----------------------
*/
void sort(unsigned short int a[], int n)
{
int i, j, t;
//元素从小到大排列
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - i - 1; j++) {
if (a[j] > a[j + 1]) {
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
}
/*
* Name : read_adc
* Description : ---
* Author : ysloveivy.
*
* History
* ----------------------
* Rev : 0.00
* Date : 11/21/2015
*
* create.
* ----------------------
*/
static int read_adc(int channel)
{
int i,k;
unsigned long int temp[20] = {0};
unsigned long int value;
unsigned short int data[100];
unsigned char channel_remap[5] = {ADC_Channel_14,ADC_Channel_15,ADC_Channel_15,ADC_Channel_4,ADC_Channel_5};
//取得到的100个转换值的中间20个的平均值作为结果
//连续取20次这样的平均值,再求平均值作为最终结果
for(k = 0;k < 20;k++){
for(i = 0;i < 100;i++){
if(channel == 0 || channel == 1){
ADC_RegularChannelConfig(ADC1, channel_remap[channel], 1, ADC_SampleTime_480Cycles); //ADC1规则通道为通道14,15,一个序列,采样时间为480个周期
ADC_SoftwareStartConv(ADC1); //使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //等待转换结束
data[i] = ADC_GetConversionValue(ADC1); //将结果保存
}else {
ADC_RegularChannelConfig(ADC3, channel_remap[channel], 1, ADC_SampleTime_480Cycles); //ADC3规则通道为通道15,4,5,一个序列,采样时间为480个周期
ADC_SoftwareStartConv(ADC3);
while(!ADC_GetFlagStatus(ADC3,
ADC_FLAG_EOC));
data[i] = ADC_GetConversionValue(ADC3);
}
}
sort(data,100);
for(i = 40;i < 60;i++){
temp[k] += data[i];
}
temp[k] = temp[k] / 20;
}
value = 0;
for(k = 0;k < 20;k++){
value += temp[k];
}
value /= 20;
adc.value[channel] = value * ADC_REF / 4096;
return value;
}
3.ADC参数配置说明 typedef struct
{
uint32_t ADC_Mode;
uint32_t ADC_Prescaler;
uint32_t ADC_DMAAccessMode;
uint32_t ADC_TwoSamplingDelay;
}ADC_CommonInitTypeDeftypedef ;
typedef struct
{
uint32_t ADC_Resolution;
FunctionalState ADC_ScanConvMode;
FunctionalState ADC_ContinuousConvMode;
uint32_t ADC_ExternalTrigConvEdge;
uint32_t ADC_ExternalTrigConv;
uint32_t ADC_DataAlign;
uint8_t ADC_NbrOfConversion;
}ADC_InitTypeDef;;
ADC_Mode:工作模式, 分为独立模式和混合模式,混合模式中包含了多种工作模式。 ADC_Prescaler: 分频值, 用于配置ADC时钟,有2、4、6、8四种分频方式。 ADC_DMAAccessMode:DMX通道模式,分为:不使能、模式1、模式2、模式3。 ADC_TwoSamplingDelay:两个采样之间的延迟周期。 ADC_Resolution:分辨率,12、10、8、6位可设置。 FunctionalState ADC_ScanConvMode:用于是否开启转换模式。 FunctionalState ADC_ContinuousConvMode: 用于是否开启连续转换模式。 ADC_ExternalTrigConvEdge: 用来设置启动规则转换组转换的外部事件。 ADC_ExternalTrigConv: 色孩子数据触发检测。 ADC_DataAlign: 用于设置数据对齐方式是左对齐还是右对齐。 ADC_NbrOfConversion:用来设置规则序列的长度 。 五、实验现象 iCore3 双核心板红色 LED 常亮, 串口一直向终端输出电源监控的数据。 图9_3实验效果图
六、代码包下载
网盘:http://pan.baidu.com/s/1o7wSE06
|