Luis Antonio Martin Nuez
Published

The Ifs - Coding: it´s child’s play!

The Ifs are educational toys that teach girls and boys how to code from the age of three.

ExpertWork in progress650
The Ifs - Coding: it´s child’s play!

Things used in this project

Hardware components

Arduino Nano / Atmega 328p+FTDI circuit
The Arduino Nano is a small, complete, and breadboard-friendly board based on the ATmega328 (Arduino Nano 3.x). It has more or less the same functionality of the Arduino Duemilanove, but in a different package. It lacks only a DC power jack, and works with a Mini-B USB cable instead of a standard one.
×1
Power circuit
It includes a system DC/DC which supply 5V to the circuit thanks to a lithium battery.
×1
Buzzer
×1
Speaker
×1
Microphone
×1
PCB
Download section
×1
DHT11
The DHT11 is a basic, ultra low-cost digital temperature and humidity sensor.
×1
MFRC522 RFID Reader
The MFRC522 is a highly integrated reader/writer IC for contactless communication at 13.56 MHz. The MFRC522 reader supports ISO/IEC 14443 A/MIFARE and NTAG
×1
RGB Neopixel led
×1
3D printed enclosure
The casing was designed to integrate the electronic components of the system. It consists of several 3D printed pieces.
×1
Lithium battery
500 mA lithium battery
×1
TEMT6000 luminity sensor
TEMT6000 is a silicon NPN epitaxial planar pho- totransistor in a miniature transparent mold for sur- face mounting onto a printed circuit board.
×1
NRF24L01ALT1 2.4GHz Low Power Transceiver
The nRF24L01 is used on a wide variety of applications that require wireless control. They are transceivers which this means that each module can transmit and receive data.
×1
MPU-6050
The MPU-6050™ parts are the world’s first MotionTracking devices designed for the low power, low cost, and high-performance requirements of smartphones, tablets and wearable sensors.
×1

Story

Read more

Custom parts and enclosures

Holly 3D

Liam 3D

Emma 3D

Noah 3D

Schematics

The Ifs Schematic

The Ifs BRD

The Ifs 3D

The Ifs BOM

The Ifs Gerber

Code

The Ifs basic control code

Arduino
#include <Adafruit_NeoPixel.h>
#include <Wire.h> 
#include "pitches.h"
#include "NRF24L01.h"

//neopixels
#define  PIN 2
#define  NUMBER_OF_LEDS  2

//RF
#define TX_ADR_WIDTH    5   // 5 unsigned chars TX(RX) address width
#define TX_PLOAD_WIDTH  1  // 32 unsigned chars TX payload

//////Slots//////
//ifs
#define getTap 1
#define darkness 2
#define faceDown 3
#define EmmaCalls 4

//thens
#define turnLight 1
#define playSound 2
#define callLiam 3

int ifSlot;
int thenSlot;
int luz=0;
int golpe;
int tap_detection;

////sound////

// notes in the melody:
int melody[] = {
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 4
};

////acelermetro////

byte Version[3];
int8_t x_data;
int8_t y_data;
int8_t z_data;
byte range=0x00;
float divi=16;
float x,y,z;

/////RF///////

unsigned char TX_ADDRESS[TX_ADR_WIDTH]  = 
{
  0x34,0x43,0x10,0x10,0x01
}; // Define a static TX address

unsigned char rx_buf[TX_PLOAD_WIDTH];
unsigned char tx_buf[TX_PLOAD_WIDTH];


Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMBER_OF_LEDS, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
  Serial.begin(9600);
  
//neopixels
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  SPI_DIR = ( CE + SCK + CSN + MOSI);
  SPI_DIR &=~ ( IRQ + MISO);
  //  attachInterrupt(1, _ISR, LOW); // interrupt enable
  init_io();                        // Initialize IO port
  unsigned char status=SPI_Read(STATUS);

  
