打印
[AVR单片机]

关于电机行程计数失步的问题

[复制链接]
947|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
用 Arduino Nano作为控制板(16MHZ),红外U型传感器,20线编码盘,利用中断触发计数,原理图如下,遇到的问题是,电机正转的时候,每隔200ms,采样计数差为16或17个(正常),反转的时候,每隔200ms/,采样计数为12,13,14,15,16,17(不正常,波动比较大),想实现的目标是行程控制,比方说,电机第一次正转走A个计数,存入EEPROM,反转的时候,从EEPROM中读出A,当中断计数触发达到A的时候,电机停止,由于是利用继电器控制,停止的时候,有惯性误差(暂且忽略不计),但是,利用这种U型传感器来说,会有失步的现象,不知是程序还未完善?还是硬件电路受到干扰?请大神们支招!#include <IRremote.h>
#include <EEPROM.h>

union data                                      //EEPROM 数据类型 字节拆分 转换
{
  long a;
  byte b[4];
};
data col;
int addr = 0;
int addr1 = 9;                                

int RECV_PIN = 12;                               //红外脚
int Frelay=11;                                   // 继电器控制电机 启/停
int Drelay=10;                                   // 继电器控制电机 正/反转 通过H桥改变电源正/反
unsigned long time1 = 0, time2 = 0 ,time3 = 0 ,time4 = 0 ,old_time4 = 0;   // 时间标记
unsigned long  S=2;                              //空隙距离
long F1;                                         //行程计数
long F3;                                         //行程计数
long num;                                       
long num1;                                       //每100ms 计数
long num2;                                       //每200ms 计数
int count=0;                                     //计数
int Start=0;                                     //开启计数变量
int Pause=0;                                     //暂停按键变量
int Change=0;                                    //100ms 200ms交换变量

int d=0;                                         //F1存入EEPROM变量
int e=0;                                         //开启行程比较变量
int f=0;                                         //行程设置自动返回变量
int g=0;                                         //行程比较变量
int Direction=0;                                 //方向变量
int Function=0;

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
     Serial.begin(9600);
     pinMode(Frelay,OUTPUT);
     pinMode(Drelay,OUTPUT);
     pinMode(2,INPUT_PULLUP);
     attachInterrupt(0,Count,CHANGE);

     irrecv.enableIRIn();
}

void loop()
{
     Infrared();                                  //红外遥控  
     SpeedCompare();                              //速度比较
}

void Infrared()
{   
       if (irrecv.decode(&results))
       {
           Serial.println(results.value, HEX);
           if(Direction==0)
           {
                if(results.value==0xFFA25D)            //正转按钮  
                {
                    for(addr ; addr < 4 ; addr++)      //从EEPROM中读出数值 并赋值与F3
                    {
                        col.b[addr]=EEPROM.read(addr);
                        delay(3);
                    }
                    F3=col.a;
                    digitalWrite(Frelay,1);
                    Start=1;
                    e=1;
                    Serial.print("F3=");
                    Serial.println(F3);
                }
                if(g==1)                               //中途返回按键
                {
                   if(results.value==0xFF629D)
                   {
                       count=0;
                       num=0;
                       num1=0;
                       num2=0;
                       digitalWrite(Frelay,1);
                       digitalWrite(Drelay,1);
                       Start=1;
                       e=1;
                   }
                }
           }
           if(Direction==1)
           {
               if(results.value==0xFF629D)            //反转按钮   
               {
                    for(addr ; addr < 4 ; addr++)     //从EEPROM中读出数值 并赋值与F3
                    {
                       col.b[addr]=EEPROM.read(addr);
                       delay(3);
                    }
                    F3=col.a;
                    digitalWrite(Frelay,1);
                    digitalWrite(Drelay,1);
                    Start=1;
                    e=1;
                    Serial.print("F3=");
                    Serial.println(F3);
               }
              if(g==1)                               //中途返回
              {
                   if(results.value==0xFFA25D)
                   {
                       count=0;
                       num=0;
                       num1=0;
                       num2=0;
                       digitalWrite(Frelay,1);
                       Start=1;
                       e=1;
                   }
              }
           }
           if(results.value==0xFFC23D)            //暂停键
           {
              if(Pause==0)
              {
                 g=1;
                 digitalWrite(Frelay,0);
                 Start=0;
                 F1=count;
                 Pause=1;
                 Serial.print("F1=");
                 Serial.println(F1);
              }else{
                 digitalWrite(Frelay,1);
                 Start=1;
                 Pause=0;
                 g=0;
              }
           }
           if(results.value==0xFF906F)             //行程设置键
           {
                Function = EEPROM.read(addr1);
                delay(3);
                if(Function==0)
                {
                   Function=1;
                   EEPROM.write(addr1, Function);
                   delay(3);
                   digitalWrite(Frelay,1);
                   Start=1;
                   f=1;
                   Serial.print("Function=");
                   Serial.println(Function);
                }else{                                   
                   for(int i=0; i<512 ; i++)           //清除EEPROM内容
                   {
                      EEPROM.write(i, 0);
                      delay(3);
                   }
                   for(addr1; addr1<10 ; addr1++)           //清除EEPROM内容
                   {
                      EEPROM.write(addr1, 0);
                      delay(3);
                   }
                   Serial.print("col.a=");
                   Serial.println(col.a);
                   Serial.print("Function=");
                   Serial.println(Function);
                   F3=0;
                }
           }            
          irrecv.resume();
       }
}

