MAX485两单片机半双工通信.docx
《MAX485两单片机半双工通信.docx》由会员分享,可在线阅读,更多相关《MAX485两单片机半双工通信.docx(16页珍藏版)》请在冰点文库上搜索。
MAX485两单片机半双工通信
#include
#defineuintunsignedint
#defineucharunsignedchar
sbitP0_0=P0^0;//定义P0^0为MAX485使能控制端口
ucharidatatable[17]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xaa,0xbd,0xee,0xdd,0x99,0xfd,0xff,0xff};//定义灯的16种状态
ucharidatatable2[10];//定义接收数据存放数组
ucharnum,temp;//设置temp变量,num为对应按键设定的编号
ucharnum1=0,flag;//设置flag为标志位,num1为发送和接收方选择变量
/************延时子函数*********/
voiddelay(uintz)//延时自函数
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
ucharkeyscan();
/************外部中断INT0实现接收子函数*********/
voidint0(void)interrupt0
{intm;
P1=0xff;//接收前先使接收方灯全部熄灭
for(m=0;m<5;m++)//输出按键发送的5次灯的状态
{P1=table2[m];
delay(500);//调用延时子函数
}
}
/***********T1,INT0中断初始化函数**************/
voidinit()
{TMOD=0x20;//设置定时器1为工作方式2
TH1=0xe8;//赋计数初值,对应定时26us
TL1=0xe8;
TR1=1;//T1中断开启
EA=1;//总中断开启
EX0=1;//外部中断INT0开启
IT0=1;//INT0方式下降沿有效
REN=1;//串行接收允许
SM0=0;//串行通信方式选择方式1
SM1=1;
}
/************接收子函数receive()***************/
voidreceive()//接收子函数
{RI=0;//接收中断开启
P0_0=0;//MAX485接收中断有效
do//握手过程
{
SBUF=0x01;//接收方向发送方发送0x01
while(TI==0);//发送,如果没发完则继续等待
TI=0;//发送成功,那么0->TI
while(RI==0);//发送方接收接受方的握手信号,若没收到继续等待
RI=0;//接收后,0-RI
}
while(SBUF!
=0x02);//接收到信号如果等于0x02那么握手成功,否则继续重新收发
while(!
RI);//如果没收到,继续等待
delay(500);//调用延时函数
P1=SBUF;//将收到的数据送到P1口显示
m=SBUF;//将收到的数据送到接收数组table2[n]中存放
table2[n]=m;
n++;
RI=0;//再次开启接收中断
}
/*************发送子函数send()************/
voidsend()
{flag=1;//flag标志位赋值,控制按键有效
do//握手信号
{SBUF=0x02;//发送方给接收方发送握手信号0x02
while(TI==0);//如果没发送完,那么继续等待
TI=0;//发送成功,那么0->TI
while(RI==0);//发送方接收接受方发送的握手信号,若没收到,继续等待
RI=0;//若收到,0->RI
}
while(SBUF!
=0x01);//接收到信号如果等于0x01那么握手成功,否则继续重新收发
while(flag)i=keyscan();//将扫描的键盘编码对应的num号码赋值给i
flag=1;
P0_0=1;//设置MAX485发送使能端有效
TI=0;//开启发送中断
SBUF=table[i-1];//将设置数组中的数赋值给发送缓冲区
while(!
TI);//如果没发送完,那么继续等待
P1=table[i-1];//将设置数组中的数赋值给发送P1
TI=0;//若收到,0->TI
}
/*************主函数main()*************/
voidmain()
{ucharn=0;//设定初始变量n,m,i
ucharm;
uchari=0;
flag=1;//flag标志位赋值,控制按键有效
voidinit();//调用T1,INT0中断初始化函数
while(flag)i=keyscan();//将扫描的键盘编码对应的num号码赋值给i
flag=1;//flag标志位赋值,控制按键有效
while
(1)
{if(num1==0)//如果num1=0,那么对应为接收方
{
voidreceive();//调用接收子函数
}
elseif(num1==1)//如果num1=1,那么对应为发送方
{
voidsend();//调用发送子函数
}
}
}
/**************矩阵键盘4*4函数*************/
ucharkeyscan()
{P2=0xfe;//选中第四列
temp=P2;
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数,软件防抖动
{delay(5);//延时函数调用
temp=P2;//P2口数据送入temp
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数
{temp=P2;//P2口数据送入temp
switch(temp)//选择所按键的键码
{
case0xee:
{num=1;flag=0;}break;//第四列第一行按键编号为1
case0xde:
{num=2;flag=0;}break;//第四列第二行按键编号为2
case0xbe:
{num=3;flag=0;}break;//第四列第三行按键编号为3
case0x7e:
{num=4;flag=0;}break;//第四列第四行按键编号为4
}
while(temp!
=0xf0)//去抖动,并且实现下一次按键的扫描
{temp=P2;
temp=temp&0xf0;
}
}
}
P2=0xfd;//选中第三列
temp=P2;
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数,软件防抖动
{delay(5);//延时函数调用
temp=P2;//P2口数据送入temp
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数
{temp=P2;//P2口数据送入temp
switch(temp)//选择所按键的键码
{case0xed:
{num=5;flag=0;}break;//第三列第一行按键编号为5
case0xdd:
{num=6;flag=0;}break;//第三列第二行按键编号为6
case0xbd:
{num=7;flag=0;}break;//第三列第三行按键编号为7
case0x7d:
{num=8;flag=0;}break;//第三列第四行按键编号为8
}
while(temp!
=0xf0)//去抖动,并且实现下一次按键的扫描
{temp=P2;
temp=temp&0xf0;
}
}
}
P2=0xfb;//选中第二列
temp=P2;
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数,软件防抖动
{delay(5);//延时函数调用
temp=P2;//P2口数据送入temp
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数
{temp=P2;//P2口数据送入temp
switch(temp)//选择所按键的键码
{case0xeb:
{num=9;flag=0;}break;//第二列第一行按键编号为9
case0xdb:
{num=10;flag=0;}break;//第二列第二行按键编号为10
case0xbb:
{num=11;flag=0;}break;//第二列第三行按键编号为11
case0x7b:
{num=12;flag=0;}break;//第二列第四行按键编号为12
}
while(temp!
=0xf0)//去抖动,并且实现下一次按键的扫描
{temp=P2;
temp=temp&0xf0;
}
}
}
P2=0xf7;//选中第一列
temp=P2;
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数,软件防抖动
{delay(5);//延时函数调用
temp=P2;//P2口数据送入temp
temp=temp&0xf0;//取P2口数据的高四位,对应为按键的行扫描码
while(temp!
=0xf0)//如果有按键按下执行以下子函数
{temp=P2;//P2口数据送入temp
switch(temp)//选择所按键的键码
{case0xe7:
{num=13;flag=0;}break;//第一列第一行按键编号为13
case0xd7:
{num=14;flag=0;}break;//第一列第二行按键编号为14
case0xb7:
{num=15;num1=1;flag=0;}break;//第一列第三行按键编号为15
case0x77:
{num=16;flag=0;num1=0;}break;//第一列第四行按键编号为16
}
while(temp!
=0xf0)//去抖动,并且实现下一次按键的扫描
{temp=P2;
temp=temp&0xf0;
}
}
}
returnnum;//返回对应按键的标号
returnflag;//返回对应按键子函数的控制标志位
}
图:
硬件仿真总原理图
如图所示,系统总的硬件仿真原理图中包含了单片机系统的时钟电路,复位电路,矩阵键盘
4*4电路,即灯显示电路,MAX485串行半双工连接电路的相应电路模块,其中通过选择第三行第一列的按键为发送方,选择第四行第一列的按键为接收方,而且在同一个矩阵键盘中不可以同时按这两个键,通过这种选择可是实现分时的发送和接收,满足半双工的通信方式,其中选择完后,在发送方的矩阵键盘中选择按键,每按一个按键,对应的灯状态在发送和接收两方的P1口显示其的灯状态,连续按5次后,对应灯状态也显示5次,再在接收方的INT0按键按下,可以再次显示刚才5次按键对应灯状态的连续显示。
设定仿真图上上面的单片机系统为甲,下面的单片机系统为乙,以下所有的仿真结果均采用
此设定,并且按照先前的程序可以得知对应矩阵的标号,(不是按键的键码)为下表所示:
表6.1仿真图对应的矩阵键盘的按键标号
行列
1
2
3
4
1
13
9
5
1
2
14
10
6
2
3
15
11
7
3
4
16
12
8
4
如表6.1仿真图对应的矩阵键盘的按键标号,其中表的第一行为对应的列号,左方第一列为对应的行号,中间为对应矩阵键盘的标号,即程序中的num号
(1)仿真结果1
图6.1甲单片机(上面)为发送机,乙单片机(下)为接收机的仿真结果一
通过选择甲矩阵键盘的第三行第一列,对应标号为15选择甲单片机(上)为发送机,通过选择甲矩阵键盘的第四行第一列,对应标号为16选择乙单片机为接收机,对应按键1为对应甲乙两单片机的P1^0口的灯显示亮。
(2)仿真结果2
图6.2甲单片机(上面)为发送机,乙单片机(下)为接收机的仿真结果二
通过选择甲矩阵键盘的第三行第一列,对应标号为15选择甲单片机(上)为发送机,通过选择甲矩阵键盘的第四行第一列,对应标号为16选择乙单片机为接收机,对应按键5为对应甲乙两单片机的P1^4口的灯显示亮。
(3)仿真结果3
图6.3甲单片机(上面)为发送机,乙单片机(下)为接收机的仿真结果三
通过选择甲矩阵键盘的第三行第一列,对应标号为15选择甲单片机(上)为发送机,通过选择甲矩阵键盘的第四行第一列,对应标号为16选择乙单片机为接收机,对应按键9为对应甲乙两单片机的P1^0,P1^2,P1^4,P1^6口的灯显示亮。
(4)仿真结果4
图6.4甲单片机(上面)为发送机,乙单片机(下)为接收机的仿真结果四
通过选择甲矩阵键盘的第三行第一列,对应标号为15选择甲单片机(上)为发送机,通过选择甲矩阵键盘的第四行第一列,对应标号为16选择乙单片机为接收机,对应按键10为对应甲乙两单片机的P1^0,P1^4口的灯显示亮。
(5)仿真结果5
图6.5甲单片机(上面)为发送机,乙单片机(下)为接收机的仿真结果五
通过选择甲矩阵键盘的第三行第一列,对应标号为15选择甲单片机(上)为发送机,通过选择甲矩阵键盘的第四行第一列,对应标号为16选择乙单片机为接收机,对应按键13为对应甲乙两单片机的P1^1,P1^2,P1^5,P1^6口的灯显示亮。
(a)接受方P3.2按键按下(b)P1^0口对应的灯亮
(c)P1^1口对应的灯亮(d)P1^0,P1^2,P1^4,P1^6口对应的灯亮
(e)P1^1,P1^4口对应的灯亮(f)P1^1,P1^2,P1^5,P1^6口对应的灯亮
图6.6乙单片机(下)接收机对应INT0按键按下后灯得5种状态的仿真结果六
如图6.6乙单片机(下)接收机对应INT0按键按下后灯得5种状态(b)-(e)与图6.1到6.5所对应的五种仿真结果想一致,即接收方按INT0按键可以将刚才的5种按键对应的灯状态输出。
当在甲机中选择按键16,乙单片机选择按键15可以实现设定甲机为接收机,乙机为发送机,对应的仿真结果与上述一致,在这里省略。