小R科技-WIFI机器人网·机器人创意工作室

 找回密码
 立即注册
查看: 5277|回复: 4

(求助)请问有谁使用Arduino uno3+L293D扩展板平台,求源码

[复制链接]
发表于 2013-10-5 19:38:06 | 显示全部楼层 |阅读模式
本帖最后由 41257203 于 2013-10-6 12:07 编辑

同标题,上次无意中看到路由器有那么多好玩的功能,就入了一套Arduino uno3+L293D扩展板+BD120来做一个小车,无奈没有相关经验和知识,看不懂电路图,现请教下下前辈们使用该平台的能否分享下下位机的源码!电路图和接口定义如下(没学过看不懂):
这是官网上的测试代码:点击这里官网链接麻烦高手看看能否帮我备注解释下,或直接告诉我下图中的M1/M2/M3/M4对应IO口
,谢谢!
mshieldv12schem.png

回复

使用道具 举报

 楼主| 发表于 2013-10-6 10:29:23 | 显示全部楼层
// Declare classes for Servo connectors of the MotorShield.
Servo servo_1;
Servo servo_2;


void setup()
{
   Serial.begin(9600);
   Serial.println("Simple Adafruit Motor Shield sketch");

   // Use the default "Servo" library of Arduino.
   // Attach the pin number to the servo library.
   // This might also set the servo in the middle position.
   servo_1.attach(SERVO1_PWM);
   servo_2.attach(SERVO2_PWM);
}


void loop()
{
   // Suppose there are two servo motors connected.
   // Let them move 180 degrees.
   servo_1.write(0);  
   delay(1000);
   servo_1.write(180);
   delay(2000);

   servo_2.write(0);
   delay(1000);
   servo_2.write(180);
   delay(2000);


   // Suppose there is a relay, or light or solenoid
   // connected to M3_A and GND.
   // Note that the 'speed' (the PWM, the intensity)
   // is for both M3_A and M3_B.
   // The output is a push-pull output (half bridge),
   // so it can also be used to drive something low.
   // The 'speed' (the PWM, the intensity) can be set
   // to zero, that would make the output disabled
   // and floating.
   motor_output(MOTOR3_A, HIGH, 255);
   delay(2000);
   motor_output(MOTOR3_A, LOW, 255);


   // Suppose a DC motor is connected to M1_A(+) and M1_B(-)
   // Let it run full speed forward and half speed backward.
   // If 'BRAKE' or 'RELEASE' is used, the 'speed' parameter
   // is ignored.
   motor(1, FORWARD, 255);
   delay(2000);
   // Be friendly to the motor: stop it before reverse.
   motor(1, RELEASE, 0);
   delay(500);
   motor(1, BACKWARD, 128);
   delay(2000);
   motor(1, RELEASE, 0);
}


// Initializing
// ------------
// There is no initialization function.
//
// The shiftWrite() has an automatic initializing.
// The PWM outputs are floating during startup,
// that's okay for the Adafruit Motor Shield, it stays off.
// Using analogWrite() without pinMode() is valid.
//


// ---------------------------------
// motor
//
// Select the motor (1-4), the command,
// and the speed (0-255).
// The commands are: FORWARD, BACKWARD, BRAKE, RELEASE.
//
void motor(int nMotor, int command, int speed)
{
   int motorA, motorB;

   if (nMotor >= 1 && nMotor <= 4)
   {  
     switch (nMotor)
     {
     case 1:
       motorA   = MOTOR1_A;
       motorB   = MOTOR1_B;
       break;
     case 2:
       motorA   = MOTOR2_A;
       motorB   = MOTOR2_B;
       break;
     case 3:
       motorA   = MOTOR3_A;
       motorB   = MOTOR3_B;
       break;
     case 4:
       motorA   = MOTOR4_A;
       motorB   = MOTOR4_B;
       break;
     default:
       break;
     }

     switch (command)
     {
     case FORWARD:
       motor_output (motorA, HIGH, speed);
       motor_output (motorB, LOW, -1);     // -1: no PWM set
       break;
     case BACKWARD:
       motor_output (motorA, LOW, speed);
       motor_output (motorB, HIGH, -1);    // -1: no PWM set
       break;
     case BRAKE:
       // The AdaFruit library didn't implement a brake.
       // The L293D motor driver ic doesn't have a good
       // brake anyway.
       // It uses transistors inside, and not mosfets.
       // Some use a software break, by using a short
       // reverse voltage.
       // This brake will try to brake, by enabling
       // the output and by pulling both outputs to ground.
       // But it isn't a good break.
       motor_output (motorA, LOW, 255); // 255: fully on.
       motor_output (motorB, LOW, -1);  // -1: no PWM set
       break;
     case RELEASE:
       motor_output (motorA, LOW, 0);  // 0: output floating.
       motor_output (motorB, LOW, -1); // -1: no PWM set
       break;
     default:
       break;
     }
   }
}


