极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 13774|回复: 3

[新手求助]“arduino Uno R3+L298N驱动器+rotary 增量型编码器+OLED

[复制链接]
发表于 2015-2-2 16:09:55 | 显示全部楼层 |阅读模式
各位大神,小弟想做一个小滚轮系统,用于做生物学实验,不过由于小弟初学嵌入式开发,不懂编程,向各位大神求助,先行谢过啦!
         我想做的整个装置有点像跑步机,我想为小白鼠做个跑步机,来检测小白鼠的神经系统和运动能力。整个的实验过程如下:将5只小白鼠放到以2rpm低速旋转的滚轮上(各老鼠跑道相互隔离,互不干扰),然后缓慢的匀加速或者以6秒为间隔逐步加速,当滚轮达到一定速度时,某一个小白鼠会从滚轮上掉下来,掉下来的小白鼠踩在其所在跑道内的微动开关,这时需要记录以下信息,第几跑道、当前滚轮速度和滚轮加速所用的时间,并将此信息显示到OLED显示屏上。类似的其他几只老鼠会陆续掉下来,同样记录相关信息,并输出到显示屏上。
         我初步想用arduino Uno R3开发板,L298N驱动器,rotary 增量型编码器,OLED显示屏等模块,小型微动开关(类似于鼠标的点按器),直流减速电机等搭建一个小的反馈系统,实现滚轮的速度调节、速度测量以及速度、时间等的显示。各自参数如下:
1.arduino Uno R3
(1).基本配制和参数
处理器 ATmega328
工作电压 5V
输入电压(推荐) 7-12V
输入电压(范围) 6-20V
数字IO脚 14 (其中6路作为PWM输出)
模拟输入脚 6
IO脚直流电流 40 mA
3.3V脚直流电流 50 mA
Flash Memory 32 KB (ATmega328,其中0.5 KB 用于 bootloader)
SRAM 2 KB (ATmega328)
EEPROM 1 KB (ATmega328)
工作时钟 16 MHz
  
(2)输入输出
  
14路数字输入输出口:工作电压为5V,每一路能输出和接入最大电流为40mA。每一路配置了20-50K欧姆内部上拉电阻(默认不连接)。除此之外,有些引脚有特定的功能
串口信号RX(0号)、TX(1号): 与内部 ATmega8U2 USB-to-TTL 芯片相连,提供TTL电压水平的串口接收信号。
外部中断(2号和3号):触发中断引脚,可设成上升沿、下降沿或同时触发。
脉冲宽度调制PWM(3、5、6、9、10 、11):提供6路8位PWM输出。
SPI(10(SS),11(MOSI),12(MISO),13(SCK)):SPI通信接口。
LED(13号):Arduino专门用于测试LED的保留接口,输出为高时点亮LED,反之输出为低时LED熄灭。
6路模拟输入A0到A5:每一路具有10位的分辨率(即输入有1024个不同值),默认输入信号范围为0到5V,可以通过AREF调整输入上限。除此之外,有些引脚有特定功能
TWI接口(SDA A4和SCL A5):支持通信接口(兼容I2C总线)。
AREF:模拟输入信号的参考电压。
Reset:信号为低时复位单片机芯片。
  
(3)通信接口
  
串口:ATmega328内置的UART可以通过数字口0(RX)和1(TX)与外部实现串口通信;ATmega16U2可以访问数字口实现USB上的虚拟串口。
TWI(兼容I2C)接口:
SPI 接口:
  
  
2.L298N驱动器
产品参数:
(1).驱动芯片:全新原装L298N双H桥直流电机驱动芯片
(2).驱动部分端子供电范围Vs:+5V~+35V ;如需要板内取电,则供电范围Vs:+7V~+35V
(3).驱动部分峰值电流Io:2A
(4).逻辑部分端子供电范围Vss:+5V~+7V(可板内取电+5V)
(5).逻辑部分工作电流范围:0~36mA
(6).控制信号输入电压范围:
    低电平:-0.3V≤Vin≤1.5V  
    高电平:2.3V≤Vin≤Vss
(7).使能信号输入电压范围:
    低电平:-0.3≤Vin≤1.5V(控制信号无效)
    高电平:2.3V≤Vin≤Vss(控制信号有效)
(8).最大功耗:20W(温度T=75℃时)
(9).存储温度:-25℃~+130℃
(10).驱动板尺寸:53mm*43mm
(11).驱动板重量:35g
(12).其他扩展:控制方向指示灯、逻辑部分板内取电接口。
  
驱动直流电机
由于本模块是2路的H桥驱动,所以可以同时驱动两个电机
使能ENA ENB之后,
可以分别从IN1 IN2输入PWM信号驱动电机1的转速和方向
可以分别从IN3 IN4输入PWM信号驱动电机2的转速和方向
信号如表所示:
直流电机    旋转方式    IN1    IN2    IN3    IN4    调速PWM信号
                                      调速端A 调速端B
