#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define choose P2
#define chose41 P1
//引脚定义
uchar code c485[]={0xf0,0xf2,0xf4,0xf8,0x8f,0x9f,0xaf,0xbf,0xcf,0xdf,0xef,0xff};
sbit ros_l=P1^7; //收发控制
sbit dog=P3^2; //看门狗
sbit led=P3^5; //指示灯
sbit c42=P3^3; //4051 控制
sbit c41=P1^0; //4051 控制
//变量定义
uint num=0; //计时计数
bit sm=0; //灯闪烁
bit tw=1; //02 03 判断是否重复发送
uchar rxd_buf[11]; //缓冲区
uchar fs[11]; //命令字
uchar temp; //暂存P0
uchar hc; //缓冲区控制
//----------函数定义---------------
//------------------------
//延时函数
//------------------------
debouncer(uint tms)
{
uint i;
uchar y;
for(i=0;i<tms;i++)
for(y=0;y<120;y++);
}
//--------------------
//系统初始化
//--------------------
init()
{
c41=1;
c42=1;
dog=1;
WR=0;
RD=0;
TH0=0xFC;
TL0=0x66;
TR0=1;
ET0=1;//开定时器0中断
}
//----------------------
//串口初始化
//----------------------
initser()
{
ros_l=0; //默认处于发送
TMOD=0x21;//定时器1工作模式2
PCON=0x00;
TH1=0xfd;
SCON=0x50;
TR1=1;
RI=0;
ES=1;
EA=1; //总中断
PS=1;
}
//---------------
//喂狗程序
//---------------
fordog()
{
dog=0;
debouncer(1);
dog=1;
}
//----------------------
//串口发送(单字节)
//----------------------
void com(uchar tt)
{
ros_l=1;
debouncer(1);
SBUF=tt;
EA = 0;
while(TI==0);
TI=0;
EA = 1;
ros_l=0;
}
//--------------------
//串口发送(多字节)
//--------------------
void comm(uchar *tt,uchar len)
{
ros_l=1;
debouncer(2);
EA=0;
do
{
SBUF=*tt++;
while(TI==0);
TI=0;
}while(--len!=0);
EA=1;
debouncer(2);
ros_l=0;
}
//-----------------------
//关掉LED
//-----------------------
leddown()
{
P0=0xFF;
choose=0x00;
choose=0x20; //457的上升沿,使LED显示
debouncer(2);
choose=0x80; //457的上升沿,使LED显示
}
//-------------------------
//上电执行一次LED闪烁
//-------------------------
ledup()
{
P0=0x00;
choose=0x00;
choose=0x20; //457的上升沿,使LED显示
debouncer(2);
choose=0x80; //457的上升沿,使LED显示
debouncer(1000);
leddown();
}
//-----------------------
//574错误处理
//-----------------------
void out574();
multi()//对temp处理 处理成单一的按键
{
uchar t,i,b,c[8];
bit a;
b=temp;
t=0;
for(i=0;i<8;i++)
{
a=((b>>i)&0x01);
if(a==0)
{
c[t]=(0x01<<i);
t++;
}
}
b=TL1;
temp=~c[b%t];
out574();
}
//-----------------------
//574输出
//-----------------------
void out574()
{
switch(temp)
{
case 0xFE:
if(choose==0x40)
{
P0=0x7F;
}
if(choose==0x60)
{
P0=0xF7;
}
break;
case 0xFD:
if(choose==0x40)
{
P0=0xBF;
}
if(choose==0x60)
{
P0=0xFB;
}
break;
case 0xFB:
if(choose==0x40)
{
P0=0xDF;
}
if(choose==0x60)
{
P0=0xFD;
}
break;
case 0xF7:
if(choose==0x40)
{
P0=0xEF;
}
if(choose==0x60)
{
P0=0xFE;
}
break;
case 0xEF:P0=0xF7;break;
case 0xDF:P0=0xFB;break;
case 0xBF:P0=0xFD;break;
case 0x7F:P0=0xFE;break;
default: //进行temp的异常处理
switch(fs[1])
{
case 0x01:
case 0x02:multi();break; //01 02 调用multi() ;03时不进行处理
default:break;
}
break;
}
}
//-----------------------
//随机片选74LS245
//-----------------------
whi245()
{
uchar b;
b=TL1;
switch(b%2)
{
case 0:
choose=0x40;
break;
case 1:
choose=0x60;
break;
default:break;
}
}
//----------------------------
//01模式下执行的数据处理
//----------------------------
dat245_1()
{
switch(choose)
{
case 0x40: //前8个中的有变化
out574();
choose=0x00;
debouncer(2);
choose=0x80; //457的上升沿,使LED显示
fs[3]=0;
if(fs[2]!=~temp)
{
fs[2]=~temp;
tw=1;
}
else
{
tw=0;
}
break;
case 0x60: //后4个中有变化
out574();
choose=0x20;
debouncer(2);
choose=0x80; //457的上升沿,使LED显示
fs[2]=0;
if(fs[3]!=~(temp&0x0F))
{
fs[3]=~(temp&0x0F);
tw=1;
}
else
{
tw=0;
}
break;
default:break;
}
}
//-----------------------
//处理函数
//-----------------------
manage()
{
uchar history[12];
uchar t,i;
switch(fs[1])
{
case 0x01:
c41=1;
c42=1;
sm=1; //闪烁控制开启1/4S
num=0;
leddown();
whi245();
while(P0==0xff&&sm==1) //端口没有变化一直等待,并由定时器中断控制片选
{
fordog();
}
temp=P0; //P0存入缓冲区
if(sm==1) // 只有在扫描时 才对接收的数据进行处理
{
EA=0; //关掉总中断
dat245_1();
fs[10]=fs[1]^fs[2]^fs[3];
comm(fs,11);
sm=0;
num=0;
}
break;
case 0x02: //有过的按键不再进行发送
for(t=0;t<12;t++) //在记录中都写入FF使得在中断此命令时不会再进行数据处理
{
history[t]=0xff;
}
t=0;
c41=1;
c42=1;
sm=1;
num=0;
while(sm==1) //循环进行扫描
{
leddown();
whi245();
while(P0==0xFF&&sm==1) //端口没有变化一直等待,并由定时器中断控制片选
{
fordog();
}
temp=P0; //P0存入缓冲区
ET0=0; //关掉定时器0中断
switch(choose)
{
case 0x40: //前8个中的有变化
out574();
choose=0x00;
debouncer(2);
choose=0x80; //457的上升沿,使LED显示
fs[3]=0;
for(i=0;i<t;i++)
{
tw=1;
if(history[i]==~temp) //有相同元素tw=0,并跳出;
{
tw=0;
break;
}
}
if(tw==1) //没有相同元素
{
fs[2]=~temp;
history[t]=fs[2];
t++;
}
break;
case 0x60: //后4个中有变化
out574();
choose=0x20;
debouncer(2);
choose=0x80; //457的上升沿,使LED显示
fs[2]=0;
for(i=0;i<t;i++)
{
tw=1;
if(history[i]==~(temp&0x0F))
{
tw=0;
break;
}
}
if(tw==1)
{
fs[3]=~(temp&0x0F);
history[t]=fs[3];
t++;
}
break;
default:break;
}
fs[10]=fs[1]^fs[2]^fs[3];
ET0=1;
if(tw==1&&sm==1)
{
comm(fs,11);
}
fordog();
}
break;
case 0x03:
c41=1;
c42=1;
sm=1;
num=0;
while(sm==1)
{
whi245();
while(P0==0xFF&&sm==1)
{
fordog();
}
temp=P0;
ET0=0;
dat245_1();
fs[10]=fs[1]^fs[2]^fs[3];
ET0=1;
if((sm==1)&&(tw==1))
{
comm(fs,11);
}
}
break;
case 0x05:
c41=1;
c42=1;
sm=0;
initser();
num=0;
leddown();
break;
case 0x06://分数
case 0x07://测试
if(fs[2]==0xa5) //出现07 A5的全部扫描时处理
{
for(i=0;i<12;i++)
{
c42=0;
if(i<4)
{
c42=1;
}
chose41=c485[i];
debouncer(1);
comm(fs,11);
initser();
}
break;
}
case 0x08://闪烁
case 0x09://灯带
sm=1;
num=0;
leddown();
switch(fs[2])
{
case 0x01:chose41=0xF0;c42=1;break;
case 0x02:chose41=0xF2;c42=1;break;
case 0x03:chose41=0xF4;c42=1;break;
case 0x04:chose41=0xF6;c42=1;break;
case 0x05:chose41=0x8F;c42=0;break;
case 0x06:chose41=0x9F;c42=0;break;
case 0x07:chose41=0xAF;c42=0;break;
case 0x08:chose41=0xBF;c42=0;break;
case 0x09:chose41=0xCF;c42=0;break;
case 0x0A:chose41=0xDF;c42=0;break;
case 0x0B:chose41=0xEF;c42=0;break;
case 0x0C:chose41=0xFF;c42=0;break;
default: break;
}
if(sm==1)
{
ros_l=1; //发送态
debouncer(2);
comm(fs,11);
ros_l=0; //接收状态
initser();
c41=1;
c42=1;
EA=1;
}
sm=0;
num=0;
break;
default:break;
}
}
//----------------------
//串口数据处理
take()
{
uchar i,te;
te=0x00;
for(i=1;i<6;i++) // 计算校验值
{
te^=rxd_buf[i];
}
if((rxd_buf[0]==0x51)&&(rxd_buf[10]==te)) //数据完整 校验正确
{
fordog();
for(i=0;i<11;i++)
{
fs[i]=rxd_buf[i];
rxd_buf[i]=0;
}
manage();
}
else
{
comm(rxd_buf,11);
com(0xac); //回送错误信号 请求重发
}
initser();
}
//------------------------
//主函数
//------------------------
main()
{
initser();
init();
ledup();
hc=0;
while(1)
{
fordog();
if(hc==11) //完成接收
{
hc=0;
ES=1;
initser();
take(); //进行处理
c41=1;
c42=1;
}
}
}
//--------------------------
//LED闪烁控制
//--------------------------
void T1_time() interrupt 1
{
TH0 =0xFC;
TL0 =0x66;
if(sm==1)//开始抢答,没有完成时
{
switch(choose)//每1ms进行一次切换
{
case 0x40:
choose=0x60;break;
case 0x60:
choose=0x40;break;
default:break;
}
}
num++;
if((num==1000)||(num==200&&sm==1)) //工作指示灯
{
led=~led;
num=0;
}
}
//-------------------------------
//串口中断程序
//-------------------------------
void ser_int(void) interrupt 4 //串口接收中断,连续接收
{
bit start=0;
if(RI)
{
if(SBUF==0x51)
{
rxd_buf[0]=SBUF;
start=1;
RI=0;
ES=0;
while(start==1)
{
for(hc=1;hc<11;hc++)
{
while(!RI);
rxd_buf[hc]=SBUF;
RI=0;
}
start=0;
sm=0;
}
}
}
if(TI) //接收中断不处理
{
TI=0;
}
}
使用了74LS164,485等 怕自己以后用了找不到
有兴趣的可以看看 不懂的可以问我 大家一起讨论
我也是新手