// ---------------------------------
// motor_output
//
// The function motor_ouput uses the motor driver to
// drive normal outputs like lights, relays, solenoids,
// DC motors (but not in reverse).
//
// It is also used as an internal helper function
// for the motor() function.
//
// The high_low variable should be set 'HIGH'
// to drive lights, etc.
// It can be set 'LOW', to switch it off,
// but also a 'speed' of 0 will switch it off.
//
// The 'speed' sets the PWM for 0...255, and is for
// both pins of the motor output.
//   For example, if motor 3 side 'A' is used to for a
//   dimmed light at 50% (speed is 128), also the
//   motor 3 side 'B' output will be dimmed for 50%.
// Set to 0 for completelty off (high impedance).
// Set to 255 for fully on.
// Special settings for the PWM speed:
//    Set to -1 for not setting the PWM at all.
//
void motor_output (int output, int high_low, int speed)
{
   int motorPWM;

   switch (output)
   {
   case MOTOR1_A:
   case MOTOR1_B:
     motorPWM = MOTOR1_PWM;
     break;
   case MOTOR2_A:
   case MOTOR2_B:
     motorPWM = MOTOR2_PWM;
     break;
   case MOTOR3_A:
   case MOTOR3_B:
     motorPWM = MOTOR3_PWM;
     break;
   case MOTOR4_A:
   case MOTOR4_B:
     motorPWM = MOTOR4_PWM;
     break;
   default:
     // Use speed as error flag, -3333 = invalid output.
     speed = -3333;
     break;
   }

   if (speed != -3333)
   {
     // Set the direction with the shift register
     // on the MotorShield, even if the speed = -1.
     // In that case the direction will be set, but
     // not the PWM.
     shiftWrite(output, high_low);

     // set PWM only if it is valid
     if (speed >= 0 && speed <= 255)   
     {
       analogWrite(motorPWM, speed);
     }
   }
}


// ---------------------------------
// shiftWrite
//
// The parameters are just like digitalWrite().
//
// The output is the pin 0...7 (the pin behind
// the shift register).
// The second parameter is HIGH or LOW.
//
// There is no initialization function.
// Initialization is automatically done at the first
// time it is used.
//
void shiftWrite(int output, int high_low)
{
   static int latch_copy;
   static int shift_register_initialized = false;

   // Do the initialization on the fly,
   // at the first time it is used.
   if (!shift_register_initialized)
   {
     // Set pins for shift register to output
     pinMode(MOTORLATCH, OUTPUT);
     pinMode(MOTORENABLE, OUTPUT);
     pinMode(MOTORDATA, OUTPUT);
     pinMode(MOTORCLK, OUTPUT);

     // Set pins for shift register to default value (low);
     digitalWrite(MOTORDATA, LOW);
     digitalWrite(MOTORLATCH, LOW);
     digitalWrite(MOTORCLK, LOW);
     // Enable the shift register, set Enable pin Low.
     digitalWrite(MOTORENABLE, LOW);

     // start with all outputs (of the shift register) low
     latch_copy = 0;

     shift_register_initialized = true;
   }

   // The defines HIGH and LOW are 1 and 0.
   // So this is valid.
   bitWrite(latch_copy, output, high_low);

   // Use the default Arduino 'shiftOut()' function to
   // shift the bits with the MOTORCLK as clock pulse.
   // The 74HC595 shiftregister wants the MSB first.
   // After that, generate a latch pulse with MOTORLATCH.
   shiftOut(MOTORDATA, MOTORCLK, MSBFIRST, latch_copy);
   delayMicroseconds(5);    // For safety, not really needed.
   digitalWrite(MOTORLATCH, HIGH);
   delayMicroseconds(5);    // For safety, not really needed.
   digitalWrite(MOTORLATCH, LOW);
}
有谁能告诉我这段代码执行了些什么?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-10-7 01:03:18 | 显示全部楼层
// iRover Drivers
// by Bode
// 2012.9.1

#include <MSMotorShield.h>
#include <Servo.h>

//串口输出一个字符串和一个值,用于调试
void output(const char* str, int x){
  Serial.print(str);
  Serial.println(x);
}

