极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 76353|回复: 73

关于电机中断计数问题

[复制链接]
发表于 2017-2-4 10:08:10 | 显示全部楼层 |阅读模式
用Nano作为控制板(16MHZ),红外U型传感器,20线编码盘,利用中断触发计数,电机跑动时,利用CHANGE 和 FALLING 触发方式,结果,比如跑50圈,计数竟然差不多,理论上CHANGE 方式应该比FALLING 方式 多出一倍,会不会是晶振不够?这个得怎么计算?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2017-2-5 13:30:32 | 显示全部楼层
这个问题值得研究研究
回复 支持 反对

使用道具 举报

发表于 2017-2-6 08:19:53 | 显示全部楼层
排除法吧,1、先用示波器打一下这个简易光电编码器的波形,看周期或者频率是不是与20线编码器的参数接近。2、找一个专业点的编码器来测试自己写的程序,专业编码器某宝一大堆,便宜贵的都有,建议线数不要太高,如果编码器的线数高电机带动其转速又快的话,单片机的计数器就有爆满到65536就没意义啦,建议用100线的,电机转速控制在5000转一下,一般木有问题。试试吧。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-6 10:25:02 | 显示全部楼层
wing 发表于 2017-2-5 13:30
这个问题值得研究研究

同一道程序,编码盘(图片上传不了:几个小磁铁排一圈,霍尔传感器在上方),传感器采用不一样的形式,霍尔传感器,红外U型传感器,使用霍尔这样采集的数据利用CHANGE 和 FALLING 都有很明显的差别,这样看来,是不是晶振频率不够?
回复 支持 反对

使用道具 举报

发表于 2017-2-6 10:30:23 | 显示全部楼层
本帖最后由 wing 于 2017-2-6 10:41 编辑

20线的码盘很有可能是配7K转的电机,即使这样16M的频率还是可以准确获取编码器计数的,主要是看程序怎么写了,如果乱加delay就难保证了
另外就是霍尔一般情况都比光电的分辨率要低
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-6 10:52:30 | 显示全部楼层
wing 发表于 2017-2-6 10:30
20线的码盘很有可能是配7K转的电机,即使这样16M的频率还是可以准确获取编码器计数的,主要是看程序怎么写 ...

如果您不介意的话,可以看下我个程序,delay只用在EEPROM读写这里




#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;
     }
}































回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-6 11:06:48 | 显示全部楼层
PINKWALKMAN 发表于 2017-2-6 08:19
排除法吧,1、先用示波器打一下这个简易光电编码器的波形,看周期或者频率是不是与20线编码器的参数接近。2 ...

同一道程序,编码盘(图片上传不了:几个小磁铁排一圈,霍尔传感器在上方),传感器采用不一样的形式,霍尔传感器,红外U型传感器,使用霍尔这样采集的数据利用CHANGE 和 FALLING 都有很明显的差别,这样看来,是不是晶振频率不够?
回复 支持 反对

使用道具 举报

发表于 2017-2-6 16:16:10 | 显示全部楼层
ignore 发表于 2017-2-6 11:06
同一道程序,编码盘(图片上传不了:几个小磁铁排一圈,霍尔传感器在上方),传感器采用不一样的形式,霍尔 ...

我觉得不是晶振的问题,晶振不要随便换,这个换了整个单片机的系统时钟都变了,串口通讯也会受到影响。所以不要轻易动它。
就几线的编码器不会把计数器弄爆。
还有如果晶振有问题,串口是接收不到数据的或者接收到的也是一堆乱码,如果现在板子的串口读数显示正常晶振绝对没问题。
还是那句话,换个正经的编码器试试。我之前用过非自制的编码器,没问题。
回复 支持 反对

使用道具 举报

发表于 2017-2-6 16:31:14 | 显示全部楼层
看你这个程序是做电机的位置环控制,不知精度要求高不高。
说实话之前做过电机位置环控制,用的私服电机加私服驱动器,有PID算法在其中。

建议你改传感器,用线性滑动变阻器做位置反馈,用Arduino的10位AD采样精度和响应速度比编码器来的好得多,如果加上PID算法会更牛逼。你的方法读取编码器的累积误差太大,实验都通过不了更不用说实际工程使用啦。(我说话比较直接,理解万岁哈。)

这是我前几年做的简易步进电机PID直线私服,带位置反馈。http://v.youku.com/v_show/id_XNj ... 0.0&from=y1.7-2
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-6 16:57:39 | 显示全部楼层
PINKWALKMAN 发表于 2017-2-6 16:31
看你这个程序是做电机的位置环控制,不知精度要求高不高。
说实话之前做过电机位置环控制,用的私服电机加 ...

您好,正如你所说的,同一段距离,采样的误差的确存在,目标是行程记忆,对电机第一次读取行程,第二次比较行程停止,由于我也是刚接触,所以,并不是很懂,你说的改传感器,是什么传感器?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-6 16:57:53 | 显示全部楼层
PINKWALKMAN 发表于 2017-2-6 16:31
看你这个程序是做电机的位置环控制,不知精度要求高不高。
说实话之前做过电机位置环控制,用的私服电机加 ...

您好,正如你所说的,同一段距离,采样的误差的确存在,目标是行程记忆,对电机第一次读取行程,第二次比较行程停止,由于我也是刚接触,所以,并不是很懂,你说的改传感器,是什么传感器?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-6 16:58:07 | 显示全部楼层
PINKWALKMAN 发表于 2017-2-6 16:31
看你这个程序是做电机的位置环控制,不知精度要求高不高。
说实话之前做过电机位置环控制,用的私服电机加 ...

您好,正如你所说的,同一段距离,采样的误差的确存在,目标是行程记忆,对电机第一次读取行程,第二次比较行程停止,由于我也是刚接触,所以,并不是很懂,你说的改传感器,是什么传感器?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-6 16:59:39 | 显示全部楼层
PINKWALKMAN 发表于 2017-2-6 16:31
看你这个程序是做电机的位置环控制,不知精度要求高不高。
说实话之前做过电机位置环控制,用的私服电机加 ...

尴尬了,按多了,方便的话,能留个请教方式?
回复 支持 反对

使用道具 举报

发表于 2017-2-6 17:31:39 | 显示全部楼层
ignore 发表于 2017-2-6 16:59
尴尬了,按多了,方便的话,能留个请教方式?

不着急哈。
多聊聊把这个帖子捧起来,让更多人来学习。
我说的传感器器是线性位移传感器,说白了就是线性滑动变阻器,网址:https://item.taobao.com/item.htm ... p;abbucket=9#detail
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-2-7 08:47:32 | 显示全部楼层
PINKWALKMAN 发表于 2017-2-6 17:31
不着急哈。
多聊聊把这个帖子捧起来,让更多人来学习。
我说的传感器器是线性位移传感器,说白了就是线 ...

点开发现。这传感器好大哈,你讲的这种适用于工业自动化上的标准,我目前就是用于玩具小车上面,所以说,条件有点死,不太清楚如何调整这些误差?
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-27 17:05 , Processed in 0.041534 second(s), 20 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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