在單片機(jī)系統(tǒng)中,如果并行口的IO資源不夠,那么我們可以使用74LS164來(lái)擴(kuò)展并行IO口,節(jié)約單片機(jī)IO資源。74LS164是一個(gè)串行輸入并行輸出的移位寄存器,并帶有清除端。
時(shí)序分析,單片機(jī)串行口時(shí)序單片機(jī)串行口作顯示端口時(shí)應(yīng)工作在方式發(fā)送狀態(tài),其時(shí)序如圖所示。從時(shí)序圖中可以看出,當(dāng)一個(gè)數(shù)據(jù)輸入到串行口發(fā)送緩沖器SBUF時(shí),串行口將8位數(shù)據(jù)以Fosc/12的波特率從低位到高位(即從D0~D7)依次通過(guò)RXD引腳輸出,當(dāng)位發(fā)送完以后,中斷標(biāo)志TI置“1”,結(jié)束一個(gè)發(fā)送過(guò)程。這里應(yīng)當(dāng)注意的是串行口物出一個(gè)字節(jié)數(shù)字的次序,它是單片機(jī)串行口與74LS164正確配合的關(guān)鍵所在。
圖2所示為8位串行輸入、并行輸出移位寄存器74LS164的工作時(shí)序。從圖2中我們可以看出,使能端B(引腳2)為低電平時(shí),寄存器禁止輸入數(shù)據(jù),當(dāng)B為高電平時(shí),數(shù)據(jù)可以從A端(引腳1)輸人。圖2中表明,先輸入的數(shù)據(jù)首先Qa從(引腳3)輸出。當(dāng)寄存器74LS164接收完8位數(shù)據(jù)時(shí),先輸入的1位移至Q(引腳13)輸出,而Qa端輸出的則是最后接收到的1位。
軟件與硬件的正確配合
從以上對(duì)單片機(jī)串行口及74LS164的時(shí)序分析可知,移位寄存器首先塊收到單片機(jī)串行口輸出的最低位D0。,最后接收到該字節(jié)的最高位D7。因此,當(dāng)接收完8位數(shù)據(jù)后,移位寄存器QH端輸出的是D0。,而QA輸出的是D7。以上談到的兩文中所出現(xiàn)的錯(cuò)誤原因,就是忽視了這一重要特點(diǎn)。他們給出的硬件電路如圖3所示。字形代碼及真值表如表所示。
從表1可以看出,字形代碼把段碼a當(dāng)作D0位,把段碼h當(dāng)作D7位依次對(duì)應(yīng)。在移位寄存器接收到一個(gè)完整的字形碼時(shí),QA輸出的不是段碼a,而是段碼h(h為小數(shù)點(diǎn),也可不接。)這樣處理的結(jié)果,使輸出的段碼次序剛好相反,所以,顯示出的字形就不對(duì)了。表1右側(cè)列出了(h連小數(shù)點(diǎn)時(shí)的)錯(cuò)顯字形。若要顯示正確字形,在使用圖3所示電路時(shí)字形碼應(yīng)做調(diào)整,調(diào)整后的字形代碼和真值表如表2所示。這種字形碼輸入到74LS164內(nèi)時(shí),在其輸出腳QA~QH上依次輸出段碼a~h,從而正確顯示出要顯示的內(nèi)容。
在某些場(chǎng)合,設(shè)計(jì)者仍想使用表1所列的字形碼,那么只需把顯示器與74LS164的連接做一調(diào)整即可。硬件電路如圖4所示
通過(guò)對(duì)單片機(jī)串行口和74LS164時(shí)序的分析,給出了兩種正確的軟件與硬件組合方法。筆者在研制成功的智能離心開(kāi)關(guān)斷開(kāi)測(cè)速儀中利用表2所列的字形碼與圖3所示硬件相配合,使用結(jié)果令人滿意。另外,有的設(shè)計(jì)中也可能遇到8位并入串行輸出移位寄存器74LS165與單片機(jī)串行口的配合間題,其研究方法仍然應(yīng)從時(shí)序入手,與本文所介紹方法類同,此不贅述
proteus仿真圖和代碼附上。
#include《reg51.h》
#define HIGH 1
#define LOW 0
#define SEG_PORT P0
sbit DATA = P0^4;
sbit CLK = P0^5;
unsigned char Timer0IRQEvent = 0;
unsigned char Time1SecEvent = 0;
unsigned int TimeCount = 0;
unsigned char SegCurPosition = 0;
code unsigned char SegCode[10] = {~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,~0x07,~0x7F,~0x6F};
code unsigned char SegPosition[4] = {0xFE,0xFD,0xFB,0xF7};
unsigned char SegBuf[4] = {0};
void LS164_DATA(unsigned char x)
{
if(x)
{
DATA = 1;
}
else
{
DATA = 0;
}
}
void LS164_CLK(unsigned char x)
{
if(x)
{
CLK = 1;
}
else
{
CLK = 0;
}
}
/**********************************************************
*函數(shù)名稱:LS164Send
*輸 入:byte單個(gè)字節(jié)
*輸 出:無(wú)
*功 能:74LS164發(fā)送單個(gè)字節(jié)
***********************************************************/
void LS164Send(unsigned char byte)
{
unsigned char j;
for(j=0;j《=7;j++)
{
if(byte&(1《《(7-j)))
{
LS164_DATA(HIGH);
}
else
{
LS164_DATA(LOW);
}
LS164_CLK(LOW);
LS164_CLK(HIGH);
}
}
/**********************************************************
*函數(shù)名稱:SegRefreshDisplayBuf
*輸 入:無(wú)
*輸 出:無(wú)
*功 能:數(shù)碼管刷新顯示緩存
***********************************************************/
void SegRefreshDisplayBuf(void)
{
SegBuf[0] = TimeCount%10;
SegBuf[1] = TimeCount/10%10;
SegBuf[2] = TimeCount/100%10;
SegBuf[3] = TimeCount/1000%10;
}
/**********************************************************
*函數(shù)名稱:SegDisplay
*輸 入:無(wú)
*輸 出:無(wú)
*功 能:數(shù)碼管顯示數(shù)據(jù)
***********************************************************/
void SegDisplay(void)
{
unsigned char t;
SEG_PORT = 0x0F;
t = SegCode[SegBuf[SegCurPosition]];
LS164Send(t);
SEG_PORT = SegPosition[SegCurPosition];
if(++SegCurPosition 》= 4)
{
SegCurPosition = 0;
}
}
/**********************************************************
*函數(shù)名稱:TimerInit
*輸 入:無(wú)
*輸 出:無(wú)
*功 能:定時(shí)器初始化
***********************************************************/
void TimerInit(void)
{
TH0 = (65536 - 5000)/256;
TL0 = (65536 - 5000)%256;
TMOD = 0x01;
}
/**********************************************************
*函數(shù)名稱:Timer0Start
*輸 入:無(wú)
*輸 出:無(wú)
*功 能:定時(shí)器啟動(dòng)
***********************************************************/
void Timer0Start(void)
{
TR0 = 1;
ET0 = 1;
}
/**********************************************************
*函數(shù)名稱:PortInit
*輸 入:無(wú)
*輸 出:無(wú)
*功 能:I/O初始化
***********************************************************/
void PortInit(void)
{
P0 = P1 = P2 = P3 = 0xFF;
}
/**********************************************************
*函數(shù)名稱:main
*輸 入:無(wú)
*輸 出:無(wú)
*功 能:函數(shù)主題
***********************************************************/
void main(void)
{
PortInit();
TimerInit();
Timer0Start();
SegRefreshDisplayBuf();
EA = 1;
while(1)
{
if(Timer0IRQEvent)
{
Timer0IRQEvent = 0;
if(Time1SecEvent)
{
Time1SecEvent = 0;
if(++TimeCount 》= 9999)
{
TimeCount = 0;
}
SegRefreshDisplayBuf();
}
SegDisplay();
}
}
}
/**********************************************************
*函數(shù)名稱:Timer0IRQ
*輸 入:無(wú)
*輸 出:無(wú)
*功 能:定時(shí)器中斷函數(shù)
***********************************************************/
void Timer0IRQ(void) interrupt 1
{
static unsigned int cnt = 0;
TH0 = (65536 - 5000)/256;
TL0 = (65536 - 5000)%256;
Timer0IRQEvent = 1;
if(++cnt 》= 200)
{
cnt = 0;
Time1SecEvent = 1;
}
}
評(píng)論
查看更多