//acelermetro
  Wire.begin(); 
  Wire.beginTransmission(0x0A); // address of the accelerometer 
  // range settings
  Wire.write(0x22); //register address
  Wire.write(range); //can be set at"0x00""0x01""0x02""0x03", refer to Datashhet on wiki
  // low pass filter  
  Wire.write(0x20); //register address
  Wire.write(0x05); //can be set at"0x05""0x04"......"0x01""0x00", refer to Datashhet on wiki
  Wire.endTransmission();

}

void loop() {
  
 //Acelermetro
  switch(range)  //change the data dealing method based on the range u've set
  {
  case 0x00:divi=16;  break;
  case 0x01:divi=8;  break;
  case 0x02:divi=4;  break;
  case 0x03:divi=2;  break;
  default: Serial.println("range setting is Wrong,range:from 0to 3.Please check!");while(1); 
  }
  AccelerometerInit(); 
 
 checkIfs();
 checkThens();
 
 /////getTap y TurnLight estn encajadas//////
 if ((ifSlot ==1) && (thenSlot==1))
 {
  
  taps();

  if ((golpe==1)&&(luz==0)){
     colorWipe(strip.Color(255, 0, 0), 50);
  Serial.println("getTap & turnONLight");
  luz=1;
  
  }
   else {
     if ((golpe==1)&&(luz==1))
     {
     colorWipe(strip.Color(0, 0, 0), 50);
     Serial.println("getTap & turnOFFLight");
     luz=0;
     }
   }}

 else 
 
  /////getTap y PlaySound estn encajadas//////
   {if ((ifSlot==1) && (thenSlot==2))

          {
            taps();
            if (golpe==1)
             {
                music();
                Serial.println("music");
             }
          }
                  
  else 
  
   /////Darkness y TurnLight estn encajadas////////
    {if ((ifSlot==2) && (thenSlot==1))
    {
    if (analogRead(A3)>920)
      {
     colorWipe(strip.Color(0, 255, 0), 50); 
     }
    else{ if ((analogRead(A3)>780)&&(analogRead(A3)<920)){
      colorWipe(strip.Color(0, 0, 255), 50); }
     else colorWipe(strip.Color(0, 0, 0), 50);
     }
    }
  
  else
  
  /////Darkness y PlaySound estn encajadas////////
    {if ((ifSlot==2) && (thenSlot==2))
     {
        if (analogRead(A3)>900)
          {
            music();
            Serial.println("music");
          }
     }
    
    else

   /////FaceDown y PlaySound estn encajadas////////
    {if ((ifSlot==3) && (thenSlot==2))
      {
        AccelerometerInit(); 
        if (z_data<0)
         {
            music();
            Serial.println("music");
         }
      }
    
    else
     
   /////FaceDown y TurnLight estn encajadas////////
    {if ((ifSlot==3) && (thenSlot==1)){
     AccelerometerInit(); 
        if (z_data<0)
      {
           colorWipe(strip.Color(255, 0, 255), 50);
      }
      else {colorWipe(strip.Color(0, 0, 0), 50); 
    }}

        else
     
   /////EmmaCalls y TurnLight estn encajadas////////
    {if ((ifSlot==4) && (thenSlot==1)){
       Serial.println("Emma Calls y Turn Light");
      recibo();
    
     if (rx_buf[0]==1){   colorWipe(strip.Color(255, 255, 0), 50);rx_buf[0]=0;
           Serial.print(rx_buf[0],HEX);  
          }
       else {colorWipe(strip.Color(0, 0, 0), 50); Serial.print(rx_buf[0],HEX); 
       }
    }

            else
     
   /////EmmaCalls y Music estn encajadas////////
    {if ((ifSlot==4) && (thenSlot==2)){
       Serial.println("Emma Calls y Turn Light");

       recibo();
     if (rx_buf[0]==1){   music();rx_buf[0]=0;
           Serial.print(rx_buf[0],HEX);  
          }
       else {noTone(3); Serial.print(rx_buf[0],HEX); 
       }
    }
  
     
       else

   /////FaceDown y CallLiam estn encajadas////////
    {if ((ifSlot==3) && (thenSlot==3))
      {
        Serial.println("Face Down y Call Liam");
        AccelerometerInit(); 
        if (z_data<0)
         {
      envio();
         }
         }
    else

   /////GetTap y CallLiam estn encajadas////////
    {if ((ifSlot==1) && (thenSlot==3))
      {
        Serial.println("Face Down y Call Liam");
         
            taps();
            if (golpe==1){
              envio();
         }}

          else

   /////Darkness y CallLiam estn encajadas////////
    {if ((ifSlot==2) && (thenSlot==3))
      {
        Serial.println("Face Down y Call Liam");
         
           if (analogRead(A3)>900)
          {
              envio();
         }}
    ///Sino hay dos piezas encajadas
    else{colorWipe(strip.Color(0, 0, 0), 50);   noTone(3);}
 
 ////////////////////////////////

    
}}}}}}}}}}}
   


 
////////////////////  FUNCIONES   ////////////////////

