51單片機學習筆記(清翔版)(13)——LED點陣、74HC595


如圖3,點陣屏分單色和彩色,點陣屏是由許多點組成的,在一個點上,只有一顆一種顏色的燈珠,這就是單色點陣屏,彩色的在一個點上有三顆燈珠,分別是RGB三原色。

圖4你可能沒看出來,那么大塊黃色的就是點陣屏,下面那個粉色的長條也是。

大的點陣屏實際上是由許多一小塊一小塊點陣屏拼接在一塊的,最終形成一個大的,在做移動舞台時,它拆裝方便,例如演唱會時,液晶的就不方便,運輸也不方便,也容易損壞,而點陣屏就一快一塊運輸就可以,然后拼在一起。

單色點陣屏成本低,就不能像圖4一樣顯示視頻了,只能顯示文字。

這是我們用的,一個點里面一個燈珠的單色點陣屏。

8*8就是8行8列的64個的點陣屏,左下方那是背面引腳圖,在設計點陣屏的時候就需要了解這個引腳是怎么排序的,否則怎么驅動它。

看這有一個凹起的塑料,以這個點為參考點,右面是1腳,左邊是8腳,右到左1~8,上方左到右是9~16。學會后要是自己想做一個點陣屏就要知道引腳的排序。

接下來就看點陣屏內部原理圖。

內部結構比較簡單,是由多顆LED燈珠連接在一起組成的

左邊和上邊的數字分別對應的是引腳

LED就是讓指定的燈亮,來顯示我們需要的字形

比如“上”

那么我們如何點亮呢?

例如左上角的那個,它的正極接到了9腳,負極接到了13腳,那么9接高電平,13給低電平就亮了,那么其它腳我們怎么賦值呢?

我們的LED點陣是共陽極的,和前面的數碼管一樣,也分為共陽極共陰極。

行,都是接了正極的,就是共陽極。反之,如果LED的正極接在了列上,那么就是共陰極。

回到剛才的問題,那么就是如下:

那么點亮許多燈怎么辦?

比如我們再把這個點亮。

這就用到了動態掃描技術了。(和數碼管一樣,利用人眼的視覺暫留效果)

我們先讓第一個亮,然后馬上讓第二個亮,然后又讓第一個亮,一直循環。這樣看起來就兩個都亮了,實際上是不能靜態顯示同時亮這兩個燈的。

原因呢,我們看看:

如果我們要想讓這兩個亮,那么9,14是高電平,13,3是低電平。那么第一行第二列的燈也會亮,第二行第一列也是。所以我們就需要用動態掃描的方式。

以上就是點陣屏靜態顯示和動態顯示的工作原理。點陣屏在實際的應用中我們是用動態顯示的方法顯示我們需要的內容。

有人會問為什么不把這16個引腳都接到單片機的引腳上呢?因為接下來我們介紹74HC595芯片。

我們這個點陣是焊在了一個PCB板上做點陣模塊,是由兩片595級聯在一起來驅動8*8點陣的。

級聯在一起只需要3個單片機的IO口,就可以控制16個腳的點陣了。非常的節省IO口。這也是實際應用中的一個方案。在點陣屏行業中,幾乎都是用74HC595級聯驅動的。

有些同學會看到別的同學再做實驗時,把16個引腳都接到了單片機上驅動,作為初學者看似很簡單,實際和我們實際應用中是脫節的。實際應用中我們不可能用這種方式去驅動,這種方式太耗費硬件資源了,你看1個點陣就有16個腳,假設我們要讓點陣顯示的內容更加豐富,我們再加3個8*8的點陣,那就是64個引腳,如果我們直接接單片機,那么需要多少個單片機?以我們stc89c52為例,一個單片機有32個IO口,那么就需要兩片單片機。(這種4塊8*8的點陣合在一起我們稱為16*16的點陣模塊)上面這種方案顯然是不可行的,一個單片機就好幾塊錢,你驅動4個屏就需要2個單片機,這樣硬件開銷成本太大了。

而595方法,兩個595級聯在一塊就可以驅動一個8*8點陣,驅動4個點陣我們只需要8片595,而1個595只需要幾毛錢(5毛)。可能有的同學還看到別的硬件驅動1個8*8點陣需要8個或者10個以上的IO口,這種硬件純粹就是設計給你玩的,他和實際應用是嚴重脫軌的,就算你學單片機只是為了玩,那你玩也要玩跟實際接軌的東西,不然你也玩不出什么高端。


 74HC595

