LCD1602 的接口形式是并行的,它有 8 条数据线、3 条控制线。这样就需要 11 条线来控制它的正常工作。虽然它还可以工作在 4 位数据线的形式,最精简的形式是 6 条线。
有位网友想要使用 74HC595 进行串-并转换,想要用 4 条线来控制 LCD1602。
可见链接:http://zhidao.baidu.com/question/458604195.html。
多用了一块芯片,省下了单片机的引脚,这也算是一种方法吧,在系统规模较大、资源紧张的条件下,还是值得应用的。
74HC595 是“串入并出”的移位寄存器芯片,它需要用 3 条线控制数据的输入,才能正常的输出 8 位数据。
有了 8 位数据,这时,LCD1602 还需要至少两条控制线。
经过做而论道的精心设计,分时使用这些控制线,最终,仅仅使用了 3 条线,就完成了对 74HC595 和 LCD1602 的有效控制 !
这要比前面的网友提出的 4 条线的方案,还要更加精简,节省率提高了 25%。
精简后的电路图如下:
图中是一个数字钟,是为另一个网友编写的,可以参考下面的链接:
http://hi.baidu.com/do_sermon/item/c8d1161d40768f10e3f98682
http://hi.baidu.com/%D7%F6%B6%F8%C2%DB%B5%C0/blog/item/a0c99e2343b541844423e865.html
(百度空间在 2012 年 8 月,无聊的改版了,结果,把它自己的网站链接,都弄断了。因此,下面的链接,已经失效了。不删了,留作纪念吧。)
由于 LCD1602 的驱动电路发生了改变,所以数字钟的程序,也要相应的修改。
那么,针对本电路的程序如下:
//===================================================
#include
#define uchar unsigned char
#define uint unsigned int
#define KEY_IO P3
sbit LCD_RS = P2^0;
sbit LCD_EN = P2^2;
sbit SCK = P2^0;
sbit SDI = P2^1;
sbit RCK = P2^2;
sbit SPK = P1^2;
sbit LED = P2^4;
bit new_s, modify = 0;
char t0, sec = 50, min = 59, hour = 23;
char code LCD_line1[] = "Designed by ZELD";
char code LCD_line2[] = "Timer: 00:00:00 ";
char Timer_buf[] = "23:59:50";
//---------------------------------------------------
void delay(uint z)
{
uint x, y;
for(x = z; x > 0; x--) for(y = 100; y > 0; y--);
}
//---------------------------------------------------
void write_595(uchar date)//写入595
{
uchar i;
for(i = 0; i < 8; i++) {
SCK = 0; SDI = date & 0x80;
SCK = 1; date <<= 1;
}
}
//---------------------------------------------------
void W_LCD_Com(uchar com) //写指令
{
write_595(com); LCD_RS = 0;//写入指令
RCK = 1; RCK = 0; //令595输出, 并用EN输出一个高脉冲
}
//---------------------------------------------------
void W_LCD_Dat(uchar dat) //写数据
{
write_595(dat); LCD_RS = 1;//写入数据
RCK = 1; RCK = 0; //令595输出, 并用EN输出一个高脉冲
}
//---------------------------------------------------
void W_LCD_STR(uchar *s) //写字符串
{
while(*s) W_LCD_Dat(*s++);
}
//---------------------------------------------------
void W_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);
}
//---------------------------------------------------
uchar read_key(void)
{
uchar x1, x2;
KEY_IO = 255;
x1 = KEY_IO;
if (x1 != 255) {
delay(100);
x2 = KEY_IO;
if (x1 != x2) return 255;
while(x2 != 255) x2 = KEY_IO;
if (x1 == 0x7f) return 0;
else if (x1 == 0xbf) return 1;
else if (x1 == 0xdf) return 2;
else if (x1 == 0xef) return 3;
else if (x1 == 0xf7) return 4;
}
return 255;
}
//---------------------------------------------------
void Init()
{
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;
}
//---------------------------------------------------
void main()
{
uint i, j;
uchar Key;
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) { //分别处理四个按键
case 0: modify = 1; break;
case 1: if(modify) {min++; min %= 60; W_BUFF(); break;}
case 2: if(modify) {hour++; hour %= 24; W_BUFF(); break;}
case 3: modify = 0; break;
} }
}
//---------------------------------------------------
void timer0(void) interrupt 1 //T0中断函数, 50ms执行一次
{
TH0 = 0x4c;
t0++; t0 %= 20; //20, 一秒钟
if(t0 == 0) {new_s = 1; LED = ~LED;}
if(modify) LED = 0;
}
//===================================================
上一篇:PWM --真正的流水灯
下一篇:PWM --呼吸灯
推荐阅读最新更新时间:2024-03-16 16:01