Grove I2C Motor Driver Setup and Example Code

After much deliberation I was finally able to get my Grove I2C motor driver and its example code working. I had originally had problems compiling a set of example code that I found online but now I have fixed the code. Also I have made a drawing showing how to connect the Grove I2C Motor Driver to an Arduino Uno. It seems that very few people have made tutorials on this controller other than the wiki page which has just a lot of technical information which is great but for people who don't want all that extra information I have made this short tutorial. I kept it short sweet and to the point so hopefully if you are trying to use one of these controllers you will be able to use the information on this page.

Setup:
(CLICK TO VIEW IMAGE LARGER)

The example code bellow should simply make the motor spin and then reverse directions repeatedly.
Additional help can be found here:
http://www.seeedstudio.com/wiki/index.php?title=Grove_-_I2C_Motor_Driver
http://www.seeedstudio.com/forum/viewtopic.php?f=17&t=2935
http://www.arduino.cc/en/Reference/Wire

Working Code Example:



#include <Wire.h>

//#define MOTORSHIELDaddr   0x0f
#define SETPWMAB          0x82
#define SETFREQ           0x84
#define CHANGEADDR        0x83
#define CHANNELSET        0xAA
#define MOTOR1            0xA1
#define MOTOR2            0xA5
#define SAVEADDR          'S'
#define NOTSAVEADDR       'N'
byte val = 0; // I put this here to replace the "Wire.write(0);"

static unsigned char MOTORSHIELDaddr = 0x28;

void speedAB(unsigned char spda , unsigned char spdb)
{
  Wire.beginTransmission(MOTORSHIELDaddr); // transmit to device MOTORSHIELDaddr
  Wire.write(SETPWMAB);        //set pwm header
  Wire.write(spda);              // send pwma
  Wire.write(spdb);              // send pwmb  
  Wire.endTransmission();      // stop transmitting
}

void fre_pre(unsigned char pres)
{  
  Wire.beginTransmission(MOTORSHIELDaddr); // transmit to device MOTORSHIELDaddr
  Wire.write(SETFREQ);        // set frequence header
  Wire.write(pres);           //  send prescale
  Wire.write(val);            //  need to send this byte as the third byte(no meaning)
  Wire.endTransmission();
}

void change_adr(unsigned char new_adr, unsigned char save_or_not)
{
  Wire.beginTransmission(MOTORSHIELDaddr); // transmit to device MOTORSHIELDaddr
  Wire.write(CHANGEADDR);        // change address header
  Wire.write(new_adr);              //  send new address
  Wire.write(save_or_not);          //   save the new address or not
  Wire.endTransmission();    //
  delayMicroseconds(100); //this command needs at least 6 us
}

void channel(unsigned char i4) //0b 0000 I4 I3 I2 I1
{
  delayMicroseconds(4);
  Wire.beginTransmission(MOTORSHIELDaddr); // transmit to device MOTORSHIELDaddr
  Wire.write(CHANNELSET);        // channel control header
  Wire.write(i4);                // send channel control information
  Wire.write(val);               // need to send this byte as the third byte(no meaning)
  Wire.endTransmission();
}
void motorAndspd( unsigned char motor_s,unsigned char Mstatus, unsigned char spd)
{
  Wire.beginTransmission(MOTORSHIELDaddr); // transmit to device MOTORSHIELDaddr
  Wire.write(motor_s);        // motor select information
  Wire.write(Mstatus);        // motor satus information
  Wire.write(spd);            //  motor speed information
  Wire.endTransmission();
}

void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
  delayMicroseconds(10); //wait for motor driver to initialization
}

void loop()
{

  motorAndspd(0xA1,0B01,225);
  motorAndspd(0xA5,0B01,30);
  delay(2000);

  motorAndspd(0xA5,0B10,225);
  motorAndspd(0xA1,0B10,30);
  delay(2000);

  change_adr(0x12, NOTSAVEADDR );
  MOTORSHIELDaddr = 0x12;

  for( int i = 0;i< 16;i++)
  {
    fre_pre(i);
    channel(i);
    delay(100);
  }
  speedAB(100 , 100); // was 0 , 0
  change_adr(0x28,NOTSAVEADDR );
  MOTORSHIELDaddr = 0x28;

  while(1)
  {
    channel(0b00001010);
    delay(500);
    channel(0b00000101);
    delay(500);
  }
 }


4 comments:

  1. Anonymous5/22/2012

    Hello,
    I have been studying the code for the Grove I2C because we are building a robot in school and i understand it all except for the fre_pre void, could somebody explain it to me!
    Thank You!
    :D

    ReplyDelete
  2. Hi, It has been a while since I have looked at this code. My goal was to get the motor driver to work with the example code that I found online because Arduino had made a change to their syntax since the program was written. I haven't had a chance to go any further with the code since then. Luckily I know some people who are very good with Arduino and I will confer with them about it and then get back to you. Sorry I'm unable to provide you with an answer right away but I at least wanted to let you know that your comment was not being ignored. I will reply back as soon as I can.

    ReplyDelete
  3. OK, This is what I have come up with. The
    "void fre_pre(unsigned char pres)" seems to be initializing a variable called 'pres'. However, the 'fre_pre' part may specifically serve the purpose of declaring a calibration method for this particular function. I will let you know if I find out anything more in the next few days.

    ReplyDelete
  4. Also, "fre_pre" stands for frequency prescaler. This code sends the frequency prescaler to the motor controller. I was informed of the following: A frequency prescaler is one of two arguments required to set the operating speed of the Atmel chip. The other is the crystal or internal clock. The basic version is prescaler x frequency gives final frequency. I think with the right prescaler one can clock the Atmel right down to 33KHz. This is important for power saving and if specific frequency matching is required.

    I hope this is more help to you.

    ReplyDelete