找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1125|回复: 0
打印 上一主题 下一主题
收起左侧

51单片机主,从机一拖二通信程序问题分析

[复制链接]
跳转到指定楼层
楼主
ID:479916 发表于 2019-4-22 14:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用51单片机设计了一拖二的控制系统一套。主机定时发送数据给从机,并要求从机回传数据给主机。主机发送的数据为2个字节,第一个字节为地址,第二个为数据,从机回复的数据也一样。主机将数据发送出去后,进行计时,在计时范围内接收到数据,即完成收发通信,计时完成后,仍然无法收到数据,认为数据接收失败。现在主机和从机之间通信正常.主,从机通信正常.从机设计了一个当无按键操作达到一定时间后,程序将进入一循环程序,一直执行循环程序,除非按下“唤醒”按键,程序跳出循环。现在程序好像无法进入循环,疑为通信程序影响所致。用STC-ISP的串口助手调试,将从机与电脑连接,点击"发送缓冲区---自动发送,可以定时休眠,点击"多字符串发送,勾选第1,2字符,此时就无法正常进入休眠状态.目前无法分析出原因,更不要提如何修改。求哪位敬爱的大师给予指导。贴程序:

主机程序
  1. # include "config.h"
  2. void UartDriver();                                          //串口驱动函数
  3. void DelayX50ms(uchar8 t);                          //延时函数
  4. void ConfigTimer0();                                 //定时器配置函数,定时3ms.模式1
  5. void ConfigUART();                                   //串口配置函数
  6. void OCProtect();                                         //过流检测函数
  7. void PowCheck(uchar8 t,uchar8 addr);       // 供电检测函数,     主机要发送给从机的数据  
  8. void UartSend(uchar8 addr);                     //串口发送函数
  9. void DelayX10us(uchar8 t);                           //延时函数
  10. void UartReceive();                                   //串口接收函数
  11. void UartAction(uchar8 addr);                   //串口数据解析函数
  12. void LedDisp(uchar8 temp);                     //LED显示函数
  13. void ReturnPos(uchar8 addr);                  //复位函数
  14. void UartRxMonitor(uchar8 ms);              //总线监控函数


  15. uchar8 OCBuf[2];
  16. uchar8 RxdBuf[4];
  17. uchar8 TxdBuf[4];
  18. uchar8 buf[4];
  19. uchar8 cntRxd=0;                    //字节接收计数
  20. uchar8 PowCNTR=0;                   //供电检测计数
  21. uchar8 PowSta=0xFF;                 //供电状态存储变量
  22. bit OCflag=0;                       //过流标志
  23. bit Txdflag=0;                      //字节发送完成标志
  24. bit TxFr_Succ=0;                    //帧发送完成标志
  25. bit RxFr_Succ=0;                    //帧接收完成标志
  26. bit RxFr_Fail=0;                      //帧接收失败标志


  27. main()
  28. {
  29.    ROE=1;RA3=1;RA2=1;RA1=1;         //释放所有继电器
  30.    Buz=0;
  31.    DelayX50ms(5);
  32.    Buz=1;                           //蜂鸣器响
  33.    P1=0x00;
  34.    DelayX50ms(5);
  35.    P1=0xFF;                         //数码管全亮,检测数码管是否能正常亮起,并提示系统启动
  36.    DIR485=0;
  37.    EA=1;
  38.    ConfigTimer0();
  39.    ConfigUART();
  40.    while(1)
  41.    {
  42.       OCProtect();
  43.       UartDriver();
  44.    }
  45. }

  46. //串口驱动函数
  47. void UartDriver()
  48. {
  49.    static uchar8 sl_select=1;                             //从机选择索引
  50.    switch(sl_select)
  51.    {
  52.       case 1:PowCheck(4,0x01);                            //检测供电状态,并发送
  53.                if(RxFr_Succ)                                //从机数据接收成功标志
  54.                {
  55.                   RxFr_Succ=0;
  56.                   UartReceive();                            //串口读取函数
  57.                   UartAction(0x01);                         //数据解析函数
  58.                   if((buf[1]<0x03)||(buf[1]>0x11))                        //有按键按下,有数据
  59.                   {
  60.                      sl_select++;                                                                              
  61.                   }
  62.                }
  63.                else if(RxFr_Fail)                           //从机数据接收失败标志
  64.                {
  65.                   RxFr_Fail=0;
  66.                   buf[1]=0xFF;
  67.                   UartAction(0x01);
  68.                   //ROE=1;RA3=1;RA2=1;RA1=1; Dis_Pin=0xFF;
  69.                   sl_select++;
  70.                }
  71.                break;
  72.       case 2:PowCheck(4,0x02);
  73.                if(RxFr_Succ)
  74.                {
  75.                   RxFr_Succ=0;
  76.                   UartReceive();
  77.                   UartAction(0x02);
  78.                   if((buf[1]<0x03)||(buf[1]>0x11))                        //有按键按下,有数据
  79.                   {
  80.                       sl_select--;                                                                                       
  81.                   }
  82.                }
  83.                else if(RxFr_Fail)
  84.                {
  85.                   RxFr_Fail=0;
  86.                   buf[1]=0xFF;
  87.                   UartAction(0x02);
  88.                   //ROE=1;RA3=1;RA2=1;RA1=1; Dis_Pin=0xE2;
  89.                   sl_select--;
  90.                }
  91.                break;
  92.       default:sl_select=1;break;
  93.    }
  94. }

  95. //延时函数,延时时间为t*50ms
  96. void DelayX50ms(uchar8 t)
  97. {
  98.    ........
  99. }

  100. //T0配置函数,模式1,3ms.
  101. void ConfigTimer0()
  102. {
  103.    ...........
  104. }

  105. //串口配置函数,    方式1,    9600
  106. void ConfigUART()
  107. {
  108.    ........................      
  109. }

  110. //过流保护函数,
  111. void OCProtect()
  112. {
  113.    ....................
  114. }

  115. //供电状态检测,并发送给从机,t为检测时间控制变量,addr为从机地址
  116. void PowCheck(uchar8 t,uchar8 addr)
  117. {
  118.    if(PowCNTR>=t)
  119.    {
  120.       PowCNTR=0;
  121.       if(PowSta==0xFF)                    
  122.       {
  123.          TxdBuf[1]=0x12;                     //DC供电
  124.       }
  125.       else if(PowSta==0x00)
  126.       {
  127.          TxdBuf[1]=0x13;                     //BAT供电
  128.       }
  129.       else;
  130.       UartSend(addr);                        //将供电数据发送出去
  131.    }
  132. }

  133. //串口发送函数
  134. void UartSend(uchar8 addr)
  135. {
  136.    uchar8 len=0;
  137.    DIR485=1;
  138.    DelayX10us(2);
  139.    TxdBuf[0]=addr;                        //将即要发送的地址装入缓冲数组中
  140.    for(;len<2;len++)
  141.    {
  142.       Txdflag=0;
  143.       SBUF=TxdBuf[len];
  144.       while(!Txdflag);
  145.       DelayX10us(5);
  146.    }
  147.    DelayX10us(5);
  148.    DIR485=0;
  149.    //DelayX10us(5);
  150.    TxFr_Succ=1;                           //帧发送完成标志
  151. }

  152. //延时10us函数
  153. void DelayX10us(uchar8 t)
  154. {
  155.    ....................
  156. }

  157. //串口接收函数
  158. void UartReceive()
  159. {
  160.    uchar8 len=0;
  161.         while(len<2)
  162.         {
  163.                 buf[len]=RxdBuf[len];
  164.       len++;
  165.         }
  166.         cntRxd=0;
  167. }

  168. //串口接收数据解析函数,addr为发送地址
  169. void UartAction(uchar8 addr)
  170. {
  171.    if(buf[0]!=addr)                                    //地址解析,接收到的地址字节与发送地址不相同,
  172.       { return;   }                                         //返回
  173.    switch(buf[1])                                       //数据解析,解析接收到的数据字节
  174.    {
  175.       case 0x03:ReturnPos(addr);break;
  176.                 case 0x04:ROE=0;RA3=0;RA2=0;RA1=0; LedDisp(1); break;                 //C1P为低电平
  177.                 case 0x05:ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(2); break;                 //C2P向头平移
  178.                 case 0x06:ROE=1;RA3=0;RA2=1;RA1=0; LedDisp(5); break;                 //C5P背板上升
  179.                 case 0x07:ROE=0;RA3=1;RA2=1;RA1=0; LedDisp(11);break;                //1#Y6  刹车
  180.                 case 0x08:ROE=0;RA3=0;RA2=1;RA1=1; LedDisp(7); break;                //C2N向脚平移
  181.                 case 0x09:ROE=1;RA3=0;RA2=1;RA1=1; LedDisp(10);break;                //C5N背板下降
  182.                 case 0x0A:ROE=0;RA3=0;RA2=0;RA1=1; LedDisp(6); break;                //C1N下降
  183.                 case 0x0B:ROE=1;RA3=1;RA2=0;RA1=0; LedDisp(13);break;                //2#Y4  腰升
  184.                 case 0x0C:ROE=1;RA3=0;RA2=0;RA1=0; LedDisp(4); break;                //C4P左倾
  185.                 case 0x0D:ROE=0;RA3=1;RA2=1;RA1=1; LedDisp(12);break;                //1#Y7 松刹车
  186.                 case 0x0E:ROE=0;RA3=1;RA2=0;RA1=1; LedDisp(8); break;                //C3N头降脚升
  187.                 case 0x0F:ROE=1;RA3=1;RA2=0;RA1=1; LedDisp(14);break;                //2#Y5  腰降
  188.                 case 0x10:ROE=0;RA3=1;RA2=0;RA1=0; LedDisp(3); break;                //C3P头升脚降
  189.                 case 0x11:ROE=1;RA3=0;RA2=0;RA1=1; LedDisp(9); break;                //C4N右倾      
  190.                 case 0xFF:ROE=1;RA3=1;RA2=1;RA1=1; Dis_Pin=0xFF;break;                //释放所有继电器
  191.                 default:ROE=1;RA3=1;RA2=1;RA1=1;Dis_Pin=0xFF;break;
  192.    }
  193. }

  194. //数码管显示函数
  195. void LedDisp(uchar8 temp)
  196. {
  197. .................
  198. }

  199. //复位函数
  200. void ReturnPos(uchar8 addr)
  201. {
  202. .......................      
  203. }

  204. //串口接收监控函数,从发送完成后开始监控,监控的结果:1.接收成功,2.接收失败
  205. void UartRxMonitor(uchar8 ms)
  206. {
  207.         static uchar8 cntbkp=0;
  208.         static uchar8 idletmr=0;                //总线空闲时间
  209.         if(TxFr_Succ)                             //帧发送成功后,才开始进行计时接收
  210.         {     
  211.                 if(cntRxd>0)                                                              //接收计数大于0,接收到字节,监控总线空闲时间
  212.                 {
  213.                         if(cntbkp!=cntRxd)                                           //接收计数器改变,有新字节数据,清零总线空闲计数器
  214.                         {
  215.                                 cntbkp=cntRxd;
  216.                                 idletmr=0;
  217.                         }
  218.                         else                                                                         //接收计数器不改变,没有新字节数据,空闲计数器开始计数
  219.                         {
  220.                                 if(idletmr<10)                     //小于20ms.
  221.                                 {
  222.                                         idletmr+=ms;
  223.                                         if(idletmr>=10)                //大于等于20ms
  224.                                         {
  225.                                                 RxFr_Succ=1;                                   //接收成功
  226.                                                 TxFr_Succ=0;                                 //帧发送成功标志归0,不再进行总线空闲监控
  227.                                                 idletmr=0;
  228.                                         }
  229.                                 }
  230.                         }
  231.                 }
  232.                 else                                   //从机不在线,未接收到从机数据
  233.                 {
  234.                         cntbkp=0;
  235.                         if(idletmr<20)
  236.                         {
  237.                                 idletmr+=ms;
  238.                                 if(idletmr>=20)
  239.                                 {
  240.                                         RxFr_Fail=1;                                      //接收失败
  241.                                         TxFr_Succ=0;
  242.                                         idletmr=0;
  243.                                 }
  244.                         }
  245.                 }
  246.         }
  247. }

  248. //T0中断函数
  249. void InterruptTimer0() interrupt 1
  250. {
  251.    static uchar8 j=0;
  252.    static uchar8 i=0;
  253.    TH0=0xF5;
  254.    TL0=0x33;
  255.    OCBuf[0]=(OCBuf[0]<<1)|GL1;                  //第1路过流数据采集
  256.         OCBuf[1]=(OCBuf[1]<<1)|GL2;                  //第2路过流数据采集
  257.         if((OCBuf[0]==0x00)||(OCBuf[1]==0x00))       //有过流
  258.         {
  259.                 i++;
  260.                 OCBuf[0]=0xFF;
  261.                 OCBuf[1]=0xFF;
  262.                 if(i>=2)
  263.                 {
  264.                         i=0;
  265.                         OCflag=1;                              //过流标志
  266.                 }
  267.         }
  268.    PowSta=(PowSta<<1)|DcBat;                                         //每隔2ms读取供电状态一次
  269.         j++;
  270.         if(j>=8)
  271.         {
  272.                 j=0;
  273.                 PowCNTR++;
  274.         }
  275.    UartRxMonitor(3);                            //UART空闲监控,
  276. }
  277. //串口中断函数
  278. void InterruptUART() interrupt 4
  279. {
  280.    if(RI)
  281.    {
  282.       RI=0;
  283.       RxdBuf[cntRxd]=SBUF;
  284.       cntRxd++;
  285.    }
  286.    if(TI)
  287.    {
  288.       TI=0;
  289.       Txdflag=1;
  290.    }
  291. }