//初始化驱动板上4个直流电机的输出口
MS_DCMotor motor1(1, MOTOR12_1KHZ);
MS_DCMotor motor2(2, MOTOR12_1KHZ);
MS_DCMotor motor3(3, MOTOR12_1KHZ);
MS_DCMotor motor4(4, MOTOR12_1KHZ);

//一个定制的类,专门用来控制直流电机(当然,如果用来控制任何靠电压调节功率的硬件都是可以的,比如iRover就用了这个类来控制灯光系统)
class motorTask{
  public:
    //构造函数,需要传入控制哪个电机
    motorTask(MS_DCMotor* m){
      motor = m;
      isTask = false;
    };
   
    //添加一个动作,该动作会在下一个执行周期内被执行
    void addTask(uint8_t dir, uint8_t speed){
      isTask = true;
      mSpeed = speed;
      mDir = dir;
    };
   
    //执行当前预约的动作,该函数应当在执行周期内被调用
    void doTask(){
      if(isTask){
        motor->setSpeed(mSpeed);
        motor->run(mDir);
        isTask = false;
      }
    };
   
    //清除当前预约的动作
    void clearTask(){
      isTask = false;
    }
  private:
    MS_DCMotor* motor;
    bool isTask;
    uint8_t mDir;
    uint8_t mSpeed;
};

//这里开始实例化电机了,首先实例化左右两个电机
motorTask mTaskR(&motor2);
motorTask mTaskL(&motor1);
//接着把前后大灯也作为电机类给实例了
motorTask mLedFront(&motor3);
motorTask mLedBack(&motor4);

//舵机的控制类,专门用来控制舵机
class servoTask{
  public:
  //构造函数,需要传入控制哪个舵机,舵机使用
    servoTask(Servo* s, int pin, int degree){
      servo = s;
      servo->write(degree);
      updateTime = millis();
      currentDegree = degree;
      targetDegree = degree;
    };
   
    //添加动作,即需要旋转的目标角度
    void addTask(int degree){
      targetDegree = degree;
    };
   
    //执行动作,向着目标角度转去.因为舵机不是一个及时响应的设备,所以每转动一定角度后都需要延时,为了不阻塞主循环,所以加上了时间判定
    void doTask(){
      if(currentDegree != targetDegree){
        unsigned long now = millis();
        if(now - updateTime >= 10){
          targetDegree>currentDegree?currentDegree++:currentDegree--;
          servo->write(currentDegree);
          updateTime = now;
          //output("currentDegree",currentDegree);
        }
      }
    };
   
    //清除当前预约的动作
    void clearTask(){
      targetDegree = currentDegree;
    }
  private:
    Servo* servo;
    int currentDegree;
    int targetDegree;
    unsigned long updateTime;
};

//定义两个舵机,一个控制左右转动,一个控制上下转动
Servo servoLR;  //  servo LR/L
Servo servoUD;
//将舵机绑定到自己的舵机控制类上,需要设定座机的初始位置.
servoTask sTaskLR(&servoLR, 9, 90);
servoTask sTaskUD(&servoUD, 10, 135);


//这是进行将串口读来的数据进行解析的环节
//iPhone发给小车的指令都是类似这样的字符串:"GL 100$ CH90$"
//这个函数会将读到的指令分解后放入para和paraInt中,并调用doPara()将指令下达给指定的设备.
#define max_para_cnt 5
#define max_para_len 16
char para[max_para_cnt][max_para_len];
int paraInt[max_para_cnt];
int pc=0;
int pl=0;
char cmd;
void resolveSerial() {
  while(Serial.available()){
    cmd = Serial.read();
    if( (cmd>='A' && cmd<='Z') || (cmd>='a' && cmd<='z') || (cmd>='0' && cmd<='9') || cmd=='-' || cmd=='.'){
      para[pc][pl] = cmd;
      if(cmd>='0' && cmd<='9'){
        if(paraInt[pc]==9999){
          if(cmd!='0'){
            paraInt[pc]=0-(cmd-'0');
          }
        }
        else {
          paraInt[pc]*=10;
          if(paraInt[pc]>=0)
            paraInt[pc]+=cmd-'0';
          else
            paraInt[pc]-=cmd-'0';
        }
      } else if(cmd == '-'){
        if(paraInt[pc]==0)
          paraInt[pc] = 9999;
        else
          paraInt[pc]*=-1;
      }
      pl++;
    }
    else if(cmd == '$'){
      doPara();
      memset(para,0,sizeof(char)*max_para_cnt*max_para_len);
      memset(paraInt,0,sizeof(paraInt));
      pc = 0;
      pl = 0;
    }
    else {
      if(pl>0){
        pc++;
        if(pc>=max_para_cnt){
          Serial.println("Error : pc too long");
        }
        pl = 0;
      }
    }
  };
}