M1              正转    高    低    /    /    高        /
               反转    低    高    /    /    高        /
               停止    低    低    /    /    高        /
M2              正转    /    /    高    低    /       高
               反转    /    /    低    高    /       高
               停止    /    /    低    低    /       高
  
  
3.rotary 增量型编码器
型号:增量型旋转编码器,AB两相。通过旋转的光栅盘和光耦产生可识别方向的计数脉冲信号。
性能:600P/R-600脉冲每转。DC5-24V供电。最大机械转速6000转/分,响应频率:0-20KHz;
输出:AB两相输出矩形正交脉冲,电路输出为NPN集电极开路输出型。
接线输出:A相,B相,Vcc正电源,V0地。
  
4.OLED显示屏等模块
各引脚:VCC:3.3-5V,GND,SCL:串行时钟,SDA:串行数据
  
5.直流减速电机
DC: 12V  160rpm       扭矩:  0.5kg.cm     电流:0.3A
  
万分感谢!
--
回复

使用道具 举报

发表于 2015-2-2 16:47:28 | 显示全部楼层
总体架构有了,总体资料也有了,是否将你的项目从一个着手点一点点扩大,这样就可以由浅入深了,否则你会无从入手的.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-2-3 10:47:31 | 显示全部楼层
林定祥 发表于 2015-2-2 16:47
总体架构有了,总体资料也有了,是否将你的项目从一个着手点一点点扩大,这样就可以由浅入深了,否则你会无从入 ...

我也想慢慢学啊,不过这个东东是我实验室做实验想要用,比较着急求大神能给提供个程序模板,万分感谢!导师猛于虎啊,你懂得我后期还想自己做个智能小车慢慢学习。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-2-3 11:24:13 | 显示全部楼层
ptnqyi 发表于 2015-2-3 10:47
我也想慢慢学啊,不过这个东东是我实验室做实验想要用,比较着急求大神能给提供个程序模板,万分感谢 ...

我在网上找了一个智能小车的程序,我觉得原理类似,不过不知道怎么用于我的装置,能帮我看下不

//定义变量程序段
//把小车左轮电机编码器码盘的OUTA信号连接到Arduino控制器的数字端口2,
//数字端口2是Arduino的外部中断0的端口。
#define PinA_left 2 //外部中断0
#define PinB_left 8 //小车左车轮电机编码器码盘的OUTB信号连接到数字端口8
//把小车右车轮电机编码器码盘的OUTA信号连接到Arduino控制器的数字端口3,
//数字端口3是Arduino的外部中断1的端口。
#define PinA_right 3 //外部中断1
#define PinB_right 9 //小车右车轮电机编码器码盘的OUTB信号连接到数字端口9
int E_left =5; //L298P直流电机驱动板的左轮电机使能端口连接到数字接口5
int M_left =4; //L298P直流电机驱动板的左轮电机转向端口连接到数字接口4
int E_right =6; //连接小车右轮电机的使能端口到数字接口6
int M_right =7; //连接小车右轮电机的转向端口到数字接口7
int val_right; //小车右轮电机的PWM功率值
int val_start;//上位机控制字节,用于控制电机是否启动;
int val_FB;   //上位机控制字节,用于控制电机是正转还是反转;
int val_left;//上位机控制字节,用于提供给左轮电机PWM功率值。
int count1 = 0;  //左轮编码器码盘脉冲计数值
int count2= 0; //右轮编码器码盘脉冲计数值
int rpm1 = 0;  //左轮电机每分钟(min)转速(r/min)
int rpm2 = 0;  //右轮电机每分钟(min)转速(r/min)
int rpm1_HIGH = 0;//左轮电机转速分解成高、低两个字节数据,以方便上传给PC机
int rpm1_LOW = 0;
int rpm2_HIGH = 0;//右轮电机转速分解成高、低两个字节数据
int rpm2_LOW = 0;
int flag;//设置小车行车状态,是前进、后退还是停止
unsigned long time = 0, old_time = 0; // 时间标记
unsigned long time1 = 0, time2 = 0; // 时间标记

//初始化程序段
void setup()
{
  Serial.begin(9600);    // 启动串口通信,波特率为9600b/s
  pinMode(M_left, OUTPUT);   //L298P直流电机驱动板的控制端口设置为输出模式
  pinMode(E_left, OUTPUT);
  pinMode(M_right, OUTPUT);
  pinMode(E_right, OUTPUT);
  pinMode(PinA_left,INPUT); //伺服电机编码器的OUTA和OUTB信号端设置为输入模式
  pinMode(PinB_left,INPUT);
  pinMode(PinA_right,INPUT);
  pinMode(PinB_right,INPUT);
  //定义外部中断0和1的中断子程序Code(),中断触发为下跳沿触发
  //当编码器码盘的OUTA脉冲信号发生下跳沿中断时,
  //将自动调用执行中断子程序Code()。
  attachInterrupt(0, Code1, FALLING);//小车左车轮电机的编码器脉冲中断函数
  attachInterrupt(1, Code2, FALLING);//小车右车轮电机的编码器脉冲中断函数
}