void Count()
{  
       if(Start==1)
       {
           if((millis()-time3)>5)                    //为了不计入噪音干扰脉冲,
           {                                         //当2次中断之间的时间大于5ms时,计一次有效计数
               count += 1;                           //当编码器码盘的OUTA脉冲信号下跳沿每中断一次,编码器码盘计数加一  
               Serial.print("count=");
               Serial.println(count);
               DirectionCompare();                   //行程比较控制停止
           }
           time3=millis();
       }
}

void SpeedCompare()
{
     if(Start==1)
     {  
         if ((millis()-time1>=100) && Change==0)
         {
             time1=millis();
             num1=count;
             Change=1;
         }
         if ((millis()-time2>=200) && Change==1)
         {
             time2=millis();
             num2=count;  
             num=num2-num1;
             Serial.print("num=");
             Serial.println(num);
             Change=0;
         }
         if(num==0 && count>10)
         {
             digitalWrite(Frelay,0);
             Start=0;
             if(d==1)
             {
                 col.a=count;
                 for(addr ; addr < 4 ; addr++)      //将count写入EEPROM
                 {
                     EEPROM.write(addr, col.b[addr]);
                     delay(3);
                 }
                 Serial.println("1111111111");
             }
             d=0;  
             count=0;
             if(f==1)                           
             {                                    //行程设置 闭合后 自动返回   
                 //delay(2000);
                 digitalWrite(Drelay,1);
                 digitalWrite(Frelay,1);
                 Start=1;
                 d=1;
                 f=0;
                 Serial.println("222222222");
             }
         }
     }
}

void DirectionCompare()
{
     if(F3-S<count && e==1 && g==0)                //全程 行程比较
     {
          digitalWrite(Frelay,0);
          digitalWrite(Drelay,0);
          Start=0;
          count=0;
          e=0;
          if(Direction==0)
          {
             Direction=1;
           }else{
             Direction=0;
          }
     }
     if(F1-1<count && e==1 && g==1)                //中途返回 行程比较
     {
           digitalWrite(Frelay,0);
           digitalWrite(Drelay,0);
           Start=0;
           count=0;
           e=0;
           g=0;
     }
}

100806d2cgl26grls3266m.jpg (259.27 KB )

100806d2cgl26grls3266m.jpg

111815punmzdkboq3rb8ur.png (70.55 KB )

111815punmzdkboq3rb8ur.png

相关帖子

沙发
山东电子小菜鸟| | 2017-3-14 13:48 | 只看该作者
同求

使用特权

评论回复
板凳
dirtwillfly| | 2017-3-14 14:29 | 只看该作者

你最近也在搞Arduino?

使用特权

评论回复
地板
ignore09|  楼主 | 2017-3-14 16:46 | 只看该作者

我现在测试的话,添加了程序中的计数的毛刺滤波,效果比较理想,之前两款电机,一款比较稳定,一款比较不稳定,毛刺多,结果在程序的计数上,没有对毛刺进行过滤处理,导致毛刺也被当成正常高低信号处理,程序如下,不知道你是否有用,但是这样还是存在一两个误差,能满足要求,若要做成无误差或者误差自动修正,还需共同研究了
        if((millis()-time3)>5)                        //个人认为这个5ms,1:是需要根据电机转速,码盘线数计算的
                                                           //                             2:是根据电机所产生毛刺的长度来调整
         {                                       
               int L=digitalRead(2);                        
               if(Llast==LOW && L==HIGH)    // 这是根据CHANGE触发方式来编写的,低到高,触发,延时5ms
                                                             // 判断,若改变,计数加1,若不变,计数不增加
               {
                   count +=1;                          
                   time3=millis();
                   Llast=L;
               }else if(Llast==HIGH && L==LOW)
               {
                   count +=1;
                   time3=millis();
                   Llast=L;
               }
           }

使用特权

评论回复
5
山东电子小菜鸟| | 2017-3-17 16:37 | 只看该作者
ignore09 发表于 2017-3-14 16:46
我现在测试的话,添加了程序中的计数的毛刺滤波,效果比较理想,之前两款电机,一款比较稳定,一款比较不 ...

你的 millis()函数在哪里

使用特权

评论回复
6
山东电子小菜鸟| | 2017-3-17 16:38 | 只看该作者
dirtwillfly 发表于 2017-3-14 14:29
你最近也在搞Arduino?

没有学arduino,在研究电机

使用特权

评论回复
7
dirtwillfly| | 2017-3-17 17:04 | 只看该作者

这是arduino开发环境提供的一个库函数,能显示程序运行了了多长时间

使用特权

评论回复
8
ignore09|  楼主 | 2017-3-20 09:48 | 只看该作者
山东电子小菜鸟 发表于 2017-3-17 16:38
没有学arduino,在研究电机

arduino里面可以之间调用millis(),已经封存在里面了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

6

帖子

0

粉丝