//////////////Checks-comprueba si hay if then y cual es su valor//////////////

void checkIfs(){
  
 int sensorValue = analogRead(A2);
 if ((sensorValue>322)&&(sensorValue<328)){
  ifSlot = getTap;
  }
  else {if ((sensorValue>87)&&(sensorValue<94)){
  ifSlot = darkness;
  
  }  else {if ((sensorValue>40)&&(sensorValue<47)){
  ifSlot = faceDown;
  
  }
   else {if ((sensorValue>130)&&(sensorValue<136)){
  ifSlot = EmmaCalls;
  
  }
  else ifSlot = 0;
 }}}}

void checkThens(){
 int sensorValue2 = analogRead(A1);
  if ((sensorValue2>510)&&(sensorValue2<517)){
  thenSlot = turnLight;
  }
  else {if ((sensorValue2>179)&&(sensorValue2<185)){
  thenSlot = playSound;
  
  }
  else {if ((sensorValue2>20)&&(sensorValue2<25)){
  thenSlot = callLiam;
  
  }
  else thenSlot = 0;
  }}}
  

//Taps-comprueba si ha habido un golpe
int taps(){
  if (z_data>20) {
  Serial.println(z_data); 
  delay(100);
  AccelerometerInit(); 
  Serial.print("ahora");
  Serial.println(z_data); 
  
  if (z_data<20){
    return golpe=1;
  }
  else return golpe=0;
  }
  else return golpe=0;
}


//////////////Neopixels//////////////////

void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

///////////Acelermetro//////////////////

int AccelerometerInit() 
{ 
  Wire.beginTransmission(0x0A); // address of the accelerometer 
  // reset the accelerometer 
  Wire.write(0x04); // Y data
  Wire.endTransmission(); 
  Wire.requestFrom(0x0A,1);    // request 6 bytes from slave device #2
  while(Wire.available())    // slave may send less than requested
  { 
    Version[0] = Wire.read(); // receive a byte as characte
  }  
  x_data=(int8_t)Version[0]>>2;
  
  Wire.beginTransmission(0x0A); // address of the accelerometer 
  // reset the accelerometer 
  Wire.write(0x06); // Y data
  Wire.endTransmission(); 
  Wire.requestFrom(0x0A,1);    // request 6 bytes from slave device #2
  while(Wire.available())    // slave may send less than requested
  { 
    Version[1] = Wire.read(); // receive a byte as characte
  }  
  y_data=(int8_t)Version[1]>>2;
   
  Wire.beginTransmission(0x0A); // address of the accelerometer 
  // reset the accelerometer 
  Wire.write(0x08); // Y data
  Wire.endTransmission(); 
  Wire.requestFrom(0x0A,1);    // request 6 bytes from slave device #2
   while(Wire.available())    // slave may send less than requested
  { 
    Version[2] = Wire.read(); // receive a byte as characte
  }  
   z_data=(int8_t)Version[2]>>2; 
   return z_data;
} 

/////////////////PlaySound///////////////////

void music(){
    // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(3, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(3);
  }
}


//////////////RF//////////////////////

