性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

ReCclay
認(rèn)證:VIP會員
所在專題目錄 查看專題
【藍(lán)橋杯單片機組模塊】2、以 LED 流水燈為例,熟悉 CT107D 外設(shè)驅(qū)動套路
【藍(lán)橋杯單片機組模塊】3、上手 CT107D 外設(shè)驅(qū)動之?dāng)?shù)碼管模塊
【藍(lán)橋杯單片機組模塊】4、按鍵模塊
【藍(lán)橋杯單片機組模塊】5、EEPROM模塊
【藍(lán)橋杯單片機組模塊】6、AD/DA轉(zhuǎn)換模塊
【藍(lán)橋杯單片機組模塊】7、DS18B20溫度傳感器模塊
作者動態(tài) 更多
【FPGA基礎(chǔ)】基于 Pango Design Suite(PDS) 的FPGA開發(fā)流程
2021-05-14 11:22
【FPGA基礎(chǔ)】基于Quartus Prime 17.1 的FPGA開發(fā)流程
2021-05-08 17:49
【AD快速入門】8051最小系統(tǒng)繪制
2021-04-22 10:03
藍(lán)橋嵌入式之 ADC電壓采集與顯示
2021-04-14 11:48
藍(lán)橋嵌入式之 實時時鐘RTC
2021-04-13 14:50

【藍(lán)橋杯單片機組模塊】6、AD/DA轉(zhuǎn)換模塊

?導(dǎo)讀:《藍(lán)橋杯單片機組》專欄文章是博主2018年參加藍(lán)橋杯的單片機組比賽所做的學(xué)習(xí)筆記,在當(dāng)年的比賽中,博主是獲得了省賽一等獎,國賽二等獎的成績。成績雖談不上最好,但至少問心無愧。如今2021年回頭再看該系列文章,仍然感觸頗多。為了能更好地幫助到單片機初學(xué)者,今年特地抽出時間對當(dāng)年的文章邏輯和結(jié)構(gòu)進行重構(gòu),以達到初學(xué)者快速上手的目的。需要指出的是,由于本人水平有限,如有錯誤還請讀者指出,非常感謝。那么,接下來讓我們一起開始愉快的學(xué)習(xí)吧。

前面的學(xué)習(xí)中,我們依次突破了單片機初學(xué)過程中的兩個難點:中斷和時序。今天在此基礎(chǔ)上,我們繼續(xù)來學(xué)習(xí)一下ADC模塊,即:數(shù)模/模數(shù)轉(zhuǎn)換模塊。關(guān)于數(shù)模和模數(shù)的概念如果學(xué)過了數(shù)電,那理解起來自然沒有難度。如果第一次接觸,還是要花點時間好好消化下的。廢話不多說,馬上開始搞,今天使用的AD/DA轉(zhuǎn)換模組是:PCFPCF8591,代碼下載到Github<傳送門>。

一、基礎(chǔ)理論

1.1、A/D 重要指標(biāo)

1、ADC 的位數(shù) 一個 n 位的 ADC 表示這個 ADC 共有 2 的 n 次方個刻度。8 位的 ADC,輸出的是從 0~255 一共 256 個數(shù)字量,也就是 2 的 8 次方個數(shù)據(jù)刻度。

2、基準(zhǔn)源 基準(zhǔn)源,也叫基準(zhǔn)電壓,是 ADC 的一個重要指標(biāo),要想把輸入 ADC 的信號測量準(zhǔn)確,那么基準(zhǔn)源首先要準(zhǔn),基準(zhǔn)源的偏差會直接導(dǎo)致轉(zhuǎn)換結(jié)果的偏差。比如一根米尺,總長度本應(yīng)該是 1 米,假定這根米尺被火烤了一下,實際變成了 1.2 米,再用這根米尺測物體長度的話自然就有了較大的偏差。假如我們的基準(zhǔn)源應(yīng)該是 5.10V,但是實際上提供的卻是 4.5V,這樣誤把 4.5V 當(dāng)成了 5.10V 來處理的話,偏差也會比較大。

3、分辨率 分辨率是數(shù)字量變化一個最小刻度時,模擬信號的變化量,定義為滿刻度量程與 2^n -1 的比值。假定 5.10V 的電壓系統(tǒng),使用 8 位的 ADC 進行測量,那么相當(dāng)于 0~255 一共 256 個刻度把 5.10V 平均分成了 255 份,那么分辨率就是 5.10/255 = 0.02V。