复制代码

从机程序
  1. # include "config.h"


  2. uint16 KeyBuf=0x0000;                        //按键缓冲
  3. uint16 SlpCNTR=0x0000;                                        //休眠索引
  4. //uchar8 Slpbuf=0xFF;                                //休眠唤醒缓冲
  5. uchar8 buf[4];                                                //读取数组
  6. uchar8 TxdBuf[4];                                    //发送缓冲
  7. bit ScanKeyCNTR=0;                        //按键扫描索引
  8. uchar8 PowCNTR=0;                    //供电状态采集计数
  9. uchar8 PowSta;
  10. uchar8 RxdBuf[4];                         //接收缓冲
  11. uchar8 cntRxd=0;                         //接收计数
  12. uchar8 Cobuf=0xFF;                                                                                //按键编码缓冲


  13. bit flagFrame=0;                                        //帧接收完成标志
  14. bit flagTxd=0;                                                //字节接收完成标志


  15. void UartDriver();                                      //串口驱动函数
  16. void ConfigTimer0();                                 //T0配置函数,3ms,模式1
  17. void ConfigUART();                                    //UART配置函数,方式1
  18. void Delay60us();                                    //延时函数
  19. void ScanKey();                                        //按键扫描函数
  20. void KeyCode();                                       //按键编码函数
  21. void SlpMode();                                                 //休眠函数
  22. void UartReceive();                                        //串口接收函数
  23. void UartSend(uchar8 addr,uchar8 Txdata);              //串口发送函数
  24. void UartRxMonitor(uchar8 ms);                           //总线监控函数
  25. void PowStaDisp();                                             //供电状态监控函数




  26. void main()
  27. {
  28.         P3M1=0x00;
  29.         P3M0=0x40;
  30.         P1M1=0x00;
  31.         P1M0=0x03;
  32.    _nop_();_nop_();
  33.    SleepDisp=1;
  34.    _nop_();_nop_();
  35.         PowDisp=0;                                       
  36.         DIR_485=0;                                       
  37.         ConfigTimer0();
  38.         ConfigUART();
  39.         while(1)
  40.         {
  41.                 if(ScanKeyCNTR)
  42.                 {
  43.                         ScanKeyCNTR=0;
  44.                         ScanKey();
  45.                         KeyCode();
  46.                 }
  47.                SlpMode();
  48.                 PowStaDisp();
  49.                 UartDriver();
  50.         }
  51. }
  52. //串口驱动函数
  53. void UartDriver()
  54. {
  55.         if(flagFrame)
  56.         {
  57.                 flagFrame=0;
  58.                 UartReceive();
  59.                 if(buf[0]!=0x01)
  60.                 {
  61.                         return;
  62.                 }
  63.                 switch(buf[1])
  64.                 {
  65.                         case 0x12:PowSta=buf[1];break;
  66.                         case 0x13:PowSta=buf[1];break;
  67.                         default:break;
  68.                 }
  69.                 UartSend(buf[0],Cobuf);
  70.         }
  71. }
  72. //定时器配置函数
  73. void ConfigTimer0()
  74. {
  75.         ................
  76. }
  77. //UART配置函数
  78. void ConfigUART()
  79. {
  80.         ....................
  81. }
  82. //软件延时函数
  83. void Delay60us()   //?ó2? -0.049913194444us
  84. {
  85.    ...........................
  86. }
  87. //读取按键状态函数
  88. void ScanKey()
  89. {
  90.         ...................
  91. }
  92. //按键编码函数,定时调用,执行
  93. void KeyCode()
  94. {
  95.         ....................
  96. }
  97. //休眠函数
  98. void SlpMode()
  99. {
  100.         if(SlpCNTR>=SleepTime)
  101.         {
  102.                 while(Wake_up!=0)
  103.                 {
  104.          SlpCNTR=0;                             //休眠灯亮
  105.          SleepDisp=0;                                          
  106.          PowStaDisp();
  107.                         if(flagFrame)
  108.                         {
  109.                                 flagFrame=0;
  110.                                 UartReceive();
  111.                                 if(buf[0]!=0x01)
  112.                                 {
  113.                                         return;
  114.                                 }
  115.                                 switch(buf[1])
  116.                                 {
  117.                                         case 0x12:PowSta=buf[1];break;
  118.                                         case 0x13:PowSta=buf[1];break;
  119.                                         default:break;
  120.                                 }
  121.                                 UartSend(buf[0],0xFF);
  122.                         }
  123.                 }
  124.                 SleepDisp=1;
  125.         }
  126. }
  127. //串口接收函数
  128. void UartReceive()
  129. {
  130.         uchar8 len=0;
  131.         while(len<2)
  132.         {
  133.                 buf[len]=RxdBuf[len];
  134.       len++;
  135.         }
  136.         cntRxd=0;
  137. }
  138. //串口发送函数
  139. void UartSend(uchar8 addr,uchar8 Txdata)
  140. {
  141.         uchar8 len=0;
  142.         DIR_485=1;
  143.         TxdBuf[0]=addr;
  144.         TxdBuf[1]=Txdata;
  145.         for(;len<2;len++)
  146.         {
  147.                 flagTxd=0;
  148.                 SBUF=TxdBuf[len];
  149.                 while(!flagTxd);
  150.                 Delay60us();
  151.         }
  152.    Delay60us();
  153.         DIR_485=0;
  154. }
  155. //串口接收监控函数,由空闲时间判断帧接收是否完成,在T0中断中调用,ms为定时间隔
  156. void UartRxMonitor(uchar8 ms)
  157. {
  158.         static uchar8 cntbkp=0;
  159.         static uchar8 idletmr=0;
  160.         if(cntRxd>0)                                                        //接收计数大于0,监控总线空闲时间
  161.         {
  162.                 if(cntbkp!=cntRxd)                                        //接收计数器改变,有新字节数据,清零总线空闲计数器
  163.                 {
  164.                         cntbkp=cntRxd;
  165.                         idletmr=0;
  166.                 }
  167.                 else                                                                //接收计数器不改变,没有新字节数据,空闲计数器开始计数
  168.                 {
  169.                         if(idletmr<10)
  170.                         {
  171.                                 idletmr+=ms;
  172.                                 if(idletmr>=10)
  173.                                 {
  174.                                         flagFrame=1;
  175.                                 }
  176.                         }
  177.                 }
  178.         }
  179.         else
  180.         {
  181.                 cntbkp=0;
  182.         }
  183. }
  184. //供电状态显示函数,通过PowSta的值进行判断,PowSta的值来自串口接收
  185. void PowStaDisp()
  186. {
  187.         if(PowSta==0x12)
  188.         {
  189.                 if(PowCNTR>=5)
  190.                 {
  191.                         PowCNTR=0;
  192.                         PowDisp=(!PowDisp);
  193.                 }
  194.         }
  195.         else if(PowSta==0x13)
  196.         {
  197.                 if(PowCNTR>=160)
  198.                 {
  199.                         PowCNTR=0;
  200.                         PowDisp=(!PowDisp);                        //LED灯每400ms亮灭一次
  201.                 }
  202.         }
  203. }
  204. //T0中断函数
  205. void InterruptTimer0() interrupt 1
  206. {
  207.         TH0=0xF5;
  208.         TL0=0x33;
  209.         ScanKeyCNTR=(!ScanKeyCNTR);                                        //按键扫描索引+1
  210.         if(KeyBuf==0xFFFF)
  211.         {
  212.                 SlpCNTR++;
  213.         }
  214.         else
  215.         {
  216.                 SlpCNTR=0;
  217.         }
  218.         PowCNTR++;
  219.         UartRxMonitor(3);
  220.         //Slpbuf=(Slpbuf<<1)|Wake_up;
  221. }
  222. //串口中断函数
  223. void InterruptUART() interrupt 4
  224. {
  225.         if(RI)
  226.         {
  227.                 RI=0;
  228.                 RxdBuf[cntRxd]=SBUF;
  229.       cntRxd++;
  230.         }
  231.         if(TI)
  232.         {
  233.                 TI=0;
  234.                 flagTxd=1;
  235.         }
  236. }
复制代码



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表