嵌入式系统:ADC

ADC(模数转换)

在这里插入图片描述


(一)ADC原理

1.模数转换:将模拟量转化为数字量

(1)采样:将连续的模拟量转化为时间离散的模拟量

(2)量化:将时间离散的模拟量转化为时间数值都离散的数字量

(3)编码:根据特定规则,将每一级的数字量编码为二进制数


2.ADC转换过程

在这里插入图片描述

(1)外部模拟量从输入引脚传入,低通滤波

(2)在采样时间内,采样保持电路进行采样

(3)ADC电路在转换时间内,进行转换(量化 + 编码)

(4)转换后的结果存入缓存


3.逐次逼近型ADC:现代MCU常用的ADC转换电路

在这里插入图片描述

  • L S B = V R E F / 2 n LSB = V_{REF}/2^n LSB=VREF/2n
  • n 越大,精度越高

(1)将参考电压按ADC的位数 n 分成 2 n 2^n 2n 等份,每一级的电压值为 V R E F / 2 n V_{REF}/2^n VREF/2n

(2)将输入电压与每一级电压逐次比较,大于该级电压就将该为置1,直到小于某级电压置0

(3)如此,输入电压的值就被近似逼近在一个范围内了, V I N = s a m p l e V a l u e ∗ V R E F / 2 n V_{IN} = sampleValue * V_{REF}/2^n VIN=sampleValueVREF/2n


(二)编程

1.编程流程

(1)引脚复用为模拟输入

(2)ADC功能配置

  • 时钟配置
  • 参考电压
  • 采样时间
  • 转换时间
  • 转换通道(采样通道)
  • 触发方式(软件/定时器触发)
  • 转换模式(单次、连续、扫描(多通道))
  • 数据对齐方式(左/右对齐)

(3)ADC模块使能

(4)中断配置(转换完成后可触发中断)

  • 中断源
  • 中断优先级
  • 中断使能

(5)采样数据读取

  • 查询模式
  • 中断模式
  • DMA模式

2.编程实例

(1)寄存器版本

#include "msp.h"
#include "driverlib.h"

void uSDelay( __IO uint32_t us)
{
	uint32_t i;
	SysTick->LOAD  = (uint32_t)(SystemCoreClock/24000000 - 1UL);
	SysTick->VAL   = 0UL;
	SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
	
	for(i=0;i<us;i++)
	{
		/* 当计数器的值减小到0的时候,CRTL寄存器的位16会置1*/	
		while( !((SysTick->CTRL)&(1<<16)) );
	}
	/* 关闭SysTick定时器*/	
	SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}

void initADC()
{
	//选用ADC内部的温度传感器采样
	
	//ADC功能配置(采样频率、采样分辨率、采样通道、采样参考电压、采样模式)
	//时钟源选择:SMCLK 12MHz,1分频
	ADC14->CTL0 |= ADC14_CTL0_SSEL__SMCLK | ADC14_CTL0_PDIV_0 | ADC14_CTL0_DIV__1;
	//单通道单次采样(手动采样)
	ADC14->CTL0 |= ADC14_CTL0_CONSEQ_0;
	
	//内部温度传感器采样、14位分辨率、内存0
	ADC14->CTL1 |= ADC14_CTL1_TCMAP | ADC14_CTL1_RES__14BIT;
	ADC14->CTL1 &=~ADC14_CTL1_CSTARTADD_MASK;
	
	//内部参考电压、内部温度传感器在A22
	ADC14->MCTL[0] |= ADC14_MCTLN_VRSEL_1 | ADC14_MCTLN_INCH_22;
	
	//ADC内核使能
	ADC14->CTL0 |= ADC14_CTL0_ON;
	
	
}

uint16_t  nSmpVal[5],nI,nMin,nMax,nMinIndex,nMaxIndex,nSampleSum,nValidCnt;
//采样五次,去掉最大值和最小值后取平均值
uint16_t GetSampleValue()
{
	//采样使能,开始采样
	ADC14->CTL0 |= ADC14_CTL0_ENC | ADC14_CTL0_SC ;
	uSDelay(5);
	ADC14->CTL0 &=~(ADC14_CTL0_ENC | ADC14_CTL0_SC);
	
	uSDelay(10);
	nMin=1024,nMax=0;
    for(nI=0;nI<5;nI++)
    {
		ADC14->CTL0 |= ADC14_CTL0_ENC | ADC14_CTL0_SC ;
        uSDelay(5);
        nSmpVal[nI]= ADC14->MEM[0];
        ADC14->CTL0 &=~(ADC14_CTL0_ENC | ADC14_CTL0_SC);
        uSDelay(5);
        if(nSmpVal[nI]>nMax)
        {
			nMaxIndex=nI;
            nMax=nSmpVal[nI];
  	    }
        if(nSmpVal[nI]<nMin)
        {
            nMinIndex=nI;
            nMin=nSmpVal[nI];
        }
    }
    nSampleSum=0;nValidCnt=0;
    for(nI=0;nI<5;nI++)
    {
        if((nI!=nMinIndex)&&(nI!=nMaxIndex))
        {
            nSampleSum+=nSmpVal[nI];
            nValidCnt++;
        }
    } 
	if(nValidCnt>0)
    	return nSampleSum/nValidCnt;
    return 0;
}

float TempSample()
{
	float TValue = 0.0f;
	uint16_t SampleValue = 0,SampleValue1 = 0;
	short SampleValueOff;
	
	//使能内部温度传感器
	REF_A->CTL0 &=~REF_A_CTL0_TCOFF;
	
	//设置参考电压(2.5V),使能
	REF_A->CTL0 |= REF_A_CTL0_VSEL_3 | REF_A_CTL0_ON;
	
	SampleValue  = GetSampleValue();
	SampleValue1 = GetSampleValue();
	
	SampleValueOff = SampleValue1 - SampleValue;
	
	if(SampleValueOff >(-10) && SampleValueOff < 10)
	{
		if(SampleValue == 0)
			TValue = 0;
		else
			TValue = (2.5f*SampleValue)/16383;
	}
	
	return TValue;
}

void main()
{
	WDTCTL = WDTPW + WDTHOLD;
	
	//解锁时钟寄存器(0x695A)
	CS->KEY = CS_KEY;
	
	//DCO 12MHz
	CS->CTL0 |= CS_CTL0_DCORSEL_3 | CS_CTL0_DCOEN;
	
	//SMCLK:12MHz
	CS->CTL1 |= CS_CTL1_SELS__DCOCLK | CS_CTL1_DIVS__1 | CS_CLKEN_SMCLK_EN;
	
	//锁住时钟寄存器(0xA569)
	CS->KEY = CS_KEY_KEY_OFS;
	
	initADC();
	float value;
	value = TempSample();

	while(1);
}

(2)库函数版本

#include "msp.h"
#include "driverlib.h"

void uSDelay( __IO uint32_t us)
{
	uint32_t i;
	SysTick->LOAD  = (uint32_t)(SystemCoreClock/24000000 - 1UL);
	SysTick->VAL   = 0UL;
	SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
	
	for(i=0;i<us;i++)
	{
		/* 当计数器的值减小到0的时候,CRTL寄存器的位16会置1*/	
		while( !((SysTick->CTRL)&(1<<16)) );
	}
	/* 关闭SysTick定时器*/	
	SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}

void initADC()
{
	//ADC内核初始化
	ADC14_initModule(ADC_CLOCKSOURCE_SMCLK, ADC_PREDIVIDER_1,ADC_DIVIDER_1,ADC_TEMPSENSEMAP);
	//ADC采样模式配置
	ADC14_configureSingleSampleMode(ADC_MEM0, true);
	//ADC采样通道配置
	ADC14_configureConversionMemory(ADC_MEM0, ADC_VREFPOS_INTBUF_VREFNEG_VSS,ADC_INPUT_A22, false);
	
	//ADC采样模块使能
	ADC14_enableModule();
}

uint16_t  nSmpVal[5],nI,nMin,nMax,nMinIndex,nMaxIndex,nSampleSum,nValidCnt;
//采样五次,去掉最大值和最小值后取平均值
uint16_t GetSampleValue()
{
	//采样使能,开始采样
	ADC14_enableConversion();
	ADC14_toggleConversionTrigger();
	uSDelay(5);
	ADC14_disableConversion();
	
	uSDelay(10);
	nMin=1024,nMax=0;
    for(nI=0;nI<5;nI++)
    {
		ADC14_enableConversion();
		ADC14_toggleConversionTrigger();
        uSDelay(5);
        nSmpVal[nI]= ADC14->MEM[0];
        ADC14_disableConversion();
        uSDelay(5);
		
        if(nSmpVal[nI]>nMax)
        {
			nMaxIndex=nI;
            nMax=nSmpVal[nI];
  	    }
        if(nSmpVal[nI]<nMin)
        {
            nMinIndex=nI;
            nMin=nSmpVal[nI];
        }
    }
    nSampleSum=0;nValidCnt=0;
    for(nI=0;nI<5;nI++)
    {
        if((nI!=nMinIndex)&&(nI!=nMaxIndex))
        {
            nSampleSum+=nSmpVal[nI];
            nValidCnt++;
        }
    } 
	if(nValidCnt>0)
    	return nSampleSum/nValidCnt;
    return 0;
}

float TempSample()
{
	float TValue = 0.0f;
	uint16_t SampleValue = 0,SampleValue1 = 0;
	short SampleValueOff;
	
	//使能内部温度传感器
	REF_A_enableTempSensor();
	
	//设置参考电压(2.5V),使能
	REF_A_setReferenceVoltage(REF_A_VREF2_5V);
    REF_A_enableReferenceVoltage();
	
	SampleValue  = GetSampleValue();
	SampleValue1 = GetSampleValue();
	
	SampleValueOff = SampleValue1 - SampleValue;
	
	if(SampleValueOff >(-10) && SampleValueOff < 10)
	{
		if(SampleValue == 0)
			TValue = 0;
		else
			TValue = (2.5f*SampleValue)/16383;
	}
	
	return TValue;
	
}

void main()
{
	/* Halting WDT  */
    WDT_A_holdTimer();

	//设置时钟频率 DCO 12MHz
	CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);
	//时钟源 SMCLK 12MHz
	CS_initClockSignal(CS_SMCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);

	initADC();
	float value;
	value = TempSample();

	while(1);
	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值