在學會595后你會發現,他在驅動這類電子屏是非常適合的。

串入並出:串行輸入,並行輸出。

例如有1個數據,1個字節的8位數據,要從A傳送到B點,如果是串行,串行只有一個數據通道,這8位要想從A到B只能從這一個通道過去,那么它一次只能走一個,比如第一次過去一個1,1完了后,2又過去,以此類推,8次。如果是8位並行,他就有8個通道,8個數據就可以一次傳過去

由此可見,並行傳輸速度快,但是占用的硬件資源多,一共要占用8條傳輸用的數據線。串行占用硬件資源少,但傳輸速度要慢許多。

下面看看595的使用方法

比較重要,這一塊學懂了,那么595芯片也就徹底懂了,使用方法懂了,編程也就不會有問題了。

(比較難,前面都是並行輸入輸出,現在已經到串行輸入了)

中間上面是我們的引腳圖,下面是我們模塊的原理圖,他只需要3個IO口就可驅動16個引腳的點陣屏了。

DS(14):串行數據輸入端,串行輸入只需要1個數據線,級聯就接上一級的Q7',意思是如果要多加一個595芯片,那么DS就接到上一個的Q7'

看這個電路圖就知道,當然這里標的不一樣,這里標的是SER,我們看引腳就是,

 

為什么要級聯?595是串入並出,8個IO口作並行輸出,我們點陣有16個腳,1片只能控制8個腳,還有8個腳我們就再需要一片。

Q7'(9)(注意有兩個Q7,是不同的,要區分開,那個9腳上面的點是“非”的意思):級聯輸出端,將他接到下一片595的DS端

看上面那個595的Q7'有個×,是懸空的,如果不級聯懸空就行,如果級聯就接到下一片的14腳。

 

如果級聯3個,那么我們用3個IO口就可以做一個8*3=24位數據的並行輸出了。這個方法用來擴展單片機的IO口非常實用,如果單片機的IO口不夠用,我們就可以用這種方案,並且價格也便宜,而且成熟好用。

SH_CP(11):數據輸入的時鍾線,由於是串行輸入,基本上所有的串行輸入都是需要一個時鍾線的,這個時鍾線就是給他們一個節拍,你這個數據什么時候該走,什么時候不該走要給一個節拍,不然數據不知道是不是輪到我該傳輸過去了。上升沿時,數據從DS串行輸入。輸入到595內部的移位寄存器(8位)中,是怎么一個過程呢?下面演示一下。

DS腳應用的時候要接到單片機的個IO口上,假如給接到DS的IO口送一個數據1,那么DS腳就是1了(高電平),那么1是怎么進入到內部的移位寄存器呢?就需要在11腳產生一個上升沿,那么數據就可以進入到移位寄存器中了,什么是上升沿?一個低電平,然后變為高電平。對於5V單片機而言,低電平時0V,高電平時5V。從0V變到5V的這個過程就叫做一個上升沿。單片機產生一個上升沿是很簡單的,給IO口一個0,單片機就輸出一個低電平0V,再給單片機一個1,單片機就輸出5V,從0V到5V的這么一個變化就產生了一個上升沿,這就是單片機產生一個上升沿的過程。

再詳細說一下:

假設我們發1101 0011這么一個數據,1個字節8位的。右邊是低位,左邊是高位。先發低位。給先給DS一個1,用單片機IO口輸出一個1,然后給11腳一個低電平一個高電平產生上升沿,這時這個1就會被送到移位寄存器第八位上,接着再發第二位,再給DS一個1,再產生一個上升沿,就會把最開始發的1擠到第七位移位寄存器上,而這次的1就發到了第八位,接着再發0,那么第八位移位寄存器就是0,第七位就是1,第六位就是1,依次類推。接着我們要輸出,輸出到Q0~Q7上,並行的輸出出去,怎么辦?這時候就是12腳了。