分辨率和精度并不是一個概念,詳細(xì)看這里。

4、INL(積分非線性度)和 DNL(差分非線性度)

ADC精度關(guān)系重大的兩個指標(biāo)是INL(IntegralNonLiner)和 DNL(Differencial NonLiner) INL 指的是 ADC 器件在所有的數(shù)值上對應(yīng)的模擬值,和真實值之間誤差最大的那一個點的誤差值,是 ADC 最重要的一個精度指標(biāo),單位是 LSB。

LSB(Least Significant Bit)是最低有效位的意思,那么它實際上對應(yīng)的就是 ADC的分辨率。一個基準(zhǔn)為5.10V的8位ADC,它的分辨率就是 0.02V,用它去測量一個電壓信號,得到的結(jié)果是 100,就表示它測到的電壓值是 100*0.02V=2V,假定它的 INL 是 1LSB,就表示這個電壓信號真實的準(zhǔn)確值是在1.98V~2.02V 之間的,按理想情況對應(yīng)得到的數(shù)字應(yīng)該是 99~101,測量誤差是一個最低有效位,即 1LSB。

DNL 表示的是 ADC 相鄰兩個刻度之間最大的差異,單位也是 LSB。一把分辨率是 1 毫米的尺子,相鄰的刻度之間并不都剛好是 1 毫米,而總是會存在或大或小的誤差。同理,一個 ADC 的兩個刻度線之間也不總是準(zhǔn)確的等于分辨率,也是存在誤差,這個誤差就是 DNL。

一個基準(zhǔn)為 5.10V 的 8 位 ADC,假定它的 DNL 是 0.5LSB,那么當(dāng)它的轉(zhuǎn)換結(jié)果從 100 增加到 101 時,理想情況下實際電壓應(yīng)該增加 0.02V,但 DNL 為 0.5LSB 的情況下實際電壓的增加值是在 0.01~0.03V 之間。值得一提的是 DNL 并非一定小于 1LSB,很多時候它會等于或大于 1LSB,這就相當(dāng)于是一定程度上的刻度紊亂,當(dāng)實際電壓保持不變時,ADC 得出的結(jié)果可能會在幾個數(shù)值之間跳動,很大程度上就是由于這個原因(但并不完全是,因為還有無時無處不在的干擾的影響)。

5、轉(zhuǎn)換速率 轉(zhuǎn)換速率,是指 ADC 每秒能進行采樣轉(zhuǎn)換的最大次數(shù),單位是 sps (或 s/s、sa/s,即 samplesper second),它與 ADC 完成一次從模擬到數(shù)字的轉(zhuǎn)換所需要的時間互為倒數(shù)關(guān)系。ADC 的種類比較多,其中積分型的 ADC 轉(zhuǎn)換時間是毫秒級的,屬于低速 ADC;逐次逼近型 ADC轉(zhuǎn)換時間是微秒級的,屬于中速 ADC;并行/串行的 ADC 的轉(zhuǎn)換時間可達到納秒級,屬于高速 ADC。

1.2、PCF8591介紹

PCF8591 是一個單電源低功耗的 8 位 CMOS 數(shù)據(jù)采集器件,具有 4 路模擬輸入,1 路模擬輸出和一個串行 I 2 C 總線接口用來與單片機通信。與前面講過的 24C02 類似,3 個地址引腳 A0、A1、A2 用于編程硬件地址,允許最多 8 個器件連接到 I 2 C 總線而不需要額外的片選電路。器件的地址、控制以及數(shù)據(jù)都是通過 I 2 C 總線來傳輸

這里寫圖片描述

其中引腳 1、2、3、4 是 4 路模擬輸入,引腳 5、6、7 是 I 2 C 總線的硬件地址,8 腳是數(shù)字地 GND,9 腳和 10 腳是 I 2 C 總線的 SDA 和 SCL。12 腳是時鐘選擇引腳,如果接高電平表示用外部時鐘輸入,接低電平則用內(nèi)部時鐘,我們這套電路用的是內(nèi)部時鐘,因此 12 腳直接接 GND,同時 11 腳懸空。13 腳是模擬地 AGND,在實際開發(fā)中,如果有比較復(fù)雜的模擬電路,那么 AGND 部分在布局布線上要特別處理,而且和 GND 的連接也有多種方式,這個板子上沒有復(fù)雜的模擬部分電路,所以我們把 AGND 和 GND 接到一起。14 腳是基準(zhǔn)源,15 腳是 DAC 的模擬輸出,16 腳是供電電源 VCC。