//**************************************************
// Function: init_io();
// Description:
// flash led one time,chip enable(ready to TX or RX Mode),
// Spi disable,Spi clock line init high
//**************************************************
void init_io(void)
{
  SPI_PORT&=~CE;      // chip enable
  SPI_PORT|=CSN;      // Spi disable  
  SPI_PORT&=~SCK;     // Spi clock line init high
}

/**************************************************
 * Function: SPI_RW();
 * 
 * Description:
 * Writes one unsigned char to nRF24L01, and return the unsigned char read
 * from nRF24L01 during write, according to SPI protocol
 **************************************************/
unsigned char SPI_RW(unsigned char Byte)
{
  unsigned char i;
  for(i=0;i<8;i++)                      // output 8-bit
  {
    if(Byte&0x80)
    {
      SPI_PORT |=MOSI;    // output 'unsigned char', MSB to MOSI
    }
    else
    {
      SPI_PORT &=~MOSI;
    }
    SPI_PORT|=SCK;                      // Set SCK high..
    Byte <<= 1;                         // shift next bit into MSB..
    if(SPI_IN & MISO)
    {
      Byte |= 1;                // capture current MISO bit
    }
    SPI_PORT&=~SCK;                     // ..then set SCK low again
  }
  return(Byte);                     // return read unsigned char
}
/**************************************************/

/**************************************************
 * Function: SPI_RW_Reg();
 * 
 * Description:
 * Writes value 'value' to register 'reg'
/**************************************************/
unsigned char SPI_RW_Reg(unsigned char reg, unsigned char value)
{
  unsigned char status;

  SPI_PORT&=~CSN;                   // CSN low, init SPI transaction
  status = SPI_RW(reg);             // select register
  SPI_RW(value);                    // ..and write value to it..
  SPI_PORT|=CSN;                    // CSN high again

  return(status);                   // return nRF24L01 status unsigned char
}
/**************************************************/

/**************************************************
 * Function: SPI_Read();
 * 
 * Description:
 * Read one unsigned char from nRF24L01 register, 'reg'
/**************************************************/
unsigned char SPI_Read(unsigned char reg)
{
  unsigned char reg_val;

  SPI_PORT&=~CSN;                // CSN low, initialize SPI communication...
  SPI_RW(reg);                   // Select register to read from..
  reg_val = SPI_RW(0);           // ..then read register value
  SPI_PORT|=CSN;                 // CSN high, terminate SPI communication

  return(reg_val);               // return register value
}
/**************************************************/

/**************************************************
 * Function: SPI_Read_Buf();
 * 
 * Description:
 * Reads 'unsigned chars' #of unsigned chars from register 'reg'
 * Typically used to read RX payload, Rx/Tx address
/**************************************************/
unsigned char SPI_Read_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
  unsigned char status,i;

  SPI_PORT&=~CSN;                   // Set CSN low, init SPI tranaction
  status = SPI_RW(reg);             // Select register to write to and read status unsigned char

  for(i=0;i<bytes;i++)
  {
    pBuf[i] = SPI_RW(0);    // Perform SPI_RW to read unsigned char from nRF24L01
  }

  SPI_PORT|=CSN;                   // Set CSN high again

  return(status);                  // return nRF24L01 status unsigned char
}
/**************************************************/

/**************************************************
 * Function: SPI_Write_Buf();
 * 
 * Description:
 * Writes contents of buffer '*pBuf' to nRF24L01
 * Typically used to write TX payload, Rx/Tx address
/**************************************************/
unsigned char SPI_Write_Buf(unsigned char reg, unsigned char *pBuf, unsigned char bytes)
{
  unsigned char status,i;

  SPI_PORT&=~CSN;                   // Set CSN low, init SPI tranaction
  status = SPI_RW(reg);             // Select register to write to and read status unsigned char
  for(i=0;i<bytes; i++)             // then write all unsigned char in buffer(*pBuf)
  {
    SPI_RW(*pBuf++);
  }
  SPI_PORT|=CSN;                   // Set CSN high again
  return(status);                  // return nRF24L01 status unsigned char
}
/**************************************************/

