标题:
51单片机主,从机一拖二通信程序问题分析
[打印本页]
作者:
arcer1230
时间:
2019-4-22 14:02
标题:
51单片机主,从机一拖二通信程序问题分析
用51单片机设计了一拖二的控制系统一套。主机定时发送数据给从机,并要求从机回传数据给主机。主机发送的数据为2个字节,第一个字节为地址,第二个为数据,从机回复的数据也一样。主机将数据发送出去后,进行计时,在计时范围内接收到数据,即完成收发通信,计时完成后,仍然无法收到数据,认为数据接收失败。现在主机和从机之间通信正常.主,从机通信正常.从机设计了一个当无按键操作达到一定时间后,程序将进入一循环程序,一直执行循环程序,除非按下“唤醒”按键,程序跳出循环。现在程序好像无法进入循环,疑为通信程序影响所致。用STC-ISP的串口助手调试,将从机与电脑连接,点击"发送缓冲区---自动发送,可以定时休眠,点击"多字符串发送,勾选第1,2字符,此时就无法正常进入休眠状态.目前无法分析出原因,更不要提如何修改。求哪位敬爱的大师给予指导。贴程序:
主机程序
# include "config.h"
void UartDriver(); //串口驱动函数
void DelayX50ms(uchar8 t); //延时函数
void ConfigTimer0(); //定时器配置函数,定时3ms.模式1
void ConfigUART(); //串口配置函数
void OCProtect(); //过流检测函数
void PowCheck(uchar8 t,uchar8 addr); // 供电检测函数, 主机要发送给从机的数据
void UartSend(uchar8 addr); //串口发送函数
void DelayX10us(uchar8 t); //延时函数
void UartReceive(); //串口接收函数
void UartAction(uchar8 addr); //串口数据解析函数
void LedDisp(uchar8 temp); //LED显示函数
void ReturnPos(uchar8 addr); //复位函数
void UartRxMonitor(uchar8 ms); //总线监控函数
uchar8 OCBuf[2];
uchar8 RxdBuf[4];
uchar8 TxdBuf[4];
uchar8 buf[4];
uchar8 cntRxd=0; //字节接收计数
uchar8 PowCNTR=0; //供电检测计数
uchar8 PowSta=0xFF; //供电状态存储变量
bit OCflag=0; //过流标志
bit Txdflag=0; //字节发送完成标志
bit TxFr_Succ=0; //帧发送完成标志
bit RxFr_Succ=0; //帧接收完成标志
bit RxFr_Fail=0; //帧接收失败标志
main()
{
ROE=1;RA3=1;RA2=1;RA1=1; //释放所有继电器
Buz=0;
DelayX50ms(5);
Buz=1; //蜂鸣器响
P1=0x00;
DelayX50ms(5);
P1=0xFF; //数码管全亮,检测数码管是否能正常亮起,并提示系统启动
DIR485=0;
EA=1;
ConfigTimer0();
ConfigUART();
while(1)
{
OCProtect();
UartDriver();
}
}
//串口驱动函数
void UartDriver()
{
static uchar8 sl_select=1; //从机选择索引
switch(sl_select)
{
case 1:PowCheck(4,0x01); //检测供电状态,并发送
if(RxFr_Succ) //从机数据接收成功标志
{
RxFr_Succ=0;
UartReceive(); //串口读取函数
UartAction(0x01); //数据解析函数
if((buf[1]<0x03)||(buf[1]>0x11)) //有按键按下,有数据
{
sl_select++;
}
}
else if(RxFr_Fail) //从机数据接收失败标志
{
RxFr_Fail=0;
buf[1]=0xFF;
UartAction(0x01);
//ROE=1;RA3=1;RA2=1;RA1=1; Dis_Pin=0xFF;
sl_select++;
}
break;
case 2:PowCheck(4,0x02);
if(RxFr_Succ)
{
RxFr_Succ=0;
UartReceive();
UartAction(0x02);
if((buf[1]<0x03)||(buf[1]>0x11)) //有按键按下,有数据
{
sl_select--;
}
}
else if(RxFr_Fail)
{
RxFr_Fail=0;
buf[1]=0xFF;
UartAction(0x02);
//ROE=1;RA3=1;RA2=1;RA1=1; Dis_Pin=0xE2;
sl_select--;
}
break;
default:sl_select=1;break;
}
}
//延时函数,延时时间为t*50ms
void DelayX50ms(uchar8 t)
{
........
}
//T0配置函数,模式1,3ms.
void ConfigTimer0()
{
...........
}
//串口配置函数, 方式1, 9600
void ConfigUART()
{
........................
}
//过流保护函数,
void OCProtect()
{
....................
}
//供电状态检测,并发送给从机,t为检测时间控制变量,addr为从机地址
void PowCheck(uchar8 t,uchar8 addr)
{
if(PowCNTR>=t)
{
PowCNTR=0;
if(PowSta==0xFF)
{
TxdBuf[1]=0x12; //DC供电
}
else if(PowSta==0x00)
{
TxdBuf[1]=0x13; //BAT供电
}
else;
UartSend(addr); //将供电数据发送出去
}
}
//串口发送函数
void UartSend(uchar8 addr)
{
uchar8 len=0;
DIR485=1;
DelayX10us(2);
TxdBuf[0]=addr; //将即要发送的地址装入缓冲数组中
for(;len<2;len++)
{
Txdflag=0;
SBUF=TxdBuf[len];
while(!Txdflag);
DelayX10us(5);
}
DelayX10us(5);
DIR485=0;
//DelayX10us(5);
TxFr_Succ=1; //帧发送完成标志
}
//延时10us函数
void DelayX10us(uchar8 t)
{
....................
}
//串口接收函数
void UartReceive()
{
uchar8 len=0;
while(len<2)
{
buf[len]=RxdBuf[len];
len++;
}
cntRxd=0;
}
//串口接收数据解析函数,addr为发送地址
void UartAction(uchar8 addr)
{
if(buf[0]!=addr) //地址解析,接收到的地址字节与发送地址不相同,
{ return; } //返回
switch(buf[1]) //数据解析,解析接收到的数据字节
{
case 0x03:ReturnPos(addr);break;
case 0x04:ROE=0;RA3=0;RA2=0;RA1=0; LedDisp(1); break; //C1P为低电平
case 0x05:ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(2); break; //C2P向头平移
case 0x06:ROE=1;RA3=0;RA2=1;RA1=0; LedDisp(5); break; //C5P背板上升
case 0x07:ROE=0;RA3=1;RA2=1;RA1=0; LedDisp(11);break; //1#Y6 刹车
case 0x08:ROE=0;RA3=0;RA2=1;RA1=1; LedDisp(7); break; //C2N向脚平移
case 0x09:ROE=1;RA3=0;RA2=1;RA1=1; LedDisp(10);break; //C5N背板下降
case 0x0A:ROE=0;RA3=0;RA2=0;RA1=1; LedDisp(6); break; //C1N下降
case 0x0B:ROE=1;RA3=1;RA2=0;RA1=0; LedDisp(13);break; //2#Y4 腰升
case 0x0C:ROE=1;RA3=0;RA2=0;RA1=0; LedDisp(4); break; //C4P左倾
case 0x0D:ROE=0;RA3=1;RA2=1;RA1=1; LedDisp(12);break; //1#Y7 松刹车
case 0x0E:ROE=0;RA3=1;RA2=0;RA1=1; LedDisp(8); break; //C3N头降脚升
case 0x0F:ROE=1;RA3=1;RA2=0;RA1=1; LedDisp(14);break; //2#Y5 腰降
case 0x10:ROE=0;RA3=1;RA2=0;RA1=0; LedDisp(3); break; //C3P头升脚降
case 0x11:ROE=1;RA3=0;RA2=0;RA1=1; LedDisp(9); break; //C4N右倾
case 0xFF:ROE=1;RA3=1;RA2=1;RA1=1; Dis_Pin=0xFF;break; //释放所有继电器
default:ROE=1;RA3=1;RA2=1;RA1=1;Dis_Pin=0xFF;break;
}
}
//数码管显示函数
void LedDisp(uchar8 temp)
{
.................
}
//复位函数
void ReturnPos(uchar8 addr)
{
.......................
}
//串口接收监控函数,从发送完成后开始监控,监控的结果:1.接收成功,2.接收失败
void UartRxMonitor(uchar8 ms)
{
static uchar8 cntbkp=0;
static uchar8 idletmr=0; //总线空闲时间
if(TxFr_Succ) //帧发送成功后,才开始进行计时接收
{
if(cntRxd>0) //接收计数大于0,接收到字节,监控总线空闲时间
{
if(cntbkp!=cntRxd) //接收计数器改变,有新字节数据,清零总线空闲计数器
{
cntbkp=cntRxd;
idletmr=0;
}
else //接收计数器不改变,没有新字节数据,空闲计数器开始计数
{
if(idletmr<10) //小于20ms.
{
idletmr+=ms;
if(idletmr>=10) //大于等于20ms
{
RxFr_Succ=1; //接收成功
TxFr_Succ=0; //帧发送成功标志归0,不再进行总线空闲监控
idletmr=0;
}
}
}
}
else //从机不在线,未接收到从机数据
{
cntbkp=0;
if(idletmr<20)
{
idletmr+=ms;
if(idletmr>=20)
{
RxFr_Fail=1; //接收失败
TxFr_Succ=0;
idletmr=0;
}
}
}
}
}
//T0中断函数
void InterruptTimer0() interrupt 1
{
static uchar8 j=0;
static uchar8 i=0;
TH0=0xF5;
TL0=0x33;
OCBuf[0]=(OCBuf[0]<<1)|GL1; //第1路过流数据采集
OCBuf[1]=(OCBuf[1]<<1)|GL2; //第2路过流数据采集
if((OCBuf[0]==0x00)||(OCBuf[1]==0x00)) //有过流
{
i++;
OCBuf[0]=0xFF;
OCBuf[1]=0xFF;
if(i>=2)
{
i=0;
OCflag=1; //过流标志
}
}
PowSta=(PowSta<<1)|DcBat; //每隔2ms读取供电状态一次
j++;
if(j>=8)
{
j=0;
PowCNTR++;
}
UartRxMonitor(3); //UART空闲监控,
}
//串口中断函数
void InterruptUART() interrupt 4
{
if(RI)
{
RI=0;
RxdBuf[cntRxd]=SBUF;
cntRxd++;
}
if(TI)
{
TI=0;
Txdflag=1;
}
}
复制代码
从机程序
# include "config.h"
uint16 KeyBuf=0x0000; //按键缓冲
uint16 SlpCNTR=0x0000; //休眠索引
//uchar8 Slpbuf=0xFF; //休眠唤醒缓冲
uchar8 buf[4]; //读取数组
uchar8 TxdBuf[4]; //发送缓冲
bit ScanKeyCNTR=0; //按键扫描索引
uchar8 PowCNTR=0; //供电状态采集计数
uchar8 PowSta;
uchar8 RxdBuf[4]; //接收缓冲
uchar8 cntRxd=0; //接收计数
uchar8 Cobuf=0xFF; //按键编码缓冲
bit flagFrame=0; //帧接收完成标志
bit flagTxd=0; //字节接收完成标志
void UartDriver(); //串口驱动函数
void ConfigTimer0(); //T0配置函数,3ms,模式1
void ConfigUART(); //UART配置函数,方式1
void Delay60us(); //延时函数
void ScanKey(); //按键扫描函数
void KeyCode(); //按键编码函数
void SlpMode(); //休眠函数
void UartReceive(); //串口接收函数
void UartSend(uchar8 addr,uchar8 Txdata); //串口发送函数
void UartRxMonitor(uchar8 ms); //总线监控函数
void PowStaDisp(); //供电状态监控函数
void main()
{
P3M1=0x00;
P3M0=0x40;
P1M1=0x00;
P1M0=0x03;
_nop_();_nop_();
SleepDisp=1;
_nop_();_nop_();
PowDisp=0;
DIR_485=0;
ConfigTimer0();
ConfigUART();
while(1)
{
if(ScanKeyCNTR)
{
ScanKeyCNTR=0;
ScanKey();
KeyCode();
}
SlpMode();
PowStaDisp();
UartDriver();
}
}
//串口驱动函数
void UartDriver()
{
if(flagFrame)
{
flagFrame=0;
UartReceive();
if(buf[0]!=0x01)
{
return;
}
switch(buf[1])
{
case 0x12:PowSta=buf[1];break;
case 0x13:PowSta=buf[1];break;
default:break;
}
UartSend(buf[0],Cobuf);
}
}
//定时器配置函数
void ConfigTimer0()
{
................
}
//UART配置函数
void ConfigUART()
{
....................
}
//软件延时函数
void Delay60us() //?ó2? -0.049913194444us
{
...........................
}
//读取按键状态函数
void ScanKey()
{
...................
}
//按键编码函数,定时调用,执行
void KeyCode()
{
....................
}
//休眠函数
void SlpMode()
{
if(SlpCNTR>=SleepTime)
{
while(Wake_up!=0)
{
SlpCNTR=0; //休眠灯亮
SleepDisp=0;
PowStaDisp();
if(flagFrame)
{
flagFrame=0;
UartReceive();
if(buf[0]!=0x01)
{
return;
}
switch(buf[1])
{
case 0x12:PowSta=buf[1];break;
case 0x13:PowSta=buf[1];break;
default:break;
}
UartSend(buf[0],0xFF);
}
}
SleepDisp=1;
}
}
//串口接收函数
void UartReceive()
{
uchar8 len=0;
while(len<2)
{
buf[len]=RxdBuf[len];
len++;
}
cntRxd=0;
}
//串口发送函数
void UartSend(uchar8 addr,uchar8 Txdata)
{
uchar8 len=0;
DIR_485=1;
TxdBuf[0]=addr;
TxdBuf[1]=Txdata;
for(;len<2;len++)
{
flagTxd=0;
SBUF=TxdBuf[len];
while(!flagTxd);
Delay60us();
}
Delay60us();
DIR_485=0;
}
//串口接收监控函数,由空闲时间判断帧接收是否完成,在T0中断中调用,ms为定时间隔
void UartRxMonitor(uchar8 ms)
{
static uchar8 cntbkp=0;
static uchar8 idletmr=0;
if(cntRxd>0) //接收计数大于0,监控总线空闲时间
{
if(cntbkp!=cntRxd) //接收计数器改变,有新字节数据,清零总线空闲计数器
{
cntbkp=cntRxd;
idletmr=0;
}
else //接收计数器不改变,没有新字节数据,空闲计数器开始计数
{
if(idletmr<10)
{
idletmr+=ms;
if(idletmr>=10)
{
flagFrame=1;
}
}
}
}
else
{
cntbkp=0;
}
}
//供电状态显示函数,通过PowSta的值进行判断,PowSta的值来自串口接收
void PowStaDisp()
{
if(PowSta==0x12)
{
if(PowCNTR>=5)
{
PowCNTR=0;
PowDisp=(!PowDisp);
}
}
else if(PowSta==0x13)
{
if(PowCNTR>=160)
{
PowCNTR=0;
PowDisp=(!PowDisp); //LED灯每400ms亮灭一次
}
}
}
//T0中断函数
void InterruptTimer0() interrupt 1
{
TH0=0xF5;
TL0=0x33;
ScanKeyCNTR=(!ScanKeyCNTR); //按键扫描索引+1
if(KeyBuf==0xFFFF)
{
SlpCNTR++;
}
else
{
SlpCNTR=0;
}
PowCNTR++;
UartRxMonitor(3);
//Slpbuf=(Slpbuf<<1)|Wake_up;
}
//串口中断函数
void InterruptUART() interrupt 4
{
if(RI)
{
RI=0;
RxdBuf[cntRxd]=SBUF;
cntRxd++;
}
if(TI)
{
TI=0;
flagTxd=1;
}
}
复制代码
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1