PCF8591 的 ADC 是逐次逼近型的,轉(zhuǎn)換速率算是中速,但是它的速度瓶頸在 I 2 C 通信上。由于 I 2 C 通信速度較慢,所以最終的 PCF8591 的轉(zhuǎn)換速度,直接取決于 I 2 C 的通信速率。由于 I 2 C 速度的限制,所以 PCF8591 得算是個低速的 AD 和 DA 的集成,主要應(yīng)用在一些轉(zhuǎn)換速度要求不高,希望成本較低的場合,比如電池供電設(shè)備,測量電池的供電電壓,電壓低于某一個值,報警提示更換電池等類似場合。

ref 基準(zhǔn)電壓的提供有兩種方法。一是采用簡易的原則,直接接到 VCC 上去,但是由于 VCC 會受到整個線路的用電功耗情況影響,一來不是準(zhǔn)確的 5V,實測大多在 4.8V 左右,二來隨著整個系統(tǒng)負(fù)載情況的變化會產(chǎn)生波動,所以只能用在簡易的、對精度要求不高的場合。方法二是使用專門的基準(zhǔn)電壓器件,比如 TL431,它可以提供一個精度很高的 2.5V 的電壓基準(zhǔn)。

這里寫圖片描述

藍(lán)橋的板子是直接接到VCC上的,不過它還進行了并聯(lián)電容的處理。

這里寫圖片描述

對于AD 來說,只要輸入信號超過 Vref 基準(zhǔn)源,它得到的始終都是最大值,即 255,也就是說它實際上無法測量超過其 Vref 的電壓信號的。需要注意的是,所有輸入信號的電壓值都不能超過 VCC,即+5V,否則可能會損壞 ADC 芯片。(注意Vref和VCC不一定相等,它取決于你采用哪種方式接線!)

1.3、PCF8591編程介紹

PCF8591 的通信接口是 I 2 C,那么編程肯定是要符合這個協(xié)議的。單片機對 PCF8591 進行初始化,一共發(fā)送三個字節(jié)即可!

第一個字節(jié):器件地址字節(jié)

這里寫圖片描述

其中 7 位代表地址,1 位代表讀寫方向。地址高 4 位固定是 0b1001,低三位是 A2,A1,A0,這三位我們電路上都接了 GND,因此也就是 0b000。

第二個字節(jié):器件控制字節(jié)

控制字節(jié)的第 6 位是 DA 使能位,這一位置 1 表示 DA 輸出引腳使能,會產(chǎn)生模擬電壓輸出功能。

第4位和第5位可以實現(xiàn)把PCF8591的4路模擬輸入配置成單端模式和差分模式,是配置 AD輸入方式的控制位。單端模式和差分模式的區(qū)別。

控制字節(jié)的第 2 位是自動增量控制位,自動增量的意思就是,比如我們一共有 4 個通道,當(dāng)我們?nèi)渴褂玫臅r候,讀完了通道 0,下一次再讀,會自動進入通道 1 進行讀取,不需要我們指定下一個通道。

注意:由于 A/D 每次讀到的數(shù)據(jù),都是上一次的轉(zhuǎn)換結(jié)果,所以在使用自動增量功能的時候,要特別注意,當(dāng)前讀到的是上一個通道的值。 為了保持程序的通用性,代碼沒有使用這個功能,而是直接做了一個通用的程序,可以參考一下!

具體實現(xiàn): 程序在進行 A/D 讀取數(shù)據(jù)的時候,共使用了兩條程序去讀了 2 個字節(jié):I2CReadACK(); val = I2CReadNAK(); PCF8591 的轉(zhuǎn)換時鐘是 I2C 的 SCL,8 個SCL 周期完成一次轉(zhuǎn)換,所以當(dāng)前的轉(zhuǎn)換結(jié)果總是在下一個字節(jié)的 8 個 SCL 上才能讀出,因此我們這里第一條語句的作用是產(chǎn)生一個整體的 SCL 時鐘提供給 PCF8591 進行 A/D 轉(zhuǎn)換,第二次是讀取當(dāng)前的轉(zhuǎn)換結(jié)果。如果我們只使用第二條語句的話,每次讀到的都是上一次的轉(zhuǎn)換結(jié)果。

控制字節(jié)的第 0 位和第 1 位就是通道選擇位了,00、01、10、11 代表了從 0 到 3 的一共4 個通道選擇。

