LCD1602的接口形式是并行的,它有8条数据线、3条控制线。这样就需要11条线来控制它的正常工作。虽然它还可以工作在4位数据线的形式,最精简的形式是6条线。
有位网友想要使用74HC595进行串-并转换,想要用4条线来控制LCD1602。
【问题如下】大神能不能写一个两根线用74hc595驱动1602显示的单片机c程序,RCK和SCK接在要一起。
【最佳答案】RCK和SCK接在要一起,...这个接法,恐怕不行。如果想要节约引脚,下面的方法,倒还可以试一试:SDI,和RS接在一起;RCK,和E接在一起。比楼主的电路,还要节约一个引脚。
。。。
多用了一块芯片,省下了单片机的引脚,这也算是一种方法吧,在系统规模较大、资源紧张的条件下,还是值得应用的。
74HC595是“串入并出”的移位寄存器芯片,它需要用3条线控制数据的输入,才能正常的输出8位数据。
有了8位数据,这时,LCD1602还需要至少两条控制线。
经过精心设计,分时使用这些控制线,最终,仅仅使用了3条线,就完成了对74HC595和LCD1602的有效控制!
这要比前面的网友提出的4条线的方案,还要更加精简,节省率提高了25%。
精简后的电路图如下:
由于LCD1602的驱动电路发生了改变,所以数字钟的程序,也要相应的修改。
那么,针对本电路的程序如下:
//============================================
#include<reg52.h>
#defineucharunsignedchar
#defineuintunsignedint
#defineKEY_IOP3
sbitLCD_RS=P2^0;
sbitLCD_EN=P2^2;
sbitSCK=P2^0;
sbitSDI=P2^1;
sbitRCK=P2^2;
sbitSPK=P1^2;
sbitLED=P2^4;
bitnew_s,modify=0;
chart0,sec=50,min=59,hour=23;
charcodeLCD_line1[]="DesignedbyZELD";
charcodeLCD_line2[]="Timer:00:00:00";
charTimer_buf[]="23:59:50";
//---------------------------------------------------
voiddelay(uintz)
{
uintx,y;
for(x=z;x>0;x--)for(y=100;y>0;y--);
}
//---------------------------------------------------
voidwrite_595(uchardate)//写入595
{
uchari;
for(i=0;i<8;i++){
SCK=0;SDI=date&0x80;
SCK=1;date<<=1;
}
}
//---------------------------------------------------
voidW_LCD_Com(ucharcom)//写指令
{
write_595(com);LCD_RS=0;//写入指令
RCK=1;RCK=0;//令595输出,并用EN输出一个高脉冲
}
//---------------------------------------------------
voidW_LCD_Dat(uchardat)//写数据
{
write_595(dat);LCD_RS=1;//写入数据
RCK=1;RCK=0;//令595输出,并用EN输出一个高脉冲
}
//---------------------------------------------------
voidW_LCD_STR(uchar*s)//写字符串
{
while(*s)W_LCD_Dat(*s++);
}
//---------------------------------------------------
voidW_BUFF(void)//填写显示缓冲区
{
Timer_buf[7]=sec%10+48;Timer_buf[6]=sec/10+48;
Timer_buf[4]=min%10+48;Timer_buf[3]=min/10+48;
Timer_buf[1]=hour%10+48;Timer_buf[0]=hour/10+48;
W_LCD_Com(0xc0+7);W_LCD_STR(Timer_buf);
}
//---------------------------------------------------
ucharread_key(void)
{
ucharx1,x2;
KEY_IO=255;
x1=KEY_IO;
if(x1!=255){
delay(100);
x2=KEY_IO;
if(x1!=x2)return255;
while(x2!=255)x2=KEY_IO;
if(x1==0x7f)return0;
elseif(x1==0xbf)return1;
elseif(x1==0xdf)return2;
elseif(x1==0xef)return3;
elseif(x1==0xf7)return4;
}
return255;
}
//---------------------------------------------------
voidInit()
{
W_LCD_Com(0x38);delay(50);
W_LCD_Com(0x38);delay(50);
W_LCD_Com(0x0c);
W_LCD_Com(0x06);
W_LCD_Com(0x01);delay(50);
W_LCD_Com(0x80);W_LCD_STR(LCD_line1);
W_LCD_Com(0xC0);W_LCD_STR(LCD_line2);
TMOD=0x01;//T0定时方式1
TH0=0x4c;
TR0=1;//启动T0
PT0=1;//高优先级,以保证定时精度
ET0=1;
EA=1;
}
//---------------------------------------------------
voidmain()
{
uinti,j;
ucharKey;
Init();
while(1){
//-------------------------------
if(new_s){//如果出现了新的一秒,修改时间
new_s=0;sec++;sec%=60;
if(!sec){min++;min%=60;
if(!min){hour++;hour%=24;}
}
W_BUFF();//写显示
//-------------------------------
if(!sec&&!min){//整点报时
for(i=0;i<200;i++){
SPK=0;for(j=0;j<100;j++);
SPK=1;for(j=0;j<100;j++);
}}
}
//-------------------------------
Key=read_key();//读出按键
switch(Key){//分别处理四个按键
case0:modify=1;break;
case1:if(modify){min++;min%=60;W_BUFF();break;}
case2:if(modify){hour++;hour%=24;W_BUFF();break;}
case3:modify=0;break;
}}
}
//---------------------------------------------------
voidtimer0(void)interrupt1//T0中断函数,50ms执行一次
{
TH0=0x4c;
t0++;t0%=20;//20,一秒钟
if(t0==0){new_s=1;LED=~LED;}
if(modify)LED=0;
}
//============================================