woensdag 20 januari 2010

Arduino: Controlling a DC motor

It's been a while, but I've been busy with an interesting project. I will blog about it later on. Totally unrelated is today's topic: controlling an DC motor with an Arduino. At first you might say that it is easy to power an DC motor with an Arduino. Put it on a digital pin and enable or disable the motor. But if we want different speeds you will need a different voltage. As a digital pin is only high (5v) or low (0v), the motor can either go very fast or stop. How do we fix this problem?

The short answer is quite simple actually: use pulses. By sending a pulse every x milliseconds the motor will rotate faster or slower depending on the pulse length. The longer answer, however, is a bit harder. We will need something to flat out the pulses a bit. As the pulse top is 5v and the pulse bottom is 0v, the engine will actually be turned off and on very fast. By using an capacitator we can flat out the pulse to, for example, top 3v and bottom 2.5v.

To build the following circuit we will need:
1 x An Arduino board
1 x C547B transistor
2 x 10KOhm resistors
1 x 5v DC Motor
1 x 100 MicroF Elco
2 x push-to-make buttons

This circuit will send a pulse every x milliseconds. You can control the pulse length by pressing the buttons.






Upload the following sketch to the Arduino, you will need the Metro library:


#include

#define PINBUTTON1 2
#define PINBUTTON2 3
#define PINMOTOR 8


signed int pulseTime=50;
unsigned long prevPulse = millis();

boolean inPulse = false;

Metro MotorPulse = Metro(250);