ST_CP(12):輸出存儲器鎖存時鍾線,12也接單片機一個IO,給他一個上升沿,那么剛剛的那8位數據就一下子從Q0到Q7輸出出去了,這就是串行輸入並行輸出。輸入的時候只從DS一個口,通過時鍾控制,依次放到8位的內部移位寄存器上,再給12腳輸出鎖存器一個上升沿,鎖存器中的8位數據就一下子輸出到Q0~Q7。12腳我們還有一個需要注意的,它是一個鎖存器,我們學數碼管的時候也講過,573就是一個鎖存器,這里鎖存器什么意思呢?假設經過8次后,數據放入移位寄存器中了,給一個上升沿,那么數據就輸出到Q0~Q7上了,只要595沒有斷電的情況下,Q0~Q7的數據是保持不變的,除非我們再通過DS串行輸入端輸入8位數據過去,把這數據覆蓋掉,否則在沒斷電的情況下是保持不變的。這有一個什么好處呢?這對我們驅動電子屏是非常實用,他可以實現不閃屏,我現在要這8個燈亮,它就一直保持着亮,不會因為其他情況讓數據發生變化,假設后面這幾個IO口還要拿來做別的用(11、12),Q0~Q7要保持不變,這就是他的鎖存器的功能。在數碼管那節課就體現出來了。

/MR(10):低電平清0移位寄存器,我們不需要把它清零,所以在電路圖上直接接了VCC。電路圖上標的不一樣,標的/SRCLR。

/OE(13):高電平為進制輸出狀態(高阻態),我們要用到他的串入並出所以這個腳必須接到GND上。電路圖上標的E。如果這個腳為高電平,那么Q0~Q7和點陣屏的IO口就是斷開的了,斷開后沒有電壓電流,就息屏了,不工作了。如果在IO口多的情況下,我們可以把這個腳接IO,給一個高電平就會息屏,點陣的16個腳相當於懸空,沒有任何能量過去,LED燈就會全熄滅,再給個低電平,兩個芯片的Q0~Q7又都接上了,數據是保持不變的,上一次是什么內容,這一次還是那個內容,就實現了閃屏的效果。

VCC(16):接電源,2~6V。

GND(8):接地。

級聯:

DS輸入的數據,當11腳SH_CP產生上升沿,就會把第一位數據送到第一片的移位寄存器最高位上,再發一位數據,那么之前的第一位數據就跑到移位寄存器第七位上,第二位數據跑到移位寄存器第八位上,依次進行16次,最終第一位數據就跑到第二片的移位寄存器的第一位上,第二位數據跑到第二片移位寄存器的第二位上。第16位數據跑到第一片的第八位上,再給ST_CP一個上升沿,16位數據就會都輸出出去,通過兩片你的Q0~Q7。第一片輸出的9~16位,第二片輸出的1~8位。

再詳細看下原理圖:

兩個595的時鍾線(11和12腳分別接在一起)接在一起,輸入端接在第一片(14),另一片的輸入接在級聯的輸出端。電源端加上濾波電容(C1、C2)。

市面上的大點陣屏基本都是由8*8拼接的,就像之前看到的。室外的都是防水的,室內的防水效果就沒那么好,其它都是相同的。

看看手冊

供電電壓2~6V。

引腳圖和真值表:

G如果為高,那么QA~QH其它三個不管什么狀態,輸出為高阻態。G為低,SCLR為低,那么就清除移位鎖存器內容。

SCK位上升沿時,移位寄存器移位。RCK為上升沿就把移位寄存器內容傳輸到輸出鎖存器。

工作電源要求:

最小2V,最大6V,輸出電壓最小0,最大VCC。

直流電氣特性,作為初學者不用看,成為高手自己設計電路需要了解。

VIN最小輸入高電平電壓有一個要求,VCC為4.5V,輸入還有溫度限制,不能低於3.15V,不然就檢測不到,不認為是高電平。

VIL最大低電平電壓,VCC為4.5V,低電平最大電壓不能超過1.35V,超過就不認為是低電平。

這個輸出電流只有在級聯多片點陣的時候需要考慮的到,如果電流過低,點陣屏就會很暗,就需要做一個電流放大。

 交流特性:

內部結構圖:

時序圖:

直插的外部封裝:


上面,了解了點陣工作原理,點亮燈,動態掃描,學習了74HC595,串入並出,優點節省IO口,熟悉怎么進行串行輸入和並行輸出,給14輸入,再給11接上時鍾線,給一個上升沿,數據就進入了移位寄存器,還沒輸出,輸出時,只要給12一個上升沿,8位移位寄存器的數據就輸出了。級聯,9腳接到下一個芯片的14腳,不論級聯多少都只需要3個IO口做輸入。串行輸入時要搞清楚級聯時數據的高低字節。