第三個字節(jié) D/A 數(shù)據(jù)寄存器

如果僅僅使用A/D功能,這一個字節(jié)可不進行控制!

二、動手實驗

2.1、ADC實驗中對應(yīng)的一段核心代碼!

u8 GetADCValue(u8 ch)
{
	u8 val;

	I2CStart();
	if(I2CWrite(0x48<<1) == 0) //尋器件地址 - 寫
	{
	 	I2CStop();
		return 0;  //這里并不像I2C那樣使用break,現(xiàn)在是讀東西,讀不到就得返回0.
	}
	I2CWrite(0x40 | ch);//對應(yīng)單端模式 - 通道數(shù)
	I2CStart();
	I2CWrite((0x48<<1) | 0x01);//尋器件地址 - 讀
	I2CReadACK();
	val = I2CReadNAK();//這次的值,是在下8個SCL輸出,所以先空讀然后再去NAK讀!
	I2CStop();

	return val;	
}

void ValueToString(u8 *str, u8 val)//!!注意這里的處理技巧,把電壓擴大了10倍?。?!
{
 	val = (val*50) / 255;  //電壓5V,256個刻度分成255份!
	str[0] = (val/10) + '0';
	str[1] = '.';
	str[2] = (val%10) + '0';
	str[3] = 'V';
	str[4] = '\0';
}

2.2、DAC當(dāng)然也有重點!

void SetDACOut(u8 val)
{
 	I2CStart();
	if(!I2CWrite(0x48<<1))
	{
	 	I2CStop();
		return;
	}
	I2CWrite(0x40);
	I2CWrite(val);
	I2CStop();
}

void KeyAction(u8 keycode)
{
	static u8 volt = 0;
	
	if(keycode == 0x26)
	{
	 	if(volt < 50)
		{
		 	volt++;
			SetDACOut((volt*255)/50);//輸入數(shù)字量,注意區(qū)別ADC的公式!
		}
	}	
	else if(keycode == 0x28)
	{
	 	if(volt > 0)
		{
		 	volt--;
			SetDACOut((volt*255)/50);//輸入數(shù)字量,注意區(qū)別ADC的公式!
		}
	}
}

2.3、DAC做的波形發(fā)生器!

u8 code SinWave[] = {  //正弦波波表
    127, 152, 176, 198, 217, 233, 245, 252,
    255, 252, 245, 233, 217, 198, 176, 152,
    127, 102,  78,  56,  37,  21,   9,   2,
      0,   2,   9,  21,  37,  56,  78, 102,
};
u8 code TriWave[] = {  //三角波波表
      0,  16,  32,  48,  64,  80,  96, 112,
    128, 144, 160, 176, 192, 208, 224, 240,
    255, 240, 224, 208, 192, 176, 160, 144,
    128, 112,  96,  80,  64,  48,  32,  16,
};
u8 code SawWave[] = {  //鋸齒波表
      0,   8,  16,  24,  32,  40,  48,  56,
     64,  72,  80,  88,  96, 104, 112, 120,
    128, 136, 144, 152, 160, 168, 176, 184,
    192, 200, 208, 216, 224, 232, 240, 248,
};

.....

void SetWaveFreq(u8 freq)
{
	u32 tmp;

	tmp = (11059200/12) / (freq*32); //計數(shù)器計數(shù)頻率是波形頻率的32倍!
	tmp = 65536 - tmp;
	T1RH = (u8)(tmp>>8);
	T1RL = (u8)tmp;
	TMOD &= 0x0F;
	TMOD |= 0x10;
	TH1 = T1RH;
	TL1 = T1RL;
	ET1 = 1;
	PT1 = 1; //設(shè)置高優(yōu)先級!
	TR1 = 1;
}

...

void InterrupTimer1() interrupt 3
{
 	static u8 i=0;

	TH1 = T1RH;
	TL1 = T1RL;
	SetDACOut(pWave[i]);
	i++;
	if(i >= 32)
	{
	 	i=0;
	}
}

上面關(guān)鍵是看void SetWaveFreq(u8 freq)的實現(xiàn)!

2.4、賽前封裝的PCF8591函數(shù)相關(guān)

#include "config.h"
#include "i2c.h"