void setup ()
{
  pinMode(PINMOTOR, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  if (millis() %500 ==0)
 {
  int curbut1 = digitalRead(PINBUTTON1);
  if (curbut1==HIGH)
  {
    if (pulseTime + 5 <=100)
   pulseTime +=5;
   else
     pulseTime=100;
 Serial.print(pulseTime);
 Serial.print("\n");


  }
 
  int curbut2 = digitalRead(PINBUTTON2);
  if ( (curbut2==HIGH))
  {
    if (pulseTime - 5 >=0)
      pulseTime -=5;
    else
      pulseTime = 0;
     
 Serial.print(pulseTime);
 Serial.print("\n");


  }
 }

 
  if (!inPulse)
  {
    if (MotorPulse.check() == 1)
    {
      MotorPulse.interval(5);
      inPulse = true;
      digitalWrite(PINMOTOR , HIGH);
    }
  }
  else
  {
    if (MotorPulse.check() == 1)
    {
      MotorPulse.interval(pulseTime);
      inPulse = false;
      digitalWrite(PINMOTOR , LOW);
    }
  }
 
}




zaterdag 28 november 2009

Project: Rolling the dice, putting it together

In the previous posts I have talked about building a die, expanding the I/O pins on the Arduino and reading input from a player. Today we are going to build the complete game.

The following circuit is cut in parts. The first circuit  is the overview, the second is one die. Therefore you will need to build the second circuit twice. I've put in transistors, because the PCF8574P will not deliver much current.  The following components are required to build the game:

1 x Arduino Duemilanove
15 x Red LED (7 for each die, 1 for player two)
1 x green LED (player one)
2 x PCF8574P (one for each die)
2 x 1.5 KOhm resistor (brown, green, red, gold) You can use up to 2 KOhm. I put 1 KOhm + 680 Ohm in series instead.
16 x 680 Ohm resistor (blue, gray, brown, gold)

2 x 10 KOhm resistor (brown, black, orange, gold)
14 x transistor (C547B)
2 x press-to-connect buttons

 
 

/* define addresses of the dice */
#define DICE_1 (0x4 << 3 | 0x0) // 0100000
#define DICE_2 (0x4 << 3 | 0x1) // 0100001

/* include wire */
#include

/* define pin output for player lights and buttons */
int light1 = 9;
int light2 = 10;
int button1 = 11;
int button2 = 12;

/* define gamemodes */
int gamestart = 0;
int gamePlayer1 =1;
int gamePlayer2 = 2;
int rollingPlayer1 = 3;
int rollingPlayer2 = 4;
int gameEnd = 5;
int gameMode = gamestart;

/* current number for each die*/
int curNum[2];

/* results for each throw */
int result1[2];
int result2[2];

int tick=0;
int tmp=0;
bool tmpBool;
int input;

/* different dicemodes */
byte dicemode[8] =
{
  B0000000,
  B0001000,
  B1000001,
  B1001001,
  B1010101,
  B1011101,
  B1110111,
  B1111111

};

byte curmode_d1;
byte curmode_d2;

void setup()
{
  /* start the I2c */
  Wire.begin();

  /* set pins */
  pinMode(light1, OUTPUT);
  pinMode(light2, OUTPUT);
  pinMode(button1, INPUT);    
  pinMode(button2, INPUT);    
 
  /* reset dice */
  setDiceMode(DICE_1,0);
  setDiceMode(DICE_2,0);
}

void setDiceMode(byte dice, int num)
{
  /* copy a dice mode into the current mode for a dice */
  if (dice == DICE_1)
    memcpy(&curmode_d1,&dicemode[num],sizeof(curmode_d1));
  else
    memcpy(&curmode_d2,&dicemode[num],sizeof(curmode_d2));
}

void showDice()
{
  /* show die one by sending the current mode */
  Wire.beginTransmission(DICE_1);
  Wire.send(curmode_d1);
  Wire.endTransmission();
 
  /* show die two by sending the current mode */
  Wire.beginTransmission(DICE_2);
  Wire.send(curmode_d2);
  Wire.endTransmission();
}

void GameTick()
{
  if (gameMode==gamestart)
  {
    /* game starts, show all lights */
    setDiceMode(DICE_1,7);
    setDiceMode(DICE_2,7);
    showDice();
    digitalWrite(light1, HIGH);   
    digitalWrite(light2, HIGH); 
   
    tmp++;
    if (tmp == 20)
    {
      /* after 2 seconds the game begins, turn all lights off */
      gameMode=gamePlayer1;
      setDiceMode(DICE_1,0);
      setDiceMode(DICE_2,0);    
      showDice();
      digitalWrite(light1, LOW);   
      digitalWrite(light2, LOW);  
      tmp =0;
    }
  }
  else if (gameMode==gamePlayer1)
  {
    /* player one is at turn, blink players one's light */
     tmpBool=!tmpBool;
     if (tmpBool)
       digitalWrite(light1, HIGH);
      else
        digitalWrite(light1, LOW);  
       
     /* did player press his button? */
     input = digitalRead(button1);
     if (input ==HIGH)
     {
        gameMode = rollingPlayer1;
        digitalWrite(light1, HIGH);
        tmp=0;
     } 
  }
  else if (gameMode==gamePlayer2)
  {
     /* player two is at turn, blink players two's light */
     tmpBool=!tmpBool;
     if (tmpBool)
       digitalWrite(light2, HIGH);
      else
        digitalWrite(light2, LOW);  
       
     /* did player press his button? */
     input = digitalRead(button2);
     if (input ==HIGH)
     {
        gameMode = rollingPlayer2;
        digitalWrite(light2, HIGH);
        tmp=0;
     } 
  }
  else if (gameMode==rollingPlayer1)
  {
    /* rolling dice for player 1 */
    tmp++;
    if(tmp < 15)
    {
      /* rolling... */
      curNum[0] = random(1,6);
      curNum[1] = random(1,6);
      setDiceMode(DICE_1,curNum[0]);
      setDiceMode(DICE_2,curNum[1]);   
      showDice();
    }
    /* after 1.5 seconds show result, till 2 seconds passed */
    if(tmp == 20)
    {
     
      memcpy(&result1,&curNum,sizeof(result1));
     
      setDiceMode(DICE_1,0);
      setDiceMode(DICE_2,0);  
      showDice();
      gameMode=gamePlayer2;
      digitalWrite(light1, LOW);  
    }
  }  
  else if (gameMode==rollingPlayer2)
  {
     /* rolling dice for player two */
    tmp++;
    if(tmp < 15)
    {
      /* rolling... */
      curNum[0] = random(1,6);
      curNum[1] = random(1,6);
      setDiceMode(DICE_1,curNum[0]);
      setDiceMode(DICE_2,curNum[1]);   
       showDice();
    }
    /* after 1.5 seconds show result, till 2 seconds passed */
    if(tmp == 20)
    {
      memcpy(&result2,&curNum,sizeof(result2));
      setDiceMode(DICE_1,0);
      setDiceMode(DICE_2,0);  
      showDice();
      gameMode=gameEnd;
      digitalWrite(light2, LOW);  
    }       
  }
   else if (gameMode==gameEnd)
  {
    tmpBool=!tmpBool;
   
    /* was the result for player one more or equal to player two? */
    if (result1[0] + result1[1]>=result2[0] + result2[1])
    {
      setDiceMode(DICE_1,result1[0]);
      setDiceMode(DICE_2,result1[1]);
   
      /* blink LED */ 
       if (tmpBool)
         digitalWrite(light1, HIGH);
        else
          digitalWrite(light1, LOW); 
    }
   
    /* was the result for player two more or equal to player one? */
    if (result1[0] + result1[1]<=result2[0] + result2[1])
    {
      setDiceMode(DICE_1,result2[0]);
      setDiceMode(DICE_2,result2[1]);  
     
      /* blink LED */ 
      if (tmpBool)
         digitalWrite(light2, HIGH);
       else
          digitalWrite(light2, LOW); 
    }
   
    /* blink dice */ 
    if (!tmpBool)
    {
      setDiceMode(DICE_1,0);
      setDiceMode(DICE_2,0);   
    }
   
    showDice();
   
    /* did any player press a button? */
    if ((digitalRead(button1) == HIGH) ||
      (digitalRead(button2) == HIGH))
    {
      /* reset game */
      setDiceMode(DICE_1,0);
      setDiceMode(DICE_2,0);  
   
      showDice();
      digitalWrite(light1, LOW);
      digitalWrite(light2, LOW); 
      gameMode = gamestart;
      tmp=0;
    }
  }
}

void loop()
{
 
  /* ready for antoher tick? */
  if (tick==0)
  {
    GameTick();
  }

  /* tick,tick,tick */
  tick++;
  if (tick==100)
    tick =0;
   
  /* wait a bit */
  delay(1);
}



 
 
 
 
 
 
 

woensdag 25 november 2009

Project: Rolling the dice, expanding the Arduino (PCF8574P)

Last time we looked at I2C to support communication with other ICs from our Arduino. As I2C is only a communication method, we need an IC to expand the number of I/O pins  available to us, which communicates on I2C. The PCF8574P will just do that for us. Today we are going to blink a LED on distance with our Arduino.

The pin layout for the PCF8574P is as follows:


SYMBOL PIN                               DESCRIPTION
A0         1  address input 0
A1         2  address input 1
A2         3  address input 2
P0         4  quasi-bidirectional I/O 0
P1         5  quasi-bidirectional I/O 1
P2         6  quasi-bidirectional I/O 2
P3         7  quasi-bidirectional I/O 3
VSS       8  supply ground
P4         9  quasi-bidirectional I/O 4
P5        10  quasi-bidirectional I/O 5
P6        11  quasi-bidirectional I/O 6
P7        12  quasi-bidirectional I/O 7
INT       13  interrupt output (active LOW)
SCL       14  serial clock line
SDA       15  serial data line
VDD       16  supply voltage

As we have learned, each slave IC communicating with I2C needs an address. The address is one byte long, but we have only seven bits to send as the eighth bit is an read/write indication. For the PCF8574P the address always starts with 0100, leaving us 3 bits to set. This allows us to have 8 PCF8574P slaves connected in one I2C network, because the bits 1,1,1 = 7. So we have 0 - 7 = 8 possible settings. The three bits are set by connecting the pins a0 - a2 on either Vcc (1) or ground (0). For example if I have set  A0 = 1, A1=0, A2=0 my address to control the PCF8574P  would be: 0100001.

P0 through P7 are the input/output pins much like the ones on the Arduino. VSS is the ground connection pin, while Vdd connects to the voltage supply. INT allows you to disable the PCF8574P by placing a HIGH voltage on the pin. SCL and SDA are the familiar I2C pins which should connect to the Arduino.

The following circuit will  require the following components:
1 x Arduino Duemilanove
1 x Red LED
1 x PCF8574P
1 x 680 Ohm resistor (blue, gray, brown, gold)
2 x 1.5 KOhm resistor (brown, green, red, gold) You can use up to 2 KOhm. I put 1 KOhm + 680 Ohm in series instead.


Note the two resistor connected to the 5 volt pin on the Arduino.The following code will blink the LED:

#define CARD_ADR (0x4 << 3 | 0x0) // address 0100000

/* Include the wire header */
#include

void setup ()
{
  /* setup mwiring */
  Wire.begin();
}

void loop ()
{
  /* set all pins off */
  Wire.beginTransmission(CARD_ADR);
  Wire.send(B00000000);
  Wire.endTransmission();
  delay(1000);
 
  /* set all pins on */
  Wire.beginTransmission(CARD_ADR);
  Wire.send(B11111111);
  Wire.endTransmission();
  delay(1000);  
}






That's it for today, next time we will be completing the project!