//将解析好的指令下达给指定的设备.
//GL/GR 就是控制左右轮子电机的电压,电压的取值范围是-255到255(注意传入的数字并不是直接的电压值,而是一个间接值,输入200会比输入100,使得轮子获得更大的动力,但并不能保证获得2倍的速度),
//这里默认正为前进,负为后退. 比如GL 100$ 就是给左侧电机一个值为100的前进电压
//LF/LB 是控制灯光亮度的两个通路,也是改变电压的方法,但是为了防止把LED烧坏,会限制传入的数字不能大于35
//CV/CH 是控制云台上下\左右移动的,传入的数字是需要转动到的目标角度,如果没有限制,应该在0-180之间
void doPara(){
  for(int i=0; i<max_para_cnt; i++)
  {
    if(paraInt[i]==9999)
      paraInt[i] = 0;
  }
  Serial.print("Do para : ");
  output(para[0],paraInt[1]);
  if(para[0][0]=='G'){  //Go
    uint8_t dir = paraInt[1]>=10?BACKWARD:(paraInt[1]<=10?FORWARD:RELEASE);
    uint8_t speed = abs(paraInt[1]);
    if(para[0][1]=='L'){
      mTaskL.addTask(dir,speed);
    }
    else if(para[0][1]=='R'){
      mTaskR.addTask(dir,speed);
    }
  }
  else if(para[0][0]=='C'){  //See
    uint8_t degree = abs(paraInt[1]);
    if(para[0][1]=='V'){//UD
      sTaskUD.addTask(degree);
    }
    else if(para[0][1]=='H'){//LR
      sTaskLR.addTask(degree);
    }
  }
  else if(para[0][0]=='L'){  //LED
    uint8_t dir = abs(paraInt[1])==0?RELEASE:FORWARD;
    uint8_t brightness = abs(paraInt[1]);
    brightness = brightness>35?35:brightness; //控制电压,防止把led烧了
    if(para[0][1]=='F'){
      mLedFront.addTask(dir,brightness);
    }
    else if(para[0][1]=='B'){
      mLedBack.addTask(dir,brightness);
    }
  }
}

//Arduino的初始化函数,在这里进行一些值的初始话
void setup() {               
  memset(para,0,sizeof(char)*max_para_cnt*max_para_len);
  memset(paraInt,0,sizeof(paraInt));
  
  Serial.begin(9600);  // 启动串口
  pinMode(13, OUTPUT);
  motor1.setSpeed(0);
  motor2.setSpeed(0);
  motor3.setSpeed(0);
  motor4.setSpeed(0);
  
  servoLR.attach(9,0,180);  // 绑定舵机到针脚,并且设定舵机的旋转范围.
  servoUD.attach(10);
  
}

//Arduino的主循环,不停的读取动作,执行动作就可以了.
void loop() {
  //读取串口输入(将所有的输入转换成预约的动作)
  resolveSerial();
  //执行动作,每个设备依次执行
  mTaskL.doTask();
  mTaskR.doTask();  
  sTaskLR.doTask();
  sTaskUD.doTask();
  mLedFront.doTask();
  mLedBack.doTask();
}
回复 支持 反对

使用道具 举报

发表于 2013-10-9 01:26:54 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-10-11 01:08:09 | 显示全部楼层
swatkxs 发表于 2013-10-9 01:26
你不需要知道那些接口,这个是库调用,我用了L298和L293D,效果都不行,没2分钟就发烫锁死了,强制执行会烧 ...

谢了,现在已经改用L298N平台了
回复 支持 反对

使用道具 举报

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

本版积分规则

关闭

新品特惠推荐上一条 /2 下一条

QQ|QQ技术咨询1|QQ技术咨询2|商务合作微信1:xiaorgeek001|商务合作微信2:XiaoRGEEK|诚聘英才|Archiver|手机版|小R科技-WIFI机器人网·机器人创意工作室 ( 粤ICP备15000788号-6 )

GMT+8, 2024-4-18 20:21 , Processed in 1.105448 second(s), 22 queries .

Powered by XiaoR GEEK X3.4

© 2014-2021 XiaoR GEEK

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