/**************************************************
 * Function: RX_Mode();
 * 
 * Description:
 * This function initializes one nRF24L01 device to
 * RX Mode, set RX address, writes RX payload width,
 * select RF channel, datarate & LNA HCURR.
 * After init, CE is toggled high, which means that
 * this device is now ready to receive a datapacket.
/**************************************************/
void RX_Mode(void)
{
  SPI_PORT&=~CE;
  SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // Use the same address on the RX device as the TX device
  SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // Enable Auto.Ack:Pipe0
  SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Enable Pipe0
  SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // Select RF channel 40
  SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // Select same RX payload width as TX Payload width
  SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
  SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);     // Set PWR_UP bit, enable CRC(2 unsigned chars) & Prim:RX. RX_DR enabled..
  SPI_PORT|=CE;                             // Set CE pin high to enable RX device
  //  This device is now ready to receive one packet of 16 unsigned chars payload from a TX device sending to address
  //  '3443101001', with auto acknowledgment, retransmit count of 10, RF channel 40 and datarate = 2Mbps.
}
/**************************************************/


/**************************************************
 * Function: TX_Mode();
 * 
 * Description:
 * This function initializes one nRF24L01 device to
 * TX mode, set TX address, set RX address for auto.ack,
 * fill TX payload, select RF channel, datarate & TX pwr.
 * PWR_UP is set, CRC(2 unsigned chars) is enabled, & PRIM:TX.
 * 
 * ToDo: One high pulse(>10us) on CE will now send this
 * packet and expext an acknowledgment from the RX device.
 **************************************************/
void TX_Mode(void)
{
  SPI_PORT&=~CE;

  SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // Writes TX_Address to nRF24L01
  SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // RX_Addr0 same as TX_Adr for Auto.Ack

  SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // Enable Auto.Ack:Pipe0
  SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Enable Pipe0
  SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10 retrans...
  SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // Select RF channel 40
  SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
  SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);     // Set PWR_UP bit, enable CRC(2 unsigned chars) & Prim:TX. MAX_RT & TX_DS enabled..
  SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);

  SPI_PORT|=CE;

}

/**************************************************/

void envio()
     {
            TX_Mode();                        // set TX mode
             int k = 0;
  
    for(int i=0; i<1; i++)
        tx_buf[i] = 1;        
    unsigned char status = SPI_Read(STATUS);                   // read register STATUS's value
    if(status&TX_DS)                                           // if receive data ready (TX_DS) interrupt
    {
      SPI_RW_Reg(FLUSH_TX,0);                                  
      SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);       // write playload to TX_FIFO
    }
    if(status&MAX_RT)                                         // if receive data ready (MAX_RT) interrupt, this is retransmit than  SETUP_RETR                          
    {
      SPI_RW_Reg(FLUSH_TX,0);
      SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);      // disable standy-mode
    }
    SPI_RW_Reg(WRITE_REG+STATUS,status);                     // clear RX_DR or TX_DS or MAX_RT interrupt flag
    //delay(1000);
  }

  void recibo()
  {
         RX_Mode();                        // set RX mode
       
  
    unsigned char status = SPI_Read(STATUS);                         // read register STATUS's value
    if(status&RX_DR)                                                 // if receive data ready (TX_DS) interrupt
    {
      SPI_Read_Buf(RD_RX_PLOAD, rx_buf, TX_PLOAD_WIDTH);             // read playload to rx_buf
      SPI_RW_Reg(FLUSH_RX,0);                                        // clear RX_FIFO
      for(int i=0; i<1; i++)
      {
          Serial.print(" ");
          Serial.print(rx_buf[i],HEX);                              // print rx_buf
          
      }
     
    }
    SPI_RW_Reg(WRITE_REG+STATUS,status);                             // clear RX_DR or TX_DS or MAX_RT interrupt flag
    //delay(1000);
    }

Credits

Luis Antonio Martin Nuez
6 projects • 71 followers
Electronic Engineer & Industrial Engineer. Cooking-Hacks, Libelium. #ehealth #IoT #Smartcities @Arduinodayzgz @makeronilabs @dlabs_co
Contact

Comments

Please log in or sign up to comment.