在單片機系統中,如果并行口的IO資源不夠,那么我們可以使用74LS164來擴展并行IO口,節約單片機IO資源。74LS164是一個串行輸入并行輸出的移位寄存器,并帶有清除端。
74LS164的引腳可以查看數據手冊。
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;
}
}
/**********************************************************
*函數名稱:LS164Send
*輸 入:byte單個字節
*輸 出:無
*功 能:74LS164發送單個字節
***********************************************************/
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);
}
}
/**********************************************************
*函數名稱:SegRefreshDisplayBuf
*輸 入:無
*輸 出:無
*功 能:數碼管刷新顯示緩存
***********************************************************/
void SegRefreshDisplayBuf(void)
{
SegBuf[0] = TimeCount%10;
SegBuf[1] = TimeCount/10%10;
SegBuf[2] = TimeCount/100%10;
SegBuf[3] = TimeCount/1000%10;
}
/**********************************************************
*函數名稱:SegDisplay
*輸 入:無
*輸 出:無
*功 能:數碼管顯示數據
***********************************************************/
void SegDisplay(void)
{
unsigned char t;
SEG_PORT = 0x0F;
t = SegCode[SegBuf[SegCurPosition]];
LS164Send(t);
SEG_PORT = SegPosition[SegCurPosition];
if(++SegCurPosition >= 4)
{
SegCurPosition = 0;
}
}
/**********************************************************
*函數名稱:TimerInit
*輸 入:無
*輸 出:無
*功 能:定時器初始化
***********************************************************/
void TimerInit(void)
{
TH0 = (65536 - 5000)/256;
TL0 = (65536 - 5000)%256;
TMOD = 0x01;
}
/**********************************************************
*函數名稱:Timer0Start
*輸 入:無
*輸 出:無
*功 能:定時器啟動
***********************************************************/
void Timer0Start(void)
{
TR0 = 1;
ET0 = 1;
}
/**********************************************************
*函數名稱:PortInit
*輸 入:無
*輸 出:無
*功 能:I/O初始化
***********************************************************/
void PortInit(void)
{
P0 = P1 = P2 = P3 = 0xFF;
}
/**********************************************************
*函數名稱:main
*輸 入:無
*輸 出:無
*功 能:函數主題
***********************************************************/
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();
}
}
}
/**********************************************************
*函數名稱:Timer0IRQ
*輸 入:無
*輸 出:無
*功 能:定時器中斷函數
***********************************************************/
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;
}
}