找回密码
 立即注册

QQ登录

只需一步,快速开始

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

RS485通信主机呼叫单片机从机,1主15从,发送地址问题

[复制链接]
跳转到指定楼层
楼主
问题:主机由按键启动,按下按键后开始随机发送地址,最多15次呼叫地址,但是在while这个循环里面地址是一直发送状态会堵塞RS485总线,而没有进入状态机的第二步进行应答确认,包括第三部的接收数据确认,请教一下 这个呼叫地址如何不会堵塞总线的方式。

单片机程序在2楼
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:973561 发表于 2022-6-13 19:22 | 只看该作者
while(1)                 {                                          if(KEY0 == 0)                          {                                   delay_ms(20);                                   if(KEY0 == 0)                                         {                                key_flag =!key_flag;                             }                          }                                                    if(key_flag == 1 && send_datacnt<= 15)                          {                                  volatile uchar step = 0;                                                              switch(step)                                         {                                                 //进入地址发送步骤                                                 case 0 :                                                                                              send_data();                //发送一帧数据                                                                                 send_datacnt++;             //发送数据计数                                                                                 send_addrflag = 1;         //开启发送完成标志位后定时器开始计时                           step = 1;                                                                                                          break;                                                                                                                                          case 1 :                                                                                                                                  if(ack_flag == 1)      //等待接收应答信号,如果没有应答信号表示设备不在线就马上再次发送下一个地址                                                                                                 {                                                                                                            ack_flag = 0;    //                                                                                                          step = 2;                                                                                                                 // led1 = 1;                                                                                                          clr_recvbuffer(recv_buf); //        清除这一帧应答数据,等待下一帧数据过来                                                                                                                                                                         }                                                                                 else                                                                                                  {                                                                                                                                                                                                                           step = 0;                                                                                                                                                                         }                                                                                                                                                                                                                  break;                                                                                                                                                                                                                                                            case 2:                                                                                                                 revc_data();    //接收数据                                                                                  if(noeffec_dataflag == 1)  //如果接收到的是无效数据就再次从发数据                                                                                 {                                                                                          noeffec_dataflag = 0;   //数据状态标志位清零                                                                                          step = 0;     //状态机返回第0步                                                                                                                                                                          }                                                                         else if(effec_dataflag ==1)     //如果接收到的是有效数据就转入第二步                                                                                 {                                                                                          effec_dataflag = 0;                                                                                          step = 3;                                                                                 }                                                                                         break;                                                                                                                                          case 3:                                                                                                         if(send_datacnt >= 15)   //如果发送的次数大于15  游戏停止                                                                                         {                                                                                                         //game_stop = 1;                                                                                                                                                                    //step = 0;                                                                                                   key_flag = 0;                                                                                                   send_datacnt = 0;                                                                                         }                                                                                         else                                                                                                  {                                                                                                         step = 0;     //如果发送的次数小于15  游戏继续                                                                                                 }                                                                          break;                                                                                                                                                   }                                                     }                           //                        else  //         { //                                   return; //                                 }                         //KeyRead();   //扫描按键是否按下                         //KeyProc();         //按下就启动游戏                                                                  while(1)         {               if (Intrcnt>20)     // 一直在等,直到20ms时间到,每隔20ms扫描一次大循环               {                    Intrcnt=0;                    break;       // 返回主循环               }         }
回复

使用道具 举报

板凳
ID:415064 发表于 2022-6-14 09:11 | 只看该作者
先把排版整理下吧
回复

使用道具 举报

地板
ID:161164 发表于 2022-6-14 10:11 | 只看该作者
请用代码模式来贴代码


回复

使用道具 举报

5#
ID:161164 发表于 2022-6-14 10:20 | 只看该作者
本帖最后由 lkc8210 于 2022-6-14 10:47 编辑

你case 1到case 2 的时间有多长有算过或测过吗?
这时间足以让从机收到信号并返回应答信号吗?
回复

使用道具 举报

6#
ID:973561 发表于 2022-6-15 09:11 | 只看该作者
  1. unsigned char keyscan()
  2. {
  3.         unsigned char keynum = 0;
  4.         if(KEY0 == 0)
  5.         {
  6.                  delay_ms(10);
  7.            if(KEY0 == 0)
  8.                  {
  9.                     //keynum =!keynum;       
  10.                           keynum = 1;       
  11.                  }while(KEY0 == 0);       
  12.         }
  13.         return keynum;
  14. }
复制代码


扫描按键,按下就启动发送向从机发送数据
  1.                         switch(step)
  2.                         {
  3.                                 //进入地址发送步骤
  4.                                 case 0 :   
  5.                                                              
  6.                                          send_data();                //发送一帧数据
  7.                                         send_datacnt++;             //发送数据计数
  8.                                         send_addrflag = 1;         //开启发送完成标志位后定时器开始计时
  9.                                       if(ack_flag)      //等待接收应答信号,如果没有应答信号表示设备不在线就马上再次发送下一个地址
  10.                                         {  
  11.                                                  ack_flag = 0;    //
  12.                                                 step = 1;       
  13.                                                                                
  14.                                                clr_recvbuffer(recv_buf); //        清除这一帧应答数据,等待下一帧数据过来                                                                       
  15.                                                 }
  16.                                             else
  17.                                                 {         
  18.                                                  
  19.                                                         step = 0;                                                                       
  20.                                                 }                               
  21.                                    break;
  22.                                                                        
  23.                                  case 1:                               
  24.                                         revc_data();    //接收数据
  25.                                                                 if(noeffec_dataflag)  //如果接收到的是无效数据就再次从发数据
  26.                                                                 {
  27.                                                                          noeffec_dataflag = 0;   //数据状态标志位清零
  28.                                                                          step = 0;     //状态机返回第0步
  29.                                                                        
  30.                                                                 }
  31.                                                   else if(effec_dataflag)     //如果接收到的是有效数据就转入第二步
  32.                                                                 {
  33.                                                                          effec_dataflag = 0;
  34.                                                                          step = 2;
  35.                                                                 }                       
  36.                                     break;
  37.                                                                
  38.                                   case 2:                       
  39.                                                     if(send_datacnt >= 15)   //如果发送的次数大于15 停止
  40.                                                                         {
  41.                                                                                   //跳出发送程序                                                          
  42.                                                                             return;
  43.                                                                         }       
  44.                                                                        else
  45.                                                                                 {
  46.                                                                                   step = 0;     //如果发送的次数小于15  游戏继续
  47.                                                                                 }
  48.                                                          break;
  49.                                                                                
  50.                                           default:         break;       
  51.    
  52.                                                                                
  53.                            }
复制代码


发送后超时检测,发送一帧数据后就开启定时器,因为从机收到数据成功后会立马回发数据,所以
超时检测先定在50ms测试,但是在switch里面无法转入到第二步
  1.                         if(send_addrflag == 1)    //发送一帧数据后开始倒计时,超时重发地址
  2.                                
  3.                         {
  4.                                    send_timecnt ++;                       
  5.                                        
  6.                                         if(send_timecnt<= 50 && recv_flag == 1)  //在50毫秒内接收到应答信号
  7.                                         {

  8.                                                          ack_flag = 1;    //下位机应答成功
  9.                                                          send_timecnt = 0;       //停止计时标志位
  10.                                                          send_addrflag = 0;           //重新将标志位清零
  11.                                                                                          
  12.                                         }
  13.                                         else
  14.                                         {
  15.                                                
  16.                                                 ack_flag = 0;         //下位机超时为回应
  17.                                                 send_timecnt = 0;       //停止计时标志位
  18.                                                 send_addrflag = 0;
  19.                                         }                                 
  20.                                                                                  
  21.                           }
复制代码
回复

使用道具 举报

7#
ID:973561 发表于 2022-6-15 09:18 | 只看该作者
lkc8210 发表于 2022-6-14 10:20
你case 1到case 2 的时间有多长有算过或测过吗?
这时间足以让从机收到信号并返回应答信号吗?

我好像也没找到多机通信超时重发的帖子参考,从机的回应是接收成功后会马上向主机重发 主机发过去的数据表示在线,所以第一步我在发送完成一帧数据后就开启定时50ms后判断串口是否有接收到一帧数据,如果有表示应答成功,然后转到第二步,但是这个第二步由应答信号来跳转好像不行,所以一直卡在这里面


  1.                         if(send_addrflag == 1)    //发送一帧数据后开始倒计时,超时重发地址
  2.                                
  3.                         {
  4.                                    send_timecnt ++;                       
  5.                                        
  6.                                         if(send_timecnt<= 50 && recv_flag == 1)  //在50毫秒内接收到应答信号
  7.                                         {

  8.                                                          ack_flag = 1;    //下位机应答成功
  9.                                                          send_timecnt = 0;       //停止计时标志位
  10.                                                          send_addrflag = 0;           //重新将标志位清零
  11.                                                                                          
  12.                                         }
  13.                                         else
  14.                                         {
  15.                                                
  16.                                                 ack_flag = 0;         //下位机超时为回应
  17.                                                 send_timecnt = 0;       //停止计时标志位
  18.                                                 send_addrflag = 0;
  19.                                         }                                 
  20.                                                                                  
  21.                           }
复制代码
回复

使用道具 举报

8#
ID:161164 发表于 2022-6-15 11:55 | 只看该作者
chenxinxian 发表于 2022-6-15 09:18
我好像也没找到多机通信超时重发的帖子参考,从机的回应是接收成功后会马上向主机重发 主机发过去的数据 ...

没有send_data()的代码,不知道里面有没有延时

还是那个问题
从第5行结束到第8行比较的时间有多长有算过或测过吗?
这时间足以让从机收到信号并返回应答信号吗?



应该加一个case来等待应答和超时
另外,在没有应答的情况下,根本到不了case2,检测不了send_datacnt
于是死循环了

以下是一点代码改法建议









回复

使用道具 举报

9#
ID:973561 发表于 2022-6-15 19:42 | 只看该作者
lkc8210 发表于 2022-6-15 11:55
没有send_data()的代码,不知道里面有没有延时

还是那个问题

您说得对 确实是时间问题,发送出来到接收的时间太久了,基本上切换不到case 2, 按照您建议的增加了一个case 延时还是不行,这种情况不知道如何解决
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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