單片機是一個典型的數字系統。數字系統只能對輸入的數字信號進行處理,但是在工業檢測系統和日常生活中的許多物理量都是模擬量,這些模擬量可以通過傳感器變成與之對應的數字量便于處理和顯示。
A/D和D/A的基本概念
A/D是模擬量到數字量的轉換,依靠的是模數轉換器(Analog to Digital Converter),簡稱ADC。D/A是數字量到模擬量的轉換,依靠的是數模轉換器(Digital to Analog Converter),簡稱DAC。本項目中主要以A/D為例。
模擬量是指變量在一定范圍內連續變化的量,在任意時刻都有相應的值與之對應。比如天氣溫度值,在每時每刻都有溫度值,也稱之為連續變化的量。相對應的是數字量,數字量只有在特定的時間才有相對應的值,由于有一定的間隔,不是連續的,也稱之為離散。ADC就是把連續的信號用離散的數字表達出來。
A/D的主要指標
在選取和使用A/D的時候,依靠什么指標來判斷很重要。由于AD的種類很多,分為積分型、逐次逼近型、并行/串行比較型等多種類型,同時指標也比較多,介紹常用的三種。
1、ADC的位數
一個n位的ADC表示這個ADC共有2的n次方個刻度。8位的ADC,輸出的是從0~255一共256個數字量,也就是2的8次方個數據刻度。
2、基準源
基準源,也叫基準電壓,是ADC的一個重要指標,要想把輸入ADC的信號測量準確,那么基準源首先要準,基準源的偏差會直接導致轉換結果的偏差。
3、分辨率
分辨率是數字量變化一個最小刻度時,模擬信號的變化量,定義為滿刻度量程與2n-1的比值。假定5.10V的電壓系統,使用8位的ADC進行測量,那么相當于0~255一共256個刻度把5.10V平均分成了255份,那么分辨率就是5.10/255 = 0.02V。
PCF8591模塊硬件應用說明
PCF8591是Philips公司的產品,是一個單電源低功耗的8位CMOS數據采集器件,具有4路模擬輸入,1路模擬輸出和一個串行I2C總線接口用來與單片機通信,該模塊從某寶采購,如圖1所示,該模塊共有8個引腳,在本項目中接左側的SCL、SDA、GND、VCC即可。
具有16引腳的芯片即為PCF8591,原理圖如圖2所示。該芯片允許最多8個器件連接到I2C總線而不需要額外的片選電路。器件的地址、控制以及數據都是通過I2C總線來傳輸,PCF8591的ADC是逐次逼近型,轉換速度取決于I2C的通信速率。由于I2C速度的限制,所以PCF8591是低速的AD和DA集成,主要應用在一些轉換速度要求不高,希望成本較低的場合,比如電池供電設備,測量電池的供電電壓。
圖2 PCF8591芯片連接原理圖
圖2中引腳1、2、3、4是4路模擬輸入,對應的實物是圖1中的右側引腳,通過絲印層即可觀察得到。5、6、7引腳對應A0、A1、A2,是I2C總線的硬件地址,用于編程硬件地址,8腳是數字地GND,9腳和10腳是I2C總線的SDA和SCL。12腳是時鐘選擇引腳,如果接高電平表示用外部時鐘輸入,接低電平則用內部時鐘,電路用的是內部時鐘,因此12腳直接接GND,同時11腳懸空。13腳是模擬地AGND,在實際開發中,如果有比較復雜的模擬電路,那么AGND部分在布局布線上要特別處理,而且和GND的連接也有多種方式。在板子上沒有復雜的模擬部分電路,所以把AGND和GND接到一起。14腳是基準源,15腳是DAC的模擬輸出,16腳是供電電源VCC。
14腳Vref基準電壓的提供有兩種方法。一是采用簡易的原則,直接接到VCC上去,但是由于VCC會受到整個線路的用電功耗情況影響,相對來說并不是很準確,通常用于精度要求不高的場合。方法二是使用專門的基準電壓器件,比如TL431,它可以提供一個精度很高的2.5V的電壓基準,本項目中采用方法一。
** PCF8591模塊使用說明(淘寶購買)**
模塊共有3個黑色短路帽,如圖1 PCF8591模塊所示,通過絲印層觀察可見J4、J5、J6,相應的原理圖如圖3所示,分別作用如下:
P5接上P5短路帽,選擇光敏電阻接入電路,AN0通路;
P6接上P6短路帽,選擇0-5V可調電壓接入電路,AN3通路;
由于在本實驗中讀取該3路的具體值,所以實驗中并未取下短路帽。
圖3 模塊引腳連接方式
這里需要注意的是AN3雖然測的是+5V的值,但是對于AD來說,只要輸入信號超過Vref基準源,它得到的始終都是最大值,即255,也就是說它實際上無法測量超過其Vref的電壓信號。需要注意的是,所有輸入信號的電壓值都不能超過VCC,即+5V,否則可能會損壞ADC芯片。
注:如果需要使用四路外部電壓輸入,請將3個紅色短路帽都取下。
模塊功能描述(資料中帶有)
1、模塊支持外部4路電壓輸入采集(電壓輸入范圍 0-5v);
2、模塊集成光敏電阻,可以通過AD采集環境光強精確數值;
3、模塊集成熱敏電阻,可以通過AD采集環境溫度精確數值;
4、模塊集成1路0-5V電壓輸入采集(通過藍色電位器調節輸入電壓);
5、模塊帶電源指示燈(對模塊供電后指示燈會亮);
6、模塊帶DA輸出指示燈,當模塊DA輸出接口電壓達到一定值,會點亮板上DA輸出指示燈,電壓越大,指示燈亮度越明顯;
7、模塊PCB尺寸:3.6cm*2.3cm;
8、標準雙面板,板厚1.6mm,布局美觀大方,四周設有通孔,孔徑為:3mm,方便固定。
** PCF8591的軟件編程**
PCF8591的通信接口是I2C。單片機對PCF8591進行初始化,一共發送三個字節即可。第一個字節是器件地址字節,其中7位代表地址,1位代表讀寫方向(最低位),“0”表示主機向從機寫數據,“1”表示主機向從機讀數據。地址高4位固定是0b1001,低三位是A2,A1,A0,這三位電路上都接了GND,因此也就是0b000,如圖4所示。
圖4 PCF8591地址字節
在程序中有這么一段代碼,0x48是由高四位和低3位組成的,即0b1001000,由于讀寫位在第0位,所以需要整體左移一位,程序中if用于判斷是否存在該器件,如果不存在則I2CWrite函數返回1,則執行I2CStop();return 0;這兩條語句,return函數會結束當前函數;反之,返回0,略過if語句,繼續執行下面的語句。
if(I2CWrite(0x48< 1))
{
I2CStop();
return 0;
}
發送到PCF8591的第二個字節將被存儲在控制寄存器,用于控制PCF8591的功能。其中第3位和第7位是固定的0,另外6位各自有各自的作用,如圖5所示。
圖5 PCF8591 控制字節
控制字節的第6位是DA使能位,這一位置1表示DA輸出引腳使能,會產生模擬電壓輸出功能。第4位和第5位可以實現把PCF8591的4路模擬輸入配置成單端模式和差分模式,這里只需要知道這兩位是配置AD輸入方式的控制位即可,如圖6所示,本項目中采用“00”模式。
圖6 PCF8591模擬輸入配置方式
控制字節的第2位是自動增量控制位,自動增量的意思就是,比如一共有4個通道,當全部使用的時候,讀完了通道0,下一次再讀,會自動進入通道1進行讀取,不需要我們指定下一個通道,由于A/D每次讀到的數據,都是上一次的轉換結果,所以在使用自動增量功能的時候,要特別注意,當前讀到的是上一個通道的值!
控制字節的第0位和第1位就是通道選擇位,00、01、10、11代表了從0到3的一共4個通道選擇。
發送給PCF8591的第三個字節D/A數據寄存器,表示D/A模擬輸出的電壓值。如果僅僅使用A/D功能的話,就可以不發送第三個字節。
I2C總線與通訊時序的介紹
在項目六中接觸到了第一種通信協議----UART異步串行通信,本項目中學習第二種通信協議----I2C。I2C總線是由PHILIPS公司開發的兩線式串行總線,多用于連接微處理器及其外圍芯片。I2C總線的主要特點是接口方式簡單,兩條線可以掛多個參與通信的器件,即多機模式,而且任何一個器件都可以作為主機,當然同一時刻只能有一個主機。I2C屬于同步通信,SCL時鐘線負責收發雙方的時鐘節拍,SDA數據線負責傳輸數據。I2C的發送方和接收方都以SCL這個時鐘節拍為基準進行數據的發送和接收。在本項目中,I2C用于單片機和PCF8591之間的通信。
** I2C尋址模式**
I2C通信在字節級的傳輸中,也有固定的時序要求。I2C通信的起始信號(Start)后,首先要發送一個從機的地址,這個地址一共有7位,緊跟著的第8位是數據方向位(R/W),“0”表示接下來要發送數據(寫),“1”表示接下來是請求數據(讀)。
當發送完了這7位地址和1位方向后,如果發送的這個地址確實存在,那么這個地址的器件應該回應一個ACK(拉低SDA即輸出“0”),如果不存在,就沒“人”回應ACK(SDA將保持高電平即“1”)。ACK類似在打電話的時候,當撥通電話,接聽方撿起電話肯定要回一個“喂”,這就是告訴撥電話的人,這邊有人了。同理,這個第九位ACK實際上起到的就是這樣一個作用。
在前面提到PCF8591的7位地址中高4位固定是0b1001,緊接低三位是A2,A1,A0,這三位電路上都接了GND,因此也就是0b000,因此PCF8591的7位地址實際上是二進制的0b1001000,也就是0x48。
I2C時序認識
I2C總線是由時鐘總線SCL和數據總線SDA兩條線構成,所有器件的SCL都連到一起,所有SDA都連到一起。I2C總線是開漏引腳并聯的結構,因此外部要添加上拉電阻。對于開漏電路外部加上拉電阻,就組成了線“與”的關系。總線上線“與”的關系就是說,所有接入的器件保持高電平,這條線才是高電平,而任何一個器件輸出一個低電平,那這條線就會保持低電平,因此可以做到任何一個器件都可以拉低電平,也就是任何一個器件都可以作為主機,如圖2所示,添加了R8和R9兩個上拉電阻。
I2C在通信過程中有起始信號、數據傳輸和停止信號,如圖7所示。
圖7 I2C通信流程解析
I2C分為起始信號、數據傳輸部分、停止信號。其中數據傳輸部分,可以一次通信過程傳輸很多個字節,字節數是不受限制的,而每個字節的數據最后也跟了一位,這一位叫做應答位,通常用ACK表示應答,NACK表示非應答。
起始信號:UART通信是從一直持續的高電平出現一個低電平標志起始位;而I2C通信的起始信號的定義是SCL為高電平期間,SDA由高電平向低電平變化產生一個下降沿,表示起始信號,如圖7中的Start部分所示,相應的代碼如下所示。
void I2CStart()
{
I2C_SDA = 1; //首先確保 SDA、SCL都是高電平
I2C_SCL = 1;
Delay();
I2C_SDA = 0; //先拉低 SDA
Delay();
I2C_SCL = 0; //再拉低 SCL
}
根據程序的時序圖較易理解,程序中使用了Delay()函數,那么Delay()延時多少時間?在程序定義中可以看到。
#define Delay() { nop (); nop (); nop (); nop (); nop ();}
一個_nop_()表示大概是一個機器周期,約為5us,為什么是這個值?根據PCF8591操作手冊要求,如圖8所示,需要持續tHD;STA 的時間,結合圖9,tHD;STA 的最小值為4us,沒有最大值,從圖9中還可以看到有的需要持續5us,所以統一方便定義Delay()的時間為5個_nop_()。
圖8 I2C總線時間限制圖
圖9 具體時間分布圖
數據傳輸:I2C通信是高位在前,低位在后。I2C不像UART有固定波特率,但是有時序要求:當SCL在低電平的時候,SDA允許變化,也就是說,發送方必須先保持SCL是低電平,才可以改變數據線SDA,輸出要發送的當前數據的一位;而當SCL在高電平的時候,SDA絕對不可以變化,因為這個時候,接收方要來讀取當前SDA的電平信號是0還是1,因此要保證SDA的穩定,如圖7中的每一位數據的變化,都是在SCL的低電平位置。8位數據位后邊跟著的是一位應答位。
數據傳輸又分為兩種:主機向從機寫數據和主機向從機讀取數據,再次強調下一般來說單片機為主機,從機為24C02、PCF8591等具備I2C協議的專用芯片。
1、當讀數據的時候,從設備每發送完8個數據位,如果主機繼續讀下一個字節,主機應該回答“ACK”以提示從機準備下一個數據,如果主機不希望讀取更多字節,主機應該回答“NACK”以提示從機設備準備接收Stop信號。
2、當寫數據的時候,主機每發送完8個數據位,從機設備如果還要一個字節應該回答“ACK”,從機設備如果不接受更多的字節應該回答“NACK”,主機當收到“NACK”或者一定時間之后沒收到任何數據將視為超時,此時主機放棄數據傳送。
3、無論是讀數據還是寫數據,都是主機動作!
根據讀操作特點編寫以下程序,I2CReadACKORNOT函數中的參數為1表示繼續讀下一字節,根據函數可知此時回答的是“ACK”;反之,為非1時,主機回應了“NACK”。不同于UART協議,I2C傳輸數據從高位開始,程序中巧妙地設置了BitCnt的值為0x80,對應的二進制為0b1000 0000,如果此時從機傳給主機的值為0,那么“dat &= ~BitCnt”后,dat的最高位為0,如果從機傳給主機的值為1,那么“dat |= BitCnt t”后,dat的最高位為1。一次循環后BitCnt>>=1,此時BitCnt的值為0x40,對應的二進制為0b0100 0000。通過此方式,依次讀取出從機傳給主機的數據,最后函數返回dat值!
unsigned char I2CReadACKORNOT(bit cnt)
{
unsigned char BitCnt;
unsigned char dat;
I2C_SDA = 1; //首先確保主機釋放SDA
for (BitCnt=0x80; BitCnt!=0; BitCnt >?>=1) //從高位到低位依次進行
{
Delay();
I2C_SCL = 1; //拉高SCL
if(I2C_SDA == 0) //讀取SDA的值
dat &= ~BitCnt; //為0時,dat中對應位清零
else
dat |= BitCnt; //為1時,dat中對應位置1
Delay();
I2C_SCL = 0; //再拉低SCL,以使從機發送出下一位
}
if(cnt)
I2C_SDA = 0; //8位數據發送完后,拉低SDA,發送應答信號
else
I2C_SDA = 1;
Delay();
I2C_SCL = 1; //拉高SCL
Delay();
I2C_SCL = 0; //再拉低SCL完成應答位,并保持住總線
return dat;
}
對于寫操作類似,不在此重復敘述。
停止信號:I2C通信停止信號的定義是SCL為高電平期間,SDA由低電平向高電平變化產生一個上升沿,表示結束信號,如圖7中的Stop部分所示,相應的代碼如下所示。
void I2CStop()
{
I2C_SCL = 0; //首先確保SDA、SCL都是低電平
I2C_SDA = 0;
Delay();
I2C_SCL = 1; //先拉高 SCL
Delay();
I2C_SDA = 1; //再拉高 SDA
Delay();
}
實現現象:
采集PCF8591模塊的3路信號。
評論
查看更多