//子程序程序段
void advance()//小车前进
{
     digitalWrite(M_left,HIGH);
     analogWrite(E_left,val_left);
     digitalWrite(M_right,LOW);
     analogWrite(E_right,val_right);
}
void back()//小车后退
{
     digitalWrite(M_left,LOW);
     analogWrite(E_left,val_left);
     digitalWrite(M_right,HIGH);
     analogWrite(E_right,val_right);
}
void Stop()//小车停止
{
     digitalWrite(E_right, LOW);
     digitalWrite(E_left, LOW);
}
  
//主程序段
void loop()
{
  if (Serial.available()>0) //如果Arduino控制器读缓冲区中存在上位机下达的字节
  {
      val_start= Serial.read(); //从读缓冲区中读取上位机的三个控制字节
      delay(5);
      val_FB = Serial.read();
      delay(5);  
      val_left= Serial.read();
      delay(5);      
     if(val_start==0x11)     //如果读出的第一个字节为小车启动标志字节0x11
     {
       if(val_FB ==0xAA)   //如果读出的第二个字节为小车前进标志字节0xAA
       {
         //读出的第三个字节为小车左车轮电机的PWM功率值,把它赋值给右车轮电机功率变量
         val_right=val_left;
         advance(); //小车前进
         flag='a';   //设置小车前进标志字符     
         count1 = 0; //恢复到编码器测速的初始状态
         count2 = 0;
         old_time=  millis();   
       }
       else if(val_FB ==0xBB) //如果读出的第二个字节为小车后退标志字节0xBB   
       {
         val_right=val_left;
         back();  //小车后退
         flag='b'; //设置小车后退标志字符      
         count1 = 0; //恢复到编码器测速的初始状态
         count2 = 0;
         old_time=  millis();        
       }
     }
      else if(val_start==0x22) //如果读出的第一个字节为小车停止标志字节0x22
      {
         Stop(); //小车停止
         flag='s'; //设置小车停止标志字符         
      }
  }
  time = millis();//以毫秒为单位,计算当前时间
  //计算出每一秒钟编码器码盘计得的脉冲数,
  if(abs(time - old_time) >= 1000) // 如果计时时间已达1秒
  {
    detachInterrupt(0); // 关闭外部中断0
    detachInterrupt(1); // 关闭外部中断1   
     //把每一秒钟编码器码盘计得的脉冲数,换算为当前转速值
     //转速单位是每分钟多少转,即r/min。这个编码器码盘为12个齿。
    rpm1 =(float)count1*60/12;//小车左车轮电机转速
    rpm2 =(float)count2*60/12; //小车右车轮电机转速
    rpm1_HIGH=rpm1/256;//把转速值分解为高字节和低字节
    rpm1_LOW=rpm1%256;
    rpm2_HIGH=rpm2/256;
    rpm2_LOW=rpm2%256;
   //根据左右车轮转速差rpm1-rpm2,乘以比例因子0.4,获得比例调节后的右车轮电机PWM功率值
    val_right=(float)val_right+(rpm1-rpm2)*0.4;
    Serial.print(rpm1_HIGH,BYTE);//向上位计算机上传左车轮电机当前转速的高、低字节
    Serial.print(rpm1_LOW,BYTE);
    Serial.print(rpm2_HIGH,BYTE);//向上位计算机上传右车轮电机当前转速的高、低字节
    Serial.print(rpm2_LOW,BYTE);
    Serial.print(val_right,BYTE);// 向上位计算机上传PID调节后的右轮电机PWM功率值   
    if(flag=='a') //根据刚刚调节后的小车电机PWM功率值,及时修正小车前进或者后退状态
    advance();
    if(flag=='b')
    back();   
   //恢复到编码器测速的初始状态
    count1 = 0;   //把脉冲计数值清零,以便计算下一秒的脉冲计数
    count2 = 0;
    old_time=  millis();     // 记录每秒测速时的时间节点   
    attachInterrupt(0, Code1,FALLING); // 重新开放外部中断0
    attachInterrupt(1, Code2,FALLING); // 重新开放外部中断1
  }
}

// 左侧车轮电机的编码器码盘计数中断子程序
void Code1()
{  
  //为了不计入噪音干扰脉冲,
   //当2次中断之间的时间大于5ms时,计一次有效计数
  if((millis()-time1)>5)
  //当编码器码盘的OUTA脉冲信号下跳沿每中断一次,
  count1 += 1; // 编码器码盘计数加一  
  time1==millis();
}
// 右侧车轮电机的编码器码盘计数中断子程序
void Code2()
{  
  if((millis()-time2)>5)
  //当编码器码盘的OUTA脉冲信号下跳沿每中断一次,
  count2 += 1; // 编码器码盘计数加一
  time2==millis();  
}
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-17 13:20 , Processed in 0.053237 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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