我們學習了如何利用74HC595這塊顯示驅動芯片來驅動1位8段數碼管的方法。并逐一講解了該芯片各引腳的功能。細心的童鞋可能注意到了,上次我們有一個Q7S引腳沒有用到。這一篇我們就用這個引腳來級聯兩塊74HC595芯片同時驅動8個8段數碼管。在兩塊74HC595芯片的配合下,同樣只需要3個GPIO口就能驅動八只8段數碼管。而如果直接用GPIO驅動則需要至少16個GPIO口,節省了13個GPIO!而且按照本文的方法,你還可以級聯更多的74HC595芯片,每多級聯一片就能多驅動8只數碼管,而需要的IO口仍然只有3個!媽媽再也不用擔心我的IO口不夠用了。
最終效果
視頻演示
硬件
- 74HC595顯示芯片 X 2
- 共陽(或共陰)4位數碼管 X 2
硬件圖 由于大面包板已經被我插滿了,所以用另一塊小面包板來安放第二片74HC595
原理說明
- 我們已經知道,每次制造一次移位寄存器時鐘引腳的上升沿,74HC595都會在這個上升沿將DS引腳上的數據存入內部的移位寄存器D0,同時D0原來的數據會順移到D1,D1的數據位移到D2。。。D6的數據位移到D7。而D7的數據會被輸出到引腳Q7S上,如果Q7S引腳沒有被使用,那么這一位數據就被丟掉了。
- 如果我們將Q7S引腳連接上另一塊74HC595的DS引腳并保證兩塊芯片上的移位時鐘的上升沿同時發生(將兩塊芯片的SHCP連在一起即可)的話,第一塊74HC595的串行輸出引腳Q7S就變成了第二塊74HC595的串行輸入數據源。Q7S上的數據會繼續移位到第二塊74HC595芯片的移位寄存器D0里(同樣的,D0→D1→D2→…→D6→D7→Q7S)。
- 16位數據全部這樣串行傳輸完畢后,制造兩塊芯片的鎖存時鐘STCP的上升沿(跟SHCP一樣,兩塊芯片的STCP連在一起即可)即可同時輸出16位數據。
- 利用上述級聯原理加上前一篇學習的內容,我們可以這樣靜態驅動2只數碼管:兩只數碼管的共陽(陰)極連接VCC(GND),第一片595的Q0-Q7連到第一個數碼管的A-G,Dp上,級聯的第二片595的Q0-Q7連到第二只數碼管的A-G,Dp上,然后用3根GPIO口驅動兩片級聯的74HC595芯片,連續串行輸入兩個數字的顯示碼共16位數據,然后同時制造鎖存上升沿,將兩個數字的顯示碼分別輸出到兩只數碼管上即可。這樣連接的話,N片級聯的74HC595就能驅動N只數碼管了。(咦,說好的驅動8位數碼管的呢)
- 上面的做法當然沒問題,而且有一個優點是靜態顯示所以顯示很穩定,有興趣自己試著做一下。缺點是浪費芯片,價格倒不貴可是連線復雜,占用電路板面積太多。本文采用動態掃描(原理參見本系列第5篇)的方式來使用兩塊級聯的74HC595芯片驅動8位數碼管。原理也很簡單,稍微調整一下硬件的連接方式和傳輸數據的方式即可。
- 依然是兩塊74HC595級聯,第一塊595的輸出引腳連到所有數碼管的段引腳上(8只數碼管的A-G,Dp引腳連在一起),第二塊595的輸出引腳Q0-Q7分別連上8只數碼管的共陽(陰)極上。第一塊芯片的輸出決定了數碼管上顯示什么數字。而8只數碼管中哪一只會被點亮則取決于第二塊芯片哪只數碼管的共陽(陰)端是高(低)電平。
- 由于在我的硬件連接里,級聯的第二塊74HC595是負責位選的,所以應該先發送8位位選信號,再發送8位段選信號,在連續發完了16位數據以后,第一塊74HC595的移位寄存器里保存著8位的段選信息,而在第二塊74HC595的移位寄存器里保存著8位的位選信息。由于兩片芯片的STCP是連在同一個GPIO口的,這個時候如果制造一次STCP的上升沿,兩塊595的位移寄存器里的數據會同時保存到自己的鎖存器里,由于我的使能端OE連在GND始終有效,鎖存器里的數據就直接輸出到了芯片的輸出引腳上。第二塊芯片的8根輸出引腳連接的是8位數碼管的共陽端。只有輸出高電平的引腳連接的數碼管才會被點亮。
- 當然如果你喜歡,你也可以讓8個數碼管全部同時點亮,你只要讓第二塊595輸出11111111就行了。不過顯示的數字都是一樣的。想顯示不同的數字就要進行動態掃描,每次輸出一個數字的顯示碼跟一個位選碼,快速循環切換顯示即可。
跟上一篇一樣,我也做了一個動畫幫助你理解級聯的過程。這個動畫一開始已經是傳輸完前8位位選數據的狀態了,動畫里的位選數據是1000000,點亮第一個數碼管,顯示的內容由后8位段選數據決定,動畫里是數字5。74HC595
硬件連接
模塊1引腳模塊2引腳74HC595_1Q0數碼管1/2DP74HC595_1Q1數碼管1/2G74HC595_1Q2數碼管1/2F74HC595_1Q3數碼管1/2E74HC595_1Q4數碼管1/2D74HC595_1Q5數碼管1/2C74HC595_1Q6數碼管1/2B74HC595_1Q7數碼管1/2A74HC595_1Q7S74HC595_2DS74HC595_2Q0數碼管1DIG1的共陽極74HC595_2Q1數碼管1DIG2的共陽極74HC595_2Q2數碼管1DIG3的共陽極74HC595_2Q3數碼管1DIG4的共陽極74HC595_2Q4數碼管2DIG1的共陽極74HC595_2Q5數碼管2DIG2的共陽極74HC595_2Q6數碼管2DIG3的共陽極74HC595_2Q7數碼管2DIG4的共陽極樹莓派GPIO1374HC595_1DS樹莓派GPIO1974HC595_1/2SHCP樹莓派GPIO2674HC595_1/2SHTP樹莓派VCC74HC595_1/2VCC,MR樹莓派GND74HC595_1/2GND,OE代碼(Python)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
#!/usr/bin/env python# encoding: utf-8import RPi.GPIOimport time# 串行數據輸入引腳連接的GPIO口DS = 13# 移位寄存器時鐘控制引腳連接的GPIO口——上升沿有效SHCP = 19# 數據鎖存器時鐘控制引腳連接的GPIO口——上升沿有效STCP = 26RPi.GPIO.setmode(RPi.GPIO.BCM)RPi.GPIO.setup(DS, RPi.GPIO.OUT)RPi.GPIO.setup(STCP, RPi.GPIO.OUT)RPi.GPIO.setup(SHCP, RPi.GPIO.OUT)RPi.GPIO.output(STCP, False)RPi.GPIO.output(SHCP, False)# 通過串行數據引腳向74HC595的傳送一位數據def setBitData(data):# 準備好要傳送的數據RPi.GPIO.output(DS, data)# 制造一次移位寄存器時鐘引腳的上升沿(先拉低電平再拉高電平)# 74HC595會在這個上升沿將DS引腳上的數據存入移位寄存器D0# 同時D0原來的數據會順移到D1,D1的數據位移到D2。。。D6的數據位移到D7# 而D7的數據已經沒有地方儲存了,這一位數據會被輸出到引腳Q7S上# 如果Q7S引腳沒有被使用,那么這一位的數據就被丟掉了。# 而如果將Q7S引腳連接到另一塊74HC595上的DS引腳,# 那么這一位數據就會繼續位移到第二塊595芯片的位移寄存器里去。# 這就是多塊595芯片級聯的原理。RPi.GPIO.output(SHCP, False)RPi.GPIO.output(SHCP, True)# 指定第dig位(1-8)數碼管顯示數字num(0-9),參數showDotPoint是顯示不顯示小數點(true/false)# 由于我使用的數碼管是共陽數碼管,所以設置為低電平的段才會被點亮# 如果你用的是共陰數碼管,那么要將下面的True和False全部顛倒過來,或者統一在前面加上notdef showDigit(dig, num, showDotPoint):# 由于在我的硬件連接里,級聯的第二塊74HC595是負責位選的,# 所以應該先發送8位位選信號,再發送8位段選信號,在連續發完了16位數據以后,# 第一塊74HC595的移位寄存器里保存著8位的段選信息,而在第二塊74HC595的移位寄存器里保存著8位的位選信息。# 由于兩片芯片的STCP是連在同一個GPIO口的,這個時候如果制造一次STCP的上升沿,# 兩塊595的位移寄存器里的數據會同時保存到自己的鎖存器里,由于我的使能端OE連在GND始終有效,鎖存器里的數據就直接輸出到了芯片的輸出引腳上。# 第一塊芯片的8根輸出引腳連接的是所有數碼管共用的abcdefg,dp引腳,決定了數碼管上顯示什么數字。而8只數碼管中哪一只會被點亮則取決于哪只數碼管的共陽端是高電平。# 第二塊芯片的8根輸出引腳連接的是8位數碼管的共陽端。只有輸出高電平的引腳連接的數碼管會點亮。# 當然如果你喜歡,你也可以讓8個數碼管全部同時點亮,你只要讓第二塊595輸出11111111就行了。不過顯示的數字都是一樣的。# 想顯示不同的數字就要進行動態掃描,原理不再說明請參考本系列教程第5篇。for x in range(1,9):if (x == dig):setBitData(True)else:setBitData(False)if (num == 0) :setBitData(not showDotPoint) # DPsetBitData(True) # GsetBitData(False) # FsetBitData(False) # EsetBitData(False) # DsetBitData(False) # CsetBitData(False) # BsetBitData(False) # Aelif (num == 1) :setBitData(not showDotPoint)setBitData(True)setBitData(True)setBitData(True)setBitData(True)setBitData(False)setBitData(False)setBitData(True)elif (num == 2) :setBitData(not showDotPoint)setBitData(False)setBitData(True)setBitData(False)setBitData(False)setBitData(True)setBitData(False)setBitData(False)elif (num == 3) :setBitData(not showDotPoint)setBitData(False)setBitData(True)setBitData(True)setBitData(False)setBitData(False)setBitData(False)setBitData(False)elif (num == 4) :setBitData(not showDotPoint)setBitData(False)setBitData(False)setBitData(True)setBitData(True)setBitData(False)setBitData(False)setBitData(True)elif (num == 5) :setBitData(not showDotPoint)setBitData(False)setBitData(False)setBitData(True)setBitData(False)setBitData(False)setBitData(True)setBitData(False)elif (num == 6) :setBitData(not showDotPoint)setBitData(False)setBitData(False)setBitData(False)setBitData(False)setBitData(False)setBitData(True)setBitData(False)elif (num == 7) :setBitData(not showDotPoint)setBitData(True)setBitData(True)setBitData(True)setBitData(True)setBitData(False)setBitData(False)setBitData(False)elif (num == 8) :setBitData(not showDotPoint)setBitData(False)setBitData(False)setBitData(False)setBitData(False)setBitData(False)setBitData(False)setBitData(False)elif (num == 9) :setBitData(not showDotPoint)setBitData(False)setBitData(False)setBitData(True)setBitData(False)setBitData(False)setBitData(False)setBitData(False)# 移位寄存器的8位數據全部傳輸完畢后,制造一次鎖存器時鐘引腳的上升沿(先拉低電平再拉高電平)# 74HC595會在這個上升沿將移位寄存器里的8位數據復制到8位的鎖存器中(鎖存器里原來的數據將被替換)# 到這里為止,這8位數據還只是被保存在鎖存器里,并沒有輸出到數碼管上。# 決定鎖存器里的數據是否輸出是由“輸出使能端口”OE決定的。當OE設置為低電平時,鎖存器里數據才會被輸出到Q0-Q7這8個輸出引腳上。# 在我的硬件連接里,OE直接連接在了GND上,總是保持低電平,所以移位寄存器的數據一旦通過時鐘上升沿進入鎖存器,也就相當于輸出到LED上了。RPi.GPIO.output(STCP, True)RPi.GPIO.output(STCP, False)try:# 測試代碼while (True):# 8位數碼管顯示1-8,不顯示小數點for dig in range(1,9):showDigit(dig, 9-dig, False)time.sleep(0.001)except KeyboardInterrupt:pass# 最后清理GPIO口RPi.GPIO.cleanup()
評論