為了使電子顯示屏不閃屏,都是需要用並行輸出的,串行可能會閃屏。

proteus仿真問題:

  1. CON6是接插件、插針端子,叫CONN-H6
  2. 點陣屏上面引腳是列,高有效,從左到右是1~8列,下面引腳是行,低有效,從左到右是1~8行。即共陰極點陣屏。
  3. Q0是最高位,Q7是最低位,不知道你們記錯沒有,反正我記錯了哈哈

接下來開始編程

亮左上角第一個燈(應該說是靠近9腳那側的)

這里應該是講錯了,視頻中說Q0是低位,可實際Q0是高位

 1 #include<reg51.h>
 2 
 3 #define uchar unsigned char
 4 #define uint unsigned int
 5 
 6 sbit DIO=P3^4;
 7 sbit S_CLK=P3^5;
 8 sbit R_CLK=P3^6;
 9 
10 //uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
11 //                    0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F   無顯示
12 
13 void main()
14 {
15     //點亮點陣左上方第一個點row 0x80 , col 0xfe
16     //串入並出,所以要一位一位的發送給DIO
17     uchar i=0,dat;//一個字節數據是一個常量,發數據要進行移位、運算,常量不可以
18     dat=0xfe;//先給列的值,因為列是第二個芯片控制,先給了第一個芯片,當再賦值行時,會把列擠給第二塊芯片
19     //並且先發送低位再發送高位
20     for(i=0;i<8;i++)
21     {
22         S_CLK=0;
23         R_CLK=0;
24         if(dat&0x01)
25             DIO=1;
26         else
27             DIO=0;
28         S_CLK=1;
29         dat>>=1;
30     }
31     dat=0x80;
32     for(i=0;i<8;i++)
33     {
34         S_CLK=0;
35         R_CLK=0;
36         if(dat&0x01)
37             DIO=1;
38         else
39             DIO=0;
40         S_CLK=1;
41         dat>>=1;
42     }
43     R_CLK=1;
44     while(1);
45     
46 }

 實際電路板是這樣

 

查了一遍595個引腳輸出,發現輸出不對。原因暫未發現,但不影響,將錯就錯吧。

先把串行輸入數據寫成函數的形式,再讓亮另外一個燈,上面那個

 1 #include<reg51.h>
 2 
 3 #define uchar unsigned char
 4 #define uint unsigned int
 5 
 6 sbit DIO=P3^4;
 7 sbit S_CLK=P3^5;
 8 sbit R_CLK=P3^6;
 9 
10 //uchar code Table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
11 //                    0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F   無顯示
12 
13 void Send_Byte(uchar dat);
14 
15 void main()
16 {
17     //串入並出,所以要一位一位的發送給DIO
18     //先給列的值,因為列是第二個芯片控制,先給了第一個芯片,當再賦值行時,會把列擠給第二塊芯片
19     //並且先發送低位再發送高位
20     Send_Byte(0xfe);
21     Send_Byte(0x40);
22     R_CLK=1;
23     while(1);
24     
25 }
26 void Send_Byte(uchar dat)
27 {
28     uchar i=0;
29     S_CLK=0;
30     R_CLK=0;
31     for(i=0;i<8;i++)
32     {
33         if(dat&0x01)
34             DIO=1;
35         else
36             DIO=0;
37         S_CLK=1;
38         dat>>=1;
39         S_CLK=0;
40     }
41 }

接下來顯示漢字:電

取字模,我們用到了軟件PCtoLCD2002

 設置

然后新建8,8

 

點擊生成字模就可以了

{0xEF,0x01,0x6D,0x01,0x6D,0x01,0xEE,0xE0}

這是列選的數據

 

 1 #include<reg51.h>
 2 #include<intrins.h>
 3 
 4 #define uchar unsigned char
 5 #define uint unsigned int
 6 
 7 sbit DIO=P3^4;
 8 sbit S_CLK=P3^5;
 9 sbit R_CLK=P3^6;