#define VCC 48//電壓是擴大10倍以后的電壓。。注意此處的電壓是實測的電壓值!?。?
u8 GetADCValue(u8 ch)
{
	u8 val;

	I2CStart();
	if(!(I2CWrite(0x48<<1)))
	{
	 	I2CStop();
		return 0;
	}	
	I2CWrite(0x40|ch);
	I2CStart();
	I2CWrite((0x48<<1) | 0x01);
	I2CReadACK();
	val = I2CReadNAK();
	I2CStop();

	val = (val*VCC)/255;//val擴大十倍,手動加小數(shù)點

	return val;
}

void SetDACOut(u8 val)//輸入也是一樣的道理,默認(rèn)輸入擴大十倍,然后處理.
{
	val = (val*255)/VCC;

 	I2CStart();
	if(!(I2CWrite(0x48<<1)))
	{
	 	I2CStop();
		return;
	}	
	I2CWrite(0x40);
	I2CWrite(val);
	I2CStop();
}	

GetADCValue在獲取相關(guān)的AD值以后,然后進行了轉(zhuǎn)換再輸出!

SetDACOut是直接設(shè)置相關(guān)的DA值,注意輸入的是擴大十倍以后的電壓值!

藍(lán)橋板子的AIN×輸入介紹:

AIN0:是接到右邊排針上,可以用杜邦線連外部模擬電壓信號 AIN1:是接到光敏電阻上 AIN2:放大器的輸出端 AIN3:是接到滑動變阻器Rb2上

注意DA功能輸出在右邊倒數(shù)第二個排針引腳上,D/A。倒數(shù)第三個排針是可以接外部任意電壓信號的口。

小結(jié):本篇文章主要介紹了單片機學(xué)習(xí)中的一個重頭戲:AD/DA操作,并結(jié)合了常見的AD/DA操作方式進行了詳細(xì)的介紹。在該部分學(xué)習(xí)中比較困難的就是模擬數(shù)字這個東西的理解,一個新的概念一次理解不到位也沒關(guān)系,多來幾次。相信在某一個瞬間,你也能有醍醐灌頂?shù)母杏X。

希望大家多多支持我的原創(chuàng)文章。如有錯誤,請大家及時指正,非常感謝。

聲明:本內(nèi)容為作者獨立觀點,不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 362
收藏 353
關(guān)注 431
成為作者 賺取收益
全部留言
0/200
  • dy-i2UfRuvP 2021-05-19 13:22
    請教一下
    回復(fù)
  • dy-iipPZRPN 2021-05-13 22:45
    圍觀學(xué)習(xí)
    回復(fù)
  • dy-3EbVR6Ei 2021-05-13 22:37
    精彩,很多東西還沒接觸到
    回復(fù)
  • dy-Xq2JxpfN 2021-05-13 22:19
    思路清晰,受益匪淺
    回復(fù)
  • dy-9g42stbW 2021-05-13 22:10
    感謝分享
    回復(fù)
  • dy-mLj7kl5v 2021-05-13 20:44
    期待繼續(xù)
    回復(fù)
  • dy-apcih3c1 2021-05-13 20:26
    不亞于看了一篇高質(zhì)量論文
    回復(fù)
  • dy-k78ZHtFD 2021-05-13 20:09
    大開眼界,真是好文
    回復(fù)
  • dy-nAWdnPGS 2021-05-13 18:56
    思路清晰,受益匪淺
    回復(fù)
  • dy-prSX6RBY 2021-05-13 18:48
    講的真好!
    回復(fù)
  • dy-jqGVYqsF 2021-05-13 16:53
    期待繼續(xù)
    回復(fù)
  • dy-VIQ9auhf 2021-05-13 15:06
    期待繼續(xù)
    回復(fù)
  • dy-7mura2gg 2021-05-13 14:50
    思路清晰,受益匪淺
    回復(fù)
  • dy-YN3DYTeH 2021-05-13 14:42
    不亞于看了一篇高質(zhì)量論文
    回復(fù)
  • dy-9hjGevyn 2021-05-13 13:58
    講的真好!
    回復(fù)
  • dy-H1WY5jXH 2021-05-13 13:25
    期待繼續(xù)
    回復(fù)
  • dy-wVQjSHHX 2021-05-13 13:09
    學(xué)習(xí)了
    回復(fù)
  • dy-88VlYaFf 2021-05-12 15:53
    不亞于看了一篇高質(zhì)量論文
    回復(fù)
  • dy-9QTV6UZW 2021-05-12 15:30
    思路清晰,受益匪淺
    回復(fù)
  • dy-WYS5BCmB 2021-05-12 15:16
    精彩,很多東西還沒接觸到
    回復(fù)