51单片机+ LCD1602+PCF8574转IIC接口+矩阵按键

【Proteus仿真】51单片机+ LCD1602+PCF8574转IIC接口+矩阵按键


  • 🎬Proteus仿真
    在这里插入图片描述
  • 📜PCF8574地址:
    在这里插入图片描述
    在这里插入图片描述

📑程序说明

本例程使用了2片PCF8574,并没有共用I2C总线,虽然配置了不同的地址,但是为什么不共用I2C总线,主要是因为按键扫描这一路I2C,使用了INT0中断,如果共用I2C总线,经仿真测试发现,会影响到按键扫描这一路I2C,所以只能将两路I2C分开。

📝main主程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
文件名称:1602液晶显示的光标控制
说 明:利用4\*4矩阵键盘进行输入并控制光标
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
#include <at89x52.h>
#include "key\_8574.h"
#include "1602.h"
uchar key; //定于全局变量key,用于按键扫描后的码值存放
uchar i;
int temp = 0; //1602的列
int temp1 = 0; //1602的行
/\*4\*4键盘对应的值\*/
uchar zi[] = {' ',
'1', '2', '3', 'A',
'4', '5', '6', 'B',
'7', '8', '9', 'C',
'\*', '0', '#', 'D',
};

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
函数名称:KEY\_Value
函数功能:实现4\*4矩阵按键在1602上的输出
入口参数:无
出口参数:无
备 注:实现输出0~9,光标的移位
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void KEY\_Value()
{
if(key != 0)
{
delayms(10); //按键消抖
if(key != 0)
{
i = key;
switch(i)
{
case 4:
write\_com\_1602(0x14); //光标右移一位 (0x14)~(0x17)光标右移一位
temp++; //列加1 //(0x18)~(0x1b)屏幕左移
break; //(0x1c)~(0x1f)屏幕右移
case 8:
write\_com\_1602(0x10); //光标左移一位 (0x10)~(0x13)光标左移一位
temp--; //列减1
break;
case 16:
switch(temp1) //查询当前光标在哪一行
{
case 1:
temp1 = 0; //改变光标的行
write\_com\_1602(0x80 + temp); //改变光标的行,列不变
break;
case 0:
temp1 = 1; //改变光标的行
write\_com\_1602(0xc0 + temp); //改变光标的行,列不变
break;
}
break;
case 12:
write\_com\_1602(0x01); //显示清屏
temp = 0; //回到第一列
temp1 = 0; //回到第一行
break;
case 15:
temp++; //向后移动一位
if(temp1 == 0) //如果在第一行
{
write\_com\_1602(0x80 + temp); //光标显示在第一行
}
else //否则
{
write\_com\_1602(0xc0 + temp); //光标显示在第二行
}
break;
default:
write\_char\_1602(temp1, temp, zi[i]); //在当前位置输出数字
if(temp1 == 0) //如果在第一行
{
write\_com\_1602(0x80 + temp); //光标显示在第一行
}
else //否则
{
write\_com\_1602(0xc0 + temp); //光标显示在第二行
}
break;

}
if(temp == 16) //如果到了最后一列
{
temp = 0; //回到第一列
temp1++;//到下一行
}
if(temp1 == 2) //如果到了最后一行
{
temp1 = 0; //回到第一行
}
if(temp < 0) //如果向左移,移过了第一列
{
temp = 16; //到最后一列
temp1--;//回到上一行
}
if(temp1 < 0) //如果向上移,移过了第一行
{
temp1 = 1; //到第二行
temp = 15; //到最后一列
}
}
while(key != 0); //等待按键释放
}
}

void main()
{
init\_8574();//初始化函数
init\_1602();
/\*外部中断0被pcf8574占用\*/
IT0 = 1; //令INT0下降沿触发
EX0 = 1; //开INT0中断
EA = 1; //开启总中断
write\_com\_1602(0x01);//显示清屏
while(1)
{
KEY\_Value();
}
}

/\*---------------------------------------------
\*\*函数名称:int0()
\*\*函数功能:中断系统
\*\*入口参数:无
\*\*输出参数:无
\*\*说明:当pcf8574P口变化时会产生中断变化,单片机
根据中断进行按键扫描
---------------------------------------------\*/
void int0() interrupt 0
{
EX0 = 0;//为了防止多次进入中断造成干扰,先关闭中断
key = key\_scan();//读取按键值
EX0 = 1;//开启中断
}

📚仿真资源和程序源码

1
2
3
4

链接: https://pan.baidu.com/s/1nvUAsXJ-yhK2zzZPjc3NBA
提取码: bvqx