10 
11 uchar code Table[]={0xEF,0x01,0x6D,0x01,0x6D,0x01,0xEE,0xE0};//電,列選table表
12 
13 void Send_Byte(uchar dat);
14 
15 void main()
16 {
17     uchar j=0,row;
18     
19     while(1)
20     {
21         row=0x80;
22         for(j=0;j<8;j++)
23         {
24             Send_Byte(Table[j]);//送每一行的列選值
25             Send_Byte(row);//分別掃描每一行,一次一行
26             R_CLK=1;//Send_Byte中置低了
27             R_CLK=0;//再次變低
28             row=_cror_(row,1);
29         }
30     }
31 }
32 void Send_Byte(uchar dat)
33 {
34     uchar i=0;
35     S_CLK=0;
36     R_CLK=0;
37     for(i=0;i<8;i++)
38     {
39         if(dat&0x01)
40             DIO=1;
41         else
42             DIO=0;
43         S_CLK=1;
44         dat>>=1;
45         S_CLK=0;
46     }
47 }

不過呢,這是倒着的,仿真出不來

但是這個取模軟件可以幫助我們

點完后就這樣了,然后再生成字模就可以了

接下來顯示:電子

 1 #include<reg51.h>
 2 #include<intrins.h>
 3 
 4 #define uchar unsigned char
 5 #define uint unsigned int
 6 
 7 sbit DIO=P3^4;
 8 sbit S_CLK=P3^5;
 9 sbit R_CLK=P3^6;
10 
11 uchar code Table[][8]={
12     0xE0,0xEE,0x01,0x6D,0x01,0x6D,0x01,0xEF,
13     0xE7,0xF7,0xF7,0xF7,0x80,0xF7,0xFB,0xC3
14 };//電,列選table表
15 
16 void Send_Byte(uchar dat);
17 
18 void main()
19 {
20     uchar j=0,k=0,row;
21     
22     while(1)
23     {
24         for(k=0;k<2;k++)
25         {
26             row=0x80;
27             for(j=0;j<8;j++)
28             {
29                 Send_Byte(Table[k][j]);//送每一行的列選值
30                 Send_Byte(row);//分別掃描每一行,一次一行
31                 R_CLK=1;//Send_Byte中置低了
32                 R_CLK=0;//再次變低
33                 row=_cror_(row,1);
34             }
35         }
36     }
37 }
38 void Send_Byte(uchar dat)
39 {
40     uchar i=0;
41     S_CLK=0;
42     R_CLK=0;
43     for(i=0;i<8;i++)
44     {
45         if(dat&0x01)
46             DIO=1;
47         else
48             DIO=0;
49         S_CLK=1;
50         dat>>=1;
51         S_CLK=0;
52     }
53 }

會發現電和子一起顯示了,怎么辦?自己想一下辦法

你會發現延時不行,原因是,延時的話,每一個點顯示的時間很長,而不是一個字

所以我們需要把一個字的時間加長,也就是里面的for循環多來幾次

 1 #include<reg51.h>
 2 #include<intrins.h>
 3 
 4 #define uchar unsigned char
 5 #define uint unsigned int
 6 
 7 sbit DIO=P3^4;
 8 sbit S_CLK=P3^5;
 9 sbit R_CLK=P3^6;
10 
11 uchar code Table[2][8]={
12     0xE0,0xEE,0x01,0x6D,0x01,0x6D,0x01,0xEF,
13     0xE7,0xF7,0xF7,0xF7,0x80,0xF7,0xFB,0xC3
14 };//電,列選table表
15 
16 void Send_Byte(uchar dat);
17 
18 void main()
19 {
20     uchar j=0,k=0,row;
21     uint z;//別寫成了uchar...uchar最大256
22     while(1)
23     {
24         for(k=0;k<2;k++)
25         {
26             row=0x80;
27             for(z=0;z<1000;z++)
28             {
29                 for(j=0;j<8;j++)
30                 {
31                     Send_Byte(Table[k][j]);//送每一行的列選值
32                     Send_Byte(row);//分別掃描每一行,一次一行
33                     R_CLK=1;//Send_Byte中置低了
34                     R_CLK=0;//再次變低
35                     row=_cror_(row,1);
36                 }
37             }
38         }
39     }
40 }
41 void Send_Byte(uchar dat)
42 {
43     uchar i=0;
44     S_CLK=0;
45     R_CLK=0;
46     for(i=0;i<8;i++)
47     {
48         if(dat&0x01)
49             DIO=1;
50         else
51             DIO=0;
52         S_CLK=1;
53         dat>>=1;
54         S_CLK=0;
55     }
56 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM