一、介紹
?? PCF8591 是單片箱蟆、單電源低功耗8位CMOS數(shù)據(jù)采集器件帮非,具有4個模擬輸入(其中一個為電壓模擬輸入)、一個模擬輸出和一個串行I2C總線接口博个。3個地址引腳A0怀樟、A1和A2用于編程硬件地址,允許將最多8個器件連接至I2C總線而不需要額外硬件盆佣。器件的地址往堡、控制和數(shù)據(jù)通過兩線雙向I2C總線傳輸。器件功能包括多路復(fù)用模擬輸入共耍、片上跟蹤和保持功能虑灰、8位模數(shù)轉(zhuǎn)換和8位數(shù)模擬轉(zhuǎn)換。最大轉(zhuǎn)換速率取決于I2C 總線的最高速率痹兜。
二穆咐、組件
★Raspberry Pi 3主板*1
★樹莓派電源*1
★40P軟排線*1
★PCF8591模數(shù)轉(zhuǎn)換器模塊*1
★雙色LED模塊*1
★面包板*1
★跳線若干
三、實(shí)驗(yàn)原理
??PCF8591模塊的工作原理比較復(fù)雜,斷斷續(xù)續(xù)一個多月時間才基本理清对湃,本文也經(jīng)過多次修改崖叫,以后也會不斷回頭補(bǔ)充。對于小白來說拍柒,先使用心傀,再明白就可以,不懂原理也不是天大的問題拆讯,只要堅(jiān)持學(xué)習(xí)脂男,總有一天會恍然大悟,后面也推薦有經(jīng)典教材供深入學(xué)習(xí)往果。若有疑問疆液,歡迎留言,看到了就會回復(fù)交流陕贮。
1堕油、I2C總線:
??I2C總線是由Philips公司開發(fā)的一種簡單、雙向二線制同步串行總線肮之。它只需要兩根線即可在連接于總線上的器件之間傳送信息掉缺。
??主器件用于啟動總線傳送數(shù)據(jù),并產(chǎn)生時鐘以開放傳送的器件戈擒,此時任何被尋址的器件均被認(rèn)為是從器件眶明。在總線上主和從、發(fā)和收的關(guān)系不是恒定的筐高,而取決于此時數(shù)據(jù)傳送方向搜囱。如果主機(jī)要發(fā)送數(shù)據(jù)給從器件,則主機(jī)首先尋址從器件柑土,然后主動發(fā)送數(shù)據(jù)至從器件蜀肘,最后由主機(jī)終止數(shù)據(jù)傳送;如果主機(jī)要接收從器件的數(shù)據(jù)稽屏,首先由主器件尋址從器件扮宠,然后主機(jī)接收從器件發(fā)送的數(shù)據(jù),最后由主機(jī)終止接收過程狐榔。在這種情況下坛增,機(jī)負(fù)責(zé)產(chǎn)生定時時鐘和終止數(shù)據(jù)傳送。
??SDA(串行數(shù)據(jù)線)和SCL(串行時鐘線)都是雙向I/O線薄腻,接口電路為開漏輸出收捣,需通過上拉電阻接電源VCC。當(dāng)總線空閑時.兩根線都是高電平庵楷,連接總線的外同器件都是CMOS(Complementary Metal Oxide Semiconductor互補(bǔ)金屬氧化物半導(dǎo)體)器件坏晦,輸出級也是開漏電路。在總線上消耗的電流很小,因此昆婿,總線上擴(kuò)展的器件數(shù)量主要由電容負(fù)載來決定,因?yàn)槊總€器件的總線接口都有一定的等效電容蜓斧。
??主器件用于啟動總線傳送數(shù)據(jù)仓蛆,并產(chǎn)生時鐘以開放傳送的器件,此時任何被尋址的器件均被認(rèn)為是從器件挎春。在總線上主和從看疙、發(fā)和收的關(guān)系不是恒定的,而取決于此時數(shù)據(jù)傳送方向直奋。如果主機(jī)要發(fā)送數(shù)據(jù)給從器件能庆,則主機(jī)首先尋址從器件,然后主動發(fā)送數(shù)據(jù)至從器件脚线,最后由主機(jī)終止數(shù)據(jù)傳送搁胆;如果主機(jī)要接收從器件的數(shù)據(jù),首先由主器件尋址從器件邮绿,然后主機(jī)接收從器件發(fā)送的數(shù)據(jù)渠旁,最后由主機(jī)終止接收過程。在這種情況下船逮,主機(jī)負(fù)責(zé)產(chǎn)生定時時鐘和終止數(shù)據(jù)傳送顾腊。
2、引腳定義:
本模塊左邊和右邊分別外擴(kuò)2路排針接口挖胃,分別說明如下:
右邊JP1杂靶, 5對接口:
左排是:
??AOUT 芯片DA輸出接口
??AINO 芯片模擬輸入接口0
??AIN1 芯片模擬輸入接口1
??AIN2 芯片模擬輸入接口2
??AIN3 芯片模擬輸入接口3
右排是:
??GND 接地
??GND 接地
??INPUT2 熱敏電阻接口
??INPUT1 光敏電阻接口
??INPUT0 電位計(jì)接口
左邊J1, 4個接口:
??SCL IIC時鐘接口 接樹莓派的scl口(接樹莓派 I2C1 SCL口)
??SDA IIC數(shù)字接口 接樹莓派的sda口(接單樹莓派 I2C1 SDA口)
??GND 模塊地 外接地(接樹莓派GND)
??VCC 電源接口 外接3.3v-5v (接樹莓派電源)
這里用的是5V酱鸭。
對應(yīng)的端口分別作用如下:
INPUT0端口 用短路帽接上AIN0吗垮,選擇0-5V可調(diào)電壓接入電路
INPUT1端口 用短路帽接上AIN1,選擇光敏電阻接入電路
INPUT2端口 用短路帽接上AIN2凛辣,選擇熱敏電阻接入電路
??PCF8591是具有I2C總線接口的8位A/D及D/A轉(zhuǎn)換器抱既。有4路A/D轉(zhuǎn)換輸入,1路D/A模擬輸出扁誓。I2C總線是Philips公司推出的串行總線防泵,整個系統(tǒng)僅靠數(shù)據(jù)線(SDA)和時鐘線(SCL)實(shí)現(xiàn)完善的全雙工數(shù)據(jù)傳輸,即CPU與各個外圍器件僅靠這兩條線實(shí)現(xiàn)信息交換蝗敢。I2C總線系統(tǒng)與傳統(tǒng)的并行總線系統(tǒng)相比具有結(jié)構(gòu)簡單捷泞、可維護(hù)性好、易實(shí)現(xiàn)系統(tǒng)擴(kuò)展寿谴、易實(shí)現(xiàn)模塊化標(biāo)準(zhǔn)化設(shè)計(jì)锁右、可靠性高等優(yōu)點(diǎn)。
AIN0~AIN3:模擬信號輸入端。
A0~A3:引腳地址端咏瑟。
VDD拂到、VSS:電源端(2.5~6V)
SDA、SCL:I2C總線的數(shù)據(jù)線码泞、時鐘線兄旬。
OSC:外部時鐘輸入端,內(nèi)部時鐘輸出端余寥。
EXT:內(nèi)部领铐、外部時鐘選擇線,使用內(nèi)部時鐘時EXT接地宋舷。
AGND:模擬信號地绪撵。
AOUT:D/A轉(zhuǎn)換輸出端。
VREF:基準(zhǔn)電源端祝蝠。
3音诈、第一字節(jié):器件地址
??PCF8591采用典型的I2C總線接口器件尋址方法,即總線地址由器件地址续膳、引腳地址和方向位組成改艇。飛利蒲公司規(guī)定A/D器件地址為1001。引腳地址為A2A1A0坟岔,其值由用戶選擇谒兄,因此I2C系統(tǒng)中最多可接23=8個具有I2C總線接口的A/D器件。地址的最后一位為方向位R/ 社付,當(dāng)主控器對A/D器件進(jìn)行讀操作時為1承疲,進(jìn)行寫操作時為0∨缚В總線操作時燕鸽,由器件地址、引腳地址和方向位組成的從地址為主控器發(fā)送的第一字節(jié)啼辣。
4啊研、第二字節(jié):控制字節(jié)
??控制字節(jié)用于控制器件的各種功能,如模擬信號由哪幾個通道輸入等鸥拧〉吃叮控制字節(jié)存放在控制寄存器中,總線操作時為主控器發(fā)送的第二字節(jié)富弦。其格式如下所示:
其中:
D1沟娱、D0 兩位是A/D通道編號:00通道0,01通道1腕柜,10通道2济似,11通道3
D2 自動增量選擇(0為禁止自動增量矫废,1為允許自動增量),如果允許自動增量砰蠢,則在每次A/D轉(zhuǎn)換后蓖扑,通道編號會自動遞增。
D3 特征位:固定值為:0娩脾。
D5赵誓、D4 模擬量輸入選擇:00為四路單端輸入、01為三路差分輸入柿赊、10為兩路單端與一路差分輸入、11為兩路差分輸入幻枉。
D6 使能模擬輸出AOUT有效(1為有效碰声,0為無效)。
D7 特征位:固定值為:0熬甫。
后面的編程會遇到胰挑,“bus.write_byte(address,0x40) ” 語句就是發(fā)送控制字“0x40”,40就代表控制字“0100 0000”椿肩,主要表示模擬輸出有效瞻颂,四路單端輸入,禁止自動增量郑象,A/D通道為0贡这。
具體如下圖所示:
??當(dāng)系統(tǒng)為A/D轉(zhuǎn)換時,模擬輸出允許為0厂榛。模擬量輸入選擇位取值由輸入方式?jīng)Q定:四路單端輸入時取00盖矫,三路差分輸入時取01,單端與差分輸入時取10击奶,二路差分輸入時取11辈双。最低兩位時通道編號位,當(dāng)對0通道的模擬信號進(jìn)行A/D轉(zhuǎn)換時取00柜砾,當(dāng)對1通道的模擬信號進(jìn)行A/D轉(zhuǎn)換時取01湃望,當(dāng)對2通道的模擬信號進(jìn)行A/D轉(zhuǎn)換時取10,當(dāng)對3通道的模擬信號進(jìn)行A/D轉(zhuǎn)換時取11痰驱。
??在進(jìn)行數(shù)據(jù)操作時证芭,首先是主控器發(fā)出起始信號,然后發(fā)出讀尋址字節(jié)萄唇,被控器做出應(yīng)答后檩帐,主控器從被控器讀出第一個數(shù)據(jù)字節(jié),主控器發(fā)出應(yīng)答另萤,主控器從被控器讀出第二個數(shù)據(jù)字節(jié)湃密,主控器發(fā)出應(yīng)答…一直到主控器從被控器中讀出第n個數(shù)據(jù)字節(jié)诅挑,主控器發(fā)出非應(yīng)答信號,最后主控器發(fā)出停止信號泛源。
5拔妥、A/D轉(zhuǎn)換應(yīng)用開發(fā)流程
?? 一個A/D轉(zhuǎn)換的周期的開始,總是在發(fā)送有效的讀設(shè)備地址給PCF8591之后达箍,A/D轉(zhuǎn)換在應(yīng)答時鐘脈沖的后沿被觸發(fā)没龙。PCF8591的A/D轉(zhuǎn)換程序設(shè)計(jì)流程,可以分為四個步驟:
1--發(fā)送寫設(shè)備地址缎玫,選擇IIC總線上的PCF8591器件硬纤。
2--發(fā)送控制字節(jié),選擇模擬量輸入模式和通道赃磨。
3--發(fā)送讀設(shè)備地址筝家,選擇IIC總線上的PCF8591器件。
4--讀取PCF8591中目標(biāo)通道的數(shù)據(jù)邻辉。
(1)溪王、AD的位數(shù):表明這個AD共有2n個刻度,8位AD值骇,輸出的刻度是0~255. 8591就是8為精度的莹菱,因此它digtalRead的數(shù)據(jù)在0-255之間。
(2)吱瘩、分辨率:就是AD能夠分辨的最小的模擬量變化道伟,假設(shè)5.10V的系統(tǒng)用8位的AD采樣,那么它能分辨的最小電壓就是5.10/255=0.02V搅裙。
??AD轉(zhuǎn)換的原理簡單來理解就是通過電路將非電信號轉(zhuǎn)為電信號皱卓,然后通過一個基準(zhǔn)電壓(PCF8591的基準(zhǔn)電壓是5V),然后判斷這個電信號的電壓高低部逮,然后得到一個0-255(8位精度)的比值娜汁。
四、實(shí)驗(yàn)步驟
??第1步:在本實(shí)驗(yàn)中兄朋,AIN0(模擬輸入0)端口用于接收來自電位計(jì)模塊的模擬信號掐禁。AOUT(模擬輸出)用于將模擬信號輸出到雙色LED模塊,以便改變LED的亮度颅和。傳感器上可以看見傅事,可調(diào)電阻在傳感器上是標(biāo)識的是“0”,使用INPUT0端口峡扩,用短路帽連接AIN0和INPUT0蹭越。
??光敏電阻模塊是INPUT1端口,熱敏電阻模塊是INPUT2端口教届。
樹莓派 | T型轉(zhuǎn)接板 | PCF8591模塊 |
---|---|---|
SDA | SDA | SDA |
SCL | SCL | SCL |
5V | 5V | VCC |
GND | GND | GND |
雙色LED模塊 | T型轉(zhuǎn)接板 | PCF8591模塊 |
---|---|---|
R(紅色端口) | * | AOUT |
GND | GND | GND |
G(綠色端口) | * | * |
??第2步:PCF8591模塊采用的是I2C(IIC)總線進(jìn)行通信的响鹃,但是在樹莓派的鏡像中默認(rèn)是關(guān)閉的驾霜,在使用該傳感器的時候,我們必須首先允許IIC總線通信买置。
??第3步:開始編程粪糙。這里先編寫一個PCF8591.py庫文件,后面再編寫一個python程序引入這個庫文件忿项。
??PCF8591.py庫文件就是PCF8591模塊的程序蓉冈,單獨(dú)編寫是為了便于重用。在這個腳本中轩触,我們使用了一個放大器用于模擬輸入和一個LED燈用于模擬輸出寞酿,模擬輸入不能超過3.3V!
??該程序也可以單獨(dú)運(yùn)行脱柱,用于測試3個電阻模塊的功能熟嫩。需用短路帽連接AIN0和INPUT0(電位計(jì)模塊),連接AIN1和INPUT1(光敏電阻模塊)褐捻,以及連接AIN2和INPUT2(熱敏電阻模塊)。
??連接LED燈椅邓,AIN0(模擬輸入0)端口用于接收來自電位計(jì)模塊的模擬信號柠逞,AOUT(模擬輸出)用于將模擬信號輸出到雙色LED模塊,以便改變LED的亮度景馁。
#!/usr/bin/env python
#------------------------------------------------------
#
# 您可以使用下面語句將此腳本導(dǎo)入另一個腳本:
# “import PCF8591 as ADC”
#
# ADC.Setup(Address) # 查詢PCF8591的地址:“sudo i2cdetect -y 1”
# i2cdetect is a userspace program to scan an I2C bus for devices.
# It outputs a table with the list of detected devices on the specified bus.
# ADC.read(channal) # Channal范圍從0到3
# ADC.write(Value) # Value范圍從0到255
#
#------------------------------------------------------
#SMBus (System Management Bus,系統(tǒng)管理總線)
import smbus #在程序中導(dǎo)入“smbus”模塊
import time
# for RPI version 1, use "bus = smbus.SMBus(1)"
# 0 代表 /dev/i2c-0板壮, 1 代表 /dev/i2c-1 ,具體看使用的樹莓派那個I2C來決定
bus = smbus.SMBus(1) #創(chuàng)建一個smbus實(shí)例
#在樹莓派上查詢PCF8591的地址:“sudo i2cdetect -y 1”
def setup(Addr):
global address
address = Addr
def read(chn): #channel
if chn == 0:
bus.write_byte(address,0x40) #發(fā)送一個控制字節(jié)到設(shè)備
if chn == 1:
bus.write_byte(address,0x41)
if chn == 2:
bus.write_byte(address,0x42)
if chn == 3:
bus.write_byte(address,0x43)
bus.read_byte(address) # 從設(shè)備讀取單個字節(jié),而不指定設(shè)備寄存器合住。
return bus.read_byte(address) #返回某通道輸入的模擬值A(chǔ)/D轉(zhuǎn)換后的數(shù)字值
def write(val):
temp = val # 將字符串值移動到temp
temp = int(temp) # 將字符串改為整數(shù)類型
# print temp to see on terminal else comment out
bus.write_byte_data(address, 0x40, temp)
#寫入字節(jié)數(shù)據(jù)绰精,將數(shù)字值轉(zhuǎn)化成模擬值從AOUT輸出
if __name__ == "__main__":
setup(0x48)
#在樹莓派終端上使用命令“sudo i2cdetect -y 1”,查詢出PCF8591的地址為0x48
while True:
print '電位計(jì) AIN0 = ', read(0) #電位計(jì)模擬信號轉(zhuǎn)化的數(shù)字值
print '光敏電阻 AIN1 = ', read(1) #光敏電阻模擬信號轉(zhuǎn)化的數(shù)字
print '熱敏電阻 AIN2 = ', read(2) #熱敏電阻模擬信號轉(zhuǎn)化的數(shù)字值
tmp = read(0)
tmp = tmp*(255-125)/255+125
# 125以下LED不會亮透葛,所以將“0-255”轉(zhuǎn)換為“125-255”笨使,調(diào)節(jié)亮度時燈不會熄滅
write(tmp)
time.sleep(2)
??若想深入學(xué)習(xí)模/數(shù)轉(zhuǎn)換等模電知識,強(qiáng)烈推薦以下書籍僚害,國外大學(xué)最經(jīng)典模電教程硫椰,比國內(nèi)教程生動有趣更易懂。掃碼購買或者點(diǎn)擊下面的鏈接萨蚕。
《模擬電子基礎(chǔ)》點(diǎn)擊購買:https://u.dangdang.com/OIVk
??上面的程序中import smbus(System Management BUS靶草,即系統(tǒng)管理總線),SMBUS總線規(guī)范是基于I2C的總線規(guī)范岳遥,但與I2C總線規(guī)范也有一定的區(qū)別奕翔。python smbus 有如下函數(shù):
# Send only the read / write bit
long write_quick(int addr)
# Read a single byte from a device, without specifying a device register.
long read_byte(int addr)
# Send a single byte to a device
long write_byte(int addr, char val)
# Read Byte Data transaction.
long read_byte_data(int addr, char cmd)
# Write Byte Data transaction.
long write_byte_data(int addr, char cmd, char val)
# Read Word Data transaction.
long read_word_data(int addr, char cmd)
# Write Word Data transaction.
long write_word_data(int addr, char cmd, int val)
# Process Call transaction.
long process_call(int addr, char cmd, int val)
#Read Block Data transaction.
long[] read_block_data(int addr, char cmd)
# Write up to 32 bytes to a device. This fucntion adds an initial byte indicating the
# length of the vals array before the valls array. Use write_i2c_block_data instead!
write_block_data(int addr,char cmd,long vals[])
# Block Process Call transaction.
long[] block_process_call(int addr, char cmd, long vals[])
# I2C Access Functions
# Block Read transaction.
long[] read_i2c_block_data(int addr, char cmd)
#Block Write transaction.
write_i2c_block_data(int addr, char cmd, long vals[])
#Code Example
#!/usr/bin/python
import smbus
bus = smbus.SMBus(1) # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)
DEVICE_ADDRESS = 0x15 #7 bit address (will be left shifted to add the read write bit)
DEVICE_REG_MODE1 = 0x00
DEVICE_REG_LEDOUT0 = 0x1d
#Write a single register
bus.write_byte_data(DEVICE_ADDRESS, DEVICE_REG_MODE1, 0x80)
#Write an array of registers
ledout_values = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
bus.write_i2c_block_data(DEVICE_ADDRESS, DEVICE_REG_LEDOUT0, ledout_values)
??第4步:編輯運(yùn)行本次實(shí)驗(yàn)程序。用小平口起子調(diào)節(jié)藍(lán)白色的“103”可變電阻浩蓉,LED燈的亮度會隨之變化派继;同時程序運(yùn)行終端上會不停地打印可變電阻大小A/D轉(zhuǎn)換后的數(shù)字值宾袜。
??當(dāng)然,這里僅僅用短路帽連接AIN0和INPUT0(電位計(jì)模塊)就可以了互艾,光敏電阻模塊以及熱敏電阻模塊就不需要短路帽連接了试和。
#!/usr/bin/env python
import PCF8591 as ADC
def setup():
ADC.setup(0x48)
def loop():
while True:
print ADC.read(0)
#打印電位計(jì)電壓大小A/D轉(zhuǎn)換后的數(shù)字值(從AIN0借口輸入的)
#范圍是0~255,0時LED燈熄滅,255時燈最亮
ADC.write(ADC.read(0))
#將0通道輸入的電位計(jì)電壓數(shù)字值轉(zhuǎn)化成模擬值從AOUT輸出
#給LED燈提供電源VCC輸入
def destroy():
ADC.write(0)
if __name__ == "__main__":
try:
setup()
loop()
except KeyboardInterrupt:
destroy()