矩阵键盘检测。
视频里现场写的代码给弄复杂了,难理解,简化一下以后好多了
主要就是那个与操作是不必要的。把按键取出的数与了以后,最后还要再重新从P3口取完整的数。因为如果不重新取P3口完整的值,会导致扫描2 、3、4行时取得同样的值。比如第一行第一个键被按下取的值是0xee,和0xf0与操作后得到0xe0。扫描第2行时,按下第一个键,取得的值是0xed,和0xf0与操作后仍然是0xe0,剩下的也同样。就没法区分了。
所以完全没必要做“与”操作,增加了复杂性,还容易出错。第一行直接判断是否为0xfe,第二行直接判断是否为0xfd,以此类推,就可以了。
#include
#define uint unsigned int
#define uchar unsigned char
sbit duan=P2^6;
sbit wei=P2^7;
sbit d1=P1^0;
uchar temp,num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void delay(uint);
void main()
{
wei=1;
P0=0xc0;
wei=0;
duan=1;
P0=0x00;
duan=0;
while(1)
{
/* P3=0xfe;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0) *///这里视频写的“与”操作根本多余的吧,改掉~~。
P3=0xfe; //第一行赋值为0,P3值即为0xfe
temp=P3;
if(temp!=0xfe) //如果为真,则执行if{}内代码,如果为假,
//则跳出if{}执行(去检测第2行按键有没有被按下)
{ //视频里用while循环,感觉用if好点。
delay(5);
temp=P3;
//temp=temp&0xf0;
//if(temp!=0xf0)
if(temp!=0xfe)
{
temp=P3;//取回P3口的值(有可能是按下某件得到的值,必须要取),在swith case语句中进行比较。
switch(temp)
{
case 0xee:num=0;
break;
case 0xde:num=1;
break;
case 0xbe:num=2;
break;
case 0x7e:num=3; //分别比较几个算好的码,相同则赋给相关的值,并将其值赋给num,以方便显示时调用。
break;
}
duan=1;
P0=table[num];//打开段选口,让P0口显示数值
duan=0; //注意,这里,必须放在最里面的if下,否则逻辑出问题。
while(temp!=0xfe)//松手检测。
{
temp=0xfe;
}
}
}
P3=0xfd; //将第2行赋值为0,P3口的值即为0xfd
temp=P3;
if(temp!=0xfd) //开始扫描第2行有无键按下
{
delay(5);
temp=P3;
temp=temp&0xf0;
if(temp!=0xfd)
{
temp=P3;
switch(temp)
{
case 0xed:num=4;
break;
case 0xdd:num=5;
break;
case 0xbd:num=6;
break;
case 0x7d:num=7;
break;
}
duan=1;
P0=table[num];
duan=0;
while(temp!=0xfd)
{
temp=0xfd;
}
}
}
P3=0xfb; //开始扫描第三行有无键按下
temp=P3;
if(temp!=0xfb)
{
delay(5);
temp=P3;
if(temp!=0xfb)
{
temp=P3;
switch(temp)
{
case 0xeb:num=8;
break;
case 0xdb:num=9;
break;
case 0xbb:num=10;
break;
case 0x7b:num=11;
break;
}
duan=1;
P0=table[num];
duan=0;
while(temp!=0xfb)
{
temp=0xfb;
}
}
}
P3=0xf7; //开始扫描第4行有无键按下
temp=P3;
if(temp!=0xf7)
{
delay(5);
temp=P3;
if(temp!=0xf7)
{
temp=P3;
switch(temp)
{
case 0xe7:num=12;
break;
case 0xd7:num=13;
break;
case 0xb7:num=14;
break;
case 0x77:num=15;
break;
}
duan=1;
P0=table[num];
duan=0;
while(temp!=0xf7)
{
temp=0xf7;
}
}
}
}
}
void delay(uint z) //延迟子程序
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}

第6课课间作业。利用D/A模块实现发光二极管在2秒内逐渐变亮,达到最亮时再在2秒内逐渐变暗。保持循环。
因为这是自己没有跟着视频写的第一个完整的程序,也算零的突破.经过仿真验证没有问题。值得纪念一下。
另外,看来直接对P0口赋10进制的值是没问题的(以前还一直以为对I/O口的操作只能用16进制,囧)。
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit csda=P3^2;
sbit wr=P3^6;
sbit duan=P2^6;
sbit wei=P2^7;
int num;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
duan=0;
wei=0; //关闭位选和段选,否则信号会串到数码管上。
num=0;
while(1)
{
csda=0; //打开D/A片选
wr=0; //写信号置低电平
if(num==0) //判断,当num为0时
{
while(num<255)
{
num=num+5; //num自加5
P0=num; //每次执行到此,将加5后的num赋值给P0口。除非num值等于255推出循环进入下面程序。
delay(40); //延迟40ms ,控制变化速度
}
}
if(num==255)
{
while(num>0)
{
num=num-5;
P0=num;
delay(40);
}
}
}
}
因为这是自己没有跟着视频写的第一个完整的程序,也算零的突破.经过仿真验证没有问题。值得纪念一下。
另外,看来直接对P0口赋10进制的值是没问题的(以前还一直以为对I/O口的操作只能用16进制,囧)。
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit csda=P3^2;
sbit wr=P3^6;
sbit duan=P2^6;
sbit wei=P2^7;
int num;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
duan=0;
wei=0; //关闭位选和段选,否则信号会串到数码管上。
num=0;
while(1)
{
csda=0; //打开D/A片选
wr=0; //写信号置低电平
if(num==0) //判断,当num为0时
{
while(num<255)
{
num=num+5; //num自加5
P0=num; //每次执行到此,将加5后的num赋值给P0口。除非num值等于255推出循环进入下面程序。
delay(40); //延迟40ms ,控制变化速度
}
}
if(num==255)
{
while(num>0)
{
num=num-5;
P0=num;
delay(40);
}
}
}
}