CC2430單片機(jī)標(biāo)稱AD轉(zhuǎn)換精度為14位,在單片機(jī)中算是比較高的了,CC2430最廣泛的用途是作為傳感器來(lái)使用的,而傳感器測(cè)量的物理量的原理多半是將物理量轉(zhuǎn)換成電流、電壓等模擬信號(hào),再通過AD轉(zhuǎn)換進(jìn)入單片機(jī)處理。所有用好CC2430的AD是使用好CC2430的一項(xiàng)基本技能。
本文引用地址:
http://butianyuan.cn/article/201611/320731.htm一、CC2430的ad的幾個(gè)重要參數(shù)
1、量化精度14位
2、轉(zhuǎn)換方式為代兒塔-西格瑪方式
3、8路獨(dú)立通道、4路差分通道
4、參考電壓可選內(nèi)部、外部參考電壓;(具體參考datasheet)
5、有DMA功能;(每個(gè)通道都能觸發(fā)),這個(gè)功能我認(rèn)為非常重要,主要是做交流采樣,很方便也很容易處理
6、精度可選;
二、單通道AD轉(zhuǎn)換
單通道ad轉(zhuǎn)換很簡(jiǎn)單,需要注意的是
1、搞清幾個(gè)AD寄存器的作用、設(shè)置的方法P0IFG、PERCFG、P0SEL、ADCCFG、P0DIR
2、被測(cè)電壓的負(fù)極要連到CC2430的GND上
3、轉(zhuǎn)換后數(shù)值的ADCL、ADCH內(nèi)數(shù)值的處理,要將ADCH放在低字節(jié)、ADCL放在高字節(jié)。將一個(gè)Uint16右移兩位(最后兩位沒有用);即可得到所要的ADC值;
4、電壓計(jì)算公式=ADC/精度*參考電壓;
ADC:第3條所得
精度:根據(jù)所選位數(shù),例如位數(shù)選14位,精度=2的14次方=16384
參考電壓:可選內(nèi)部或者外部,例如選內(nèi)部的1.25伏。
5、輸入電壓不要超過參考電壓。
二、差分通道轉(zhuǎn)換
1、選對(duì)輸入引腳、設(shè)對(duì)寄存器
2、電壓計(jì)算公式=ADC/精度*參考電壓;這里的精度相對(duì)于單通道的精度要再除以2
例如:轉(zhuǎn)換的值=4567; 位數(shù)=14位 ;參考電壓=1.25v 則被測(cè)電壓=4567/16384*2*1.25=0.6969 伏
再例如:轉(zhuǎn)換的值為=12345; 位數(shù)=14位 ;參考電壓=1.25v 則被測(cè)電壓=(12345-16384)/16384*2*1.25=-0.6163 伏
三、使用差分通道轉(zhuǎn)換時(shí)如何進(jìn)行補(bǔ)償
所有的AD器件都有可能有一定的0點(diǎn)偏差,即電壓輸入為0時(shí),轉(zhuǎn)換結(jié)果不為0,有可能大于0,也有可能小于0.所以,要得到正確的結(jié)果就要進(jìn)行補(bǔ)償。應(yīng)遵循以下幾個(gè)步驟:
1、測(cè)channel=0x0c,時(shí)的AD值
通道號(hào)選0xc時(shí),單片機(jī)認(rèn)為被測(cè)電壓為0,測(cè)得AD值為ADoffset1(有可能為+、也有可能為-);
2、測(cè)被測(cè)通道的AD值
假設(shè)測(cè)P0.4、P0.5兩個(gè)引腳間的電壓,測(cè)得AD值為ADC(有可能為+、也有可能為-);
3、被測(cè)電壓=(ADC-ADoffset)/精度*2*參考電壓;
四、使用DMA通道進(jìn)行AD采樣;
CC2430的DMA通道功能很強(qiáng)大,有多個(gè)觸發(fā)源。詳見datasheet;
交流采樣時(shí)使用DMA AD轉(zhuǎn)換有很多好處
a、采樣間隔容易計(jì)算
采樣間隔可通過公式Tconv = (decimation rate + 16) x 0.25 μs.來(lái)計(jì)算14位是decimation=512
b、AD采用的同時(shí)、單片機(jī)可以做其他事情,互相不干擾
c、存儲(chǔ)在一個(gè)數(shù)組之中,便于以后計(jì)算。
1、首先要了解CC2430的DMA怎么使用
2、可參考我的另一篇文章《CC2430 利用dma存儲(chǔ)adc連續(xù)轉(zhuǎn)換數(shù)據(jù)的存儲(chǔ),及轉(zhuǎn)換時(shí)間的計(jì)算》
3、舉例說明:程序比較長(zhǎng)可以只看前半部分,后半部分功能為計(jì)算對(duì)正弦波正弦波正半周平均值,DMA轉(zhuǎn)換的精髓在上半部分。
float getseadc (uint8 channel, uint8 refvolt)
{
volatile uint16 reading = 0;
uint8 resbits;
volatile uint16 adctemp,i;
volatile uint8 tmp;
uint8 adcChannel = 1;
volatile float sum,sum1;
int tmp1,max,m,n,X,lst;//m為大數(shù),n為小數(shù)
ADCCFG |= adcChannel;
if (channel==0x0A)
{
ADCCFG=0x30;
};
resbits=0x30;
tmp = ADCL;
tmp = ADCH;
osal_int_disable( INTS_ALL );
//配置dma
adcdma.srcAddrH=0xDF; //adch的邏輯地址
adcdma.srcAddrL=0xBA; //adcl的邏輯地址
adcdma.dstAddrH=(uint8)((uint16)&adctab>>8); //目標(biāo)內(nèi)存塊中的地址高位
adcdma.dstAddrL=(uint8)&adctab; //目標(biāo)內(nèi)存塊中的地址地位
adcdma.xferLenV=0x03; //
adcdma.xferLenL=0x20; //傳送0x320個(gè)字符
adcdma.ctrlA=0xd7; // word傳送 not bytes ;重復(fù)單次傳送;1號(hào)差分通道結(jié)束后觸發(fā)
adcdma.ctrlB=0x10; //目的地址自動(dòng)加1,中斷不打開。
DMA0CFGL=(uint8)&adcdma; //將0號(hào)dma通道設(shè)置為上述結(jié)構(gòu)
DMA0CFGH=(uint8)((uint16)&adcdma>>8);
DMAARM=0x01; //投入0號(hào)dma通道asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
adctemp = channel | resbits | (refvolt<<6);
ADCCON2 = adctemp;
ADC_SAMPLE_CONTINUOUS();
tmp=0;
while (!(DMAIRQ & 0x01));
DMAARM|=(1<<7);
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
DMAIRQ=0;
ADC_STOP(); //轉(zhuǎn)換結(jié)束 ,至此所有800次AD轉(zhuǎn)換的值已經(jīng)存在adctab中了。
tmp=ADCL;
tmp=ADCH;
ADCCFG &= ~adcChannel;
sum=0;
sum1=0;
max=0;
tmp1=0;
X=-1;
lst=-1;
for(i=0;i<800;i++)
{
//int AdtoInt(uint16 adctmp,int offset)
//轉(zhuǎn)換成int
tmp1=AdtoInt(adctab[i],(int)ADoffset2);
//存儲(chǔ)到原來(lái)的空間里
adctab[i]=(uint16)tmp1;
//判斷過零點(diǎn)
if((i>0) && ( *((int*)(adctab+i))<0) && (*((int*)(adctab+i-1))>=0))
{
if(X==-1)
{
n=(int)i;
lst=(int)i;
X=0;
}
else
{
if((i-lst)>120)
{
X++;
lst=i;
}
}
if(X==4)
{
m=(int)i;
}
}
//取絕對(duì)值
if(tmp1<0)
{
tmp1=0-tmp1;
}
//累加
if(X>=0 && X<4)
{
sum+=(float)tmp1;
}
//取最大值
if(tmp1>max)
{
max=tmp1;
}
sum1+=(float)tmp1;
}
osal_int_enable(INTS_ALL);
// 最大值如果小于 0x2000的5%則有可能雜波干擾比較大,真正的過零點(diǎn)難找,而又因?yàn)橹挥?%,所以累加后求平均值對(duì)最后的計(jì)算結(jié)果影響很小
if(max<410)
{
return (sum1/800);
}
else
{
return (sum/(m-n));
}
};
//將無(wú)符號(hào)整數(shù)轉(zhuǎn)換為int 大于0x1fff的為負(fù)數(shù) 偏移量要從float轉(zhuǎn)成int
int AdtoInt(volatile uint16 adctmp,int offset)
{
int tmp1;
adctmp=(adctmp<<8)|(adctmp>>8);
adctmp>>=2;
if(adctmp>8191)
{
tmp1=(int)adctmp-0x4000-offset;
}
else
{
tmp1=(int)adctmp-offset;
}
return tmp1;
}
五、至此我使用cc2430AD轉(zhuǎn)換的心得已經(jīng)講完了,希望對(duì)大家的開發(fā)工作有點(diǎn)幫助。
評(píng)論