找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机串口通信控制步进电机,为什么每次上电只能接收一次数据控制一次?

[复制链接]
跳转到指定楼层
楼主
ID:451441 发表于 2019-9-10 18:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
求助,上面的程序我单片机上电后可以正常串口通信收到数据,也可以按照设定返回给串口助手相应信息,电机也可以转动指定的脉冲数,但接下来接不能正常通信了,再发数据串口助手就没有反映了,电机也不转了,单片机关掉再上电就又可以正确接收一次数据。我想不明白哪里的问题,特来求助,望指导。

单片机源程序如下:
  1. #include<reg52.h>  //共阳极接法
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. #define N 8           //可一次接收数据量 帧头(# ascii码)0x23        帧头(+/-号)+——0x2b  --0x2d     5位数据   帧尾(* ascii码)0x2a

  5. sbit dula=P2^6;
  6. sbit wela=P2^7;
  7. sbit pul=P1^0;        //脉冲端
  8. sbit dir=P1^2;        //方向端
  9. sbit ena=P1^1;        // 电机轴使能端
  10. sbit limita=P1^3; //起始端极限位
  11. sbit limitb=P1^4;//远端极限位
  12. sbit origin=P1^5;//原点位

  13. sbit led=P1^1;
  14. sbit led2=P1^3;

  15. uchar forward=0,backward=0,flag,i,w,j=0,serial_con;
  16. uint n,m,l,k,r,a,b,c,d,e,sum;


  17. uchar code table[]={           //数码管编码组
  18. 0x3f,0x06,0x5b,0x4f,
  19. 0x66,0x6d,0x7d,0x07,
  20. 0x7f,0x6f,0x77,0x7c,
  21. 0x39,0x5e,0x79,0x71};                           
  22. uchar code table1[]="MCU gets ";
  23. uchar code table2[]=" pluses!\r\n";
  24. uchar code table3[]="Error 1!\r\n";        //帧头错误反馈代码
  25. uchar code table4[]="Error 2!\r\n";        //帧尾错误反馈代码
  26. uchar code table5[]="Error 3!\r\n";//脉冲数超过38500

  27. uchar rectable[N];        //用于接收串口通信数据的数组

  28. void delayms(uint xms)                  //延时子程序
  29. {
  30.         uint i,j;
  31.         for(i=xms;i>0;i--)
  32.                 for(j=110;j>0;j--);
  33. }

  34. void display(uchar num)          //显示子函数
  35. {
  36.         P0=table[num];
  37.         dula=1;
  38.         dula=0;
  39. }



  40. void tmod(uint m)                   //设置定时器0中断时间的子函数
  41. {
  42.         TMOD=0x01;//设定定时器0 工作方式1(16位定时/计数器)
  43.         TH0=(65536-m)/256;                //设定中断发生时间
  44.         TL0=(65536-m)%256;
  45.         ET0=1;                 //开定时器0中断
  46.         EA=1;                 //开总中断
  47.         TR0=1;                 //开启定时器0
  48. }

  49. void rs232_init()           //串口通信初始化子程序
  50. {
  51.         TMOD=0x20;
  52.     TH1=0xfd;                   //9600波特率
  53.     TL1=0xfd;
  54.     TR1=1;                                //波特率的发生利用定时器1
  55.     SM0=0;
  56.     SM1=1;
  57.     REN=1;    //先设定好工作方式,再打开允许接收
  58.     EA=1;          //打开总中断
  59.     ES=1;     //打开串口中断  
  60. }

  61. void serial_control()                         //根据串口通信收到脉冲数转动子程序
  62. {
  63.         if(serial_con==1)
  64.         {
  65.                         r=0;                                                                  //进入几次定时器0中断计数用
  66.                         serial_con=0;
  67.                 /*        a=rectable[2]-'0';
  68.                         b=rectable[3]-'0';
  69.                         c=rectable[4]-'0';
  70.                         d=rectable[5]-'0';
  71.                         e=rectable[6]-'0';
  72.                         sum=a*10000+b*1000+c*100+d*10+e;         //把输入的脉冲数的字符型字转变成数字         */
  73.                         if(limita==1&&limitb==1)
  74.                         {
  75.                                 switch(rectable[1])                                 //判断方向 +号ASC码 0x2b
  76.                                 {
  77.                                         case 0x2b:
  78.                                                  dir=0;
  79.                                                  tmod(500);
  80.                                                  n=2;
  81.                                                  forward=1;
  82.                                                  break;
  83.                                         case 0x2d:                                   ////判断方向 -号ASC码 0x2d
  84.                                                  dir=1;
  85.                                                  tmod(500);
  86.                                                  n=2;
  87.                                                  backward=1;
  88.                                                  break;        
  89.                                 }
  90.                         }        
  91.                          serial_con=0;                                
  92.          }         
  93.          
  94.                   
  95. }

  96. void serial_com()                                                  //串口通信子程序
  97. {
  98.              if(flag==1)
  99.         {
  100.                                 a=rectable[2]-'0';
  101.                                 b=rectable[3]-'0';
  102.                                 c=rectable[4]-'0';
  103.                                 d=rectable[5]-'0';
  104.                                 e=rectable[6]-'0';
  105.                                 sum=a*10000+b*1000+c*100+d*10+e;         //把输入的脉冲数的字符型字转变成数字
  106.                                 if(sum<=38500)                                                //判断是否超限,如果没有超限
  107.                                 {                                       
  108.                                 ES=0;                  //关闭串口中断
  109.                             for(i=0;i<9;i++)           //发送既定字符
  110.                             {
  111.                                     SBUF=table1[i];
  112.                                 while(!TI);
  113.                                 TI=0;
  114.                              }
  115.                              for(j=2;j<(N-1);j++) //发送接收数组               
  116.                              {
  117.                                      SBUF=rectable[j];
  118.                                 while(!TI);
  119.                                 TI=0;
  120.                               }        
  121.                                          for(i=0;i<12;i++)           //发送既定字符
  122.                                           {
  123.                                                   SBUF=table2[i];
  124.                                                 while(!TI);
  125.                                                 TI=0;
  126.                                           }        
  127.                                           j=0;
  128.                                           ES=1;
  129.                                           flag=0;
  130.                                           serial_con=1;                //进入根据收到脉冲数运动的子函数的标志位
  131.                                   }
  132.                           if(sum>38500)                                //如果输入脉冲超限
  133.                           {
  134.                                   ES=0;
  135.                                   for(i=0;i<12;i++)
  136.                                 {
  137.                                         SBUF=table5[i];
  138.                                         while(!TI);
  139.                                         TI=0;
  140.                                 }
  141.                           }
  142.                           j=0;
  143.                           ES=1;
  144.                           flag=0;
  145.          }
  146.                  if(flag==2)                  //帧头不正确的报错
  147.                  {
  148.                          ES=0;
  149.                          for(i=0;i<12;i++)
  150.                         {
  151.                                 SBUF=table3[i];
  152.                                 while(!TI);
  153.                                 TI=0;
  154.                         }
  155.                         ES=1;
  156.                         flag=0;
  157.                  }     
  158.                  if(flag==3)                        //帧尾不正确的报错
  159.                  {
  160.                          ES=0;
  161.                         for(i=0;i<12;i++)
  162.                         {
  163.                                 SBUF=table4[i];
  164.                                 while(!TI);
  165.                                 TI=0;
  166.                         }
  167.                         ES=1;
  168.                         flag=0;
  169.                  }                           
  170. }





  171. void time0() interrupt 1                  //定时器0中断子程序 中断频率在此函数内设置不同的频率,即不同的转速
  172. {

  173.         switch(n)
  174.         {        
  175.         //        case 0:
  176.         //                TH0=(65536-12500)/256; //n=12500 频率为40Hz     400脉冲/圈时转速为 6r/m
  177.         //                TL0=(65536-12500)%256;
  178.         //                break;
  179.                 case 0:
  180.                         TH0=(65536-5000)/256; //n=5000 频率为100Hz     400脉冲/圈时转速为 15r/m
  181.                         TL0=(65536-5000)%256;
  182.                         break;
  183.         //        case 0:
  184.         //                TH0=(65536-2500)/256; //n=2500 频率为200Hz     400脉冲/圈时转速为 30r/m
  185.         //                TL0=(65536-2500)%256;
  186.         //                break;
  187.                 case 1:
  188.                         TH0=(65536-1250)/256; //n=1250 频率为400Hz     400脉冲/圈时转速为 60r/m
  189.                         TL0=(65536-1250)%256;
  190.                         break;
  191.         //        case 0:
  192.         //                TH0=(65536-1000)/256; //n=1000 频率为500Hz     400脉冲/圈时转速为 75r/m
  193.         //                TL0=(65536-1000)%256;
  194.         //                break;
  195.         //        case 0:
  196.         //                TH0=(65536-800)/256; //n=800 频率为625Hz     400脉冲/圈时转速为 93.75r/m
  197.         //                TL0=(65536-800)%256;
  198.         //                break;
  199.                 case 2:
  200.                         TH0=(65536-500)/256; //n=500 频率为1KHz     400脉冲/圈时转速为 150r/m
  201.                         TL0=(65536-500)%256;
  202.                         break;
  203.         //        case 2:
  204.         //                TH0=(65536-312)/256; //n=312 频率为1.6KHz     400脉冲/圈时转速为 240r/m
  205.         //                TL0=(65536-312)%256;
  206.         //                break;
  207.                 case 3:
  208.                         TH0=(65536-200)/256;//根据调整n的数值,n为200时,速度较快且可正常运行,n为150时启动不正常(n=150时,频率为3.33KHz,可能这个频率对于起步太快了)
  209.                         TL0=(65536-200)%256; //n为200 频率为2.5KHz     400脉冲/圈时转速为 375r/m
  210.                         break;
  211.           //case 1:
  212.                 //        TH0=(65536-175)/256; //n=175 频率为2.86KHz           400脉冲/圈时转速为 430r/m
  213.                 //        TL0=(65536-175)%256;
  214.                 //        break;
  215.         //        case 4:
  216.         //                TH0=(65536-150)/256;  //n=150 频率为3.33KHz           400脉冲/圈时转速为 500r/m
  217.         //                TL0=(65536-150)%256;
  218.         //                break;
  219.                 case 4:                                                                                          
  220.                         TH0=(65536-125)/256; //n=125 频率为4KHz                   400脉冲/圈时转速为 600r/m
  221.                         TL0=(65536-125)%256;
  222.                         break;
  223.                 case 5:
  224.                         TH0=(65536-100)/256; //n=100 频率为5KHz                  400脉冲/圈时转速为 750r/m
  225.                         TL0=(65536-100)%256;
  226.                         break;
  227.                 case 6:
  228.                         TH0=(65536-75)/256;         //n=75 频率为6.67KHz         400脉冲/圈时转速为 1000r/m
  229.                         TL0=(65536-75)%256;
  230.                         break;
  231.                 case 7:
  232.                         TH0=(65536-50)/256;         //n=50 频率为10KHz                 400脉冲/圈时转速为 1500r/m
  233.                         TL0=(65536-50)%256;
  234.                         break;
  235.         }
  236. //        REN=0;//禁止串口接收数据
  237.         ES=0;
  238.         pul=~pul;   //进入中断后,开始高低电平变换以产生脉冲
  239.         r++;
  240.         if(r==(sum*2))
  241.         {
  242.                 pul=1;
  243.                 TR0=0;
  244.                 r=0;
  245.                 n=0;   //0档最慢速度
  246.                 forward=0;
  247.                 backward=0;
  248.         //        REN=1;
  249.                 ES=1;
  250.         }
  251.         if(limita==0||limitb==0)  //如果起始方向极限或远端极限被触发,pul输出高电平,停止转动并关闭定时器0
  252.         {        
  253.                 pul=1;
  254.                 TR0=0;
  255.                 n=0;   //0档最慢速度
  256.                 forward=0;
  257.                 backward=0;
  258.         //        REN=1;
  259.                 ES=1;        
  260.         }
  261. }


  262. void ser()interrupt 4                   //串口中断子程序
  263. {                 
  264.         RI=0;
  265.     rectable[j++]=SBUF;     //存数据到接收缓存
  266.         if(rectable[0]!=0x23)         //帧头验证
  267.         {
  268.                 flag=2;
  269.         }
  270.     if(j==N)              //数组满时,验证帧尾再把flag置相应数值
  271.         {         
  272.                 if(rectable[7]!=0x2a)        //帧尾验证
  273.                 {
  274.                         flag=3;
  275.                 }
  276.                 else
  277.                 {
  278.                     flag=1;
  279.             }
  280.         }
  281. }


  282. void main()
  283. {
  284.         P0=0;                                                                        
  285.         dula=1;
  286.         dula=0;
  287.         P0=0xc0;
  288.         wela=1;
  289.         wela=0;
  290.         rs232_init();     //串口通信初始化设置
  291.         while(1)
  292.         {        
  293.                 serial_com();
  294.                 serial_control();

  295.          }               
  296. }
复制代码

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

使用道具 举报

沙发
ID:451441 发表于 2019-9-11 11:55 | 只看该作者
根据我的试验,问题是在void serial_control()这个函数相关的地方,因为在主程序中如果屏蔽掉这个子程序,就可以实现连续正确接收。但我分析不出来这个子程序的问题在哪了,特在此求助。
回复

使用道具 举报

板凳
ID:123289 发表于 2019-9-11 22:17 | 只看该作者
经验不足,
1、排除电机的电磁干扰。
2、排除程序的错误。
慢慢找吧。
回复

使用道具 举报

地板
ID:451441 发表于 2019-9-12 08:25 | 只看该作者
我找到原因了,因为在主函数中我先进行串口通信接收串口助手的脉冲数信息时,TMOD设定的时定时器1的工作方式,然后在驱动步进电机是TMOD是设定定时器0的工作方式,所以在后续接收串口通信时就无法正常接受了。而修改也很简单,在269行下面加一行代码   rs232_init();    就可以实现后续的正常接收了。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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