Pages

Friday, August 8, 2014

Photogate Tutorial Part 3: Discovering More Sophisticated Parts

Welcome to the third installment of our Arduino Photogate Tutorial. In addition to the parts described in the first part of the tutorial, which are necessary for the most basic photogate circuit, there are some additional components that give the system more flexibility in terms of doing things in the real world. In this post, I'll describe these components, how they work, how to set them up, and where you can buy them (though again, I don't guarantee that the sources I link to are the best or cheapest option). If you are not very familiar with electronics or Arduino, the first two posts in this tutorial series cover the basics.

If you are going to use the Arduino and photogates outdoors, or for extended periods of time, you may need to disconnect the system from your computer. The computer does three things for the Arduino: it uploads the sketch, provides power, and stores data the Arduino collects. Once the sketch has been uploaded to the Arduino, you can disconnect it from your computer and it will keep running. You can power an Arduino with a 9V battery, using a battery holder with a 5.5x2.1 mm, center positive barrel jack connector; anything marketed as being compatible with Arduinos should work. Adafruit sells a compatible battery holder for about $4. 


                                        The barrel jack connector plugs into the Arduino's barrel jack.                                       Photo Credits: liquidware.com, store.cutedigi.com, ladyada.net

To store data on the Arduino, you can use a data logging shield (available from Adafruit for around $20). The data logging shield, or data logger, records data to an SD card (you can buy a 2GB SD card for about $5). It also has a real time clock (RTC) on it, so it can time-stamp the data it collects. Adafruit's data logger comes mostly assembled, but does require you to solder the header pins. I recommend using the stacking headers (instead of male headers). The stacking headers allow you to put another shield on top, and also make it easy to plug wires into the signal, power, and ground pins for quick prototyping.

Stacking Header Pins vs. Male Header Pins

Soldering (pronounced "soddering") is a common method of assembling electronic parts. Similar to the way hot glue guns melt the glue, which then hardens and holds things together, a soldering iron melts a special type of metal wire, called solder, onto the components you want to attach, where the solder then re-hardens. A good general guide to soldering can be found here, and the guide to soldering the header pins on the Adafruit data logger is here. To solder, you will need a soldering iron, a spool of solder, a stand for the iron (so you can set it down while working), and wire cutters. RadioShack sells a soldering kit for $11.

Once you have assembled the header pins, you need to format the SD card and set the time on the RTC. The SD card needs to be formatted to either the FAT16 or the FAT32 file system, and it is a good idea to reformat your SD card before starting a new project. FAT is an acronym for "File Allocation Table", and SD card file systems are essentially different methods of efficiently using the space on an SD card. You can read more about file systems here, but all you need to know for this project is how to change the file system on your SD card. When you put the SD card into your computer, a box will open with the SD card's files. Reformatting will erase all files on the SD card, so make sure to save anything you need to your computer. Right-click on the name of the SD card, and one of the options will be "Format".


 Click on "Format", and this box will come up:


Select either FAT32 or FAT16 under "File System", and click start. Once the reformatting is complete, the SD card is ready to use.

You also need to set the current time on the data logger's RTC. While Arduino has its own built in time-keeper, it's pretty limited- it measures time in milliseconds since the Arduino was last turned on, so every time you connect your Arduino to power, you have to manually set the time to what you estimate the current time will be when the sketch finishes compiling. If the Arduino ever loses power, the time will reset to zero. If you want to avoid the hassle of setting the time every time you plug in your Arduino, an RTC can be a good investment. Once you set the time and date on an RTC, it will keep track of them until its battery runs out, and the coin cell batteries used by the data logger can last up to 7 years. Adafruit's data logger comes with one built in, so if you're getting the data logger you might as well use its RTC. Figuring out how to set the time on the RTC was surprisingly difficult- most of the sketches I tried ended up setting the time wrong by about thirty seconds because they were getting the time from my computer, then compiling, and then setting the RTC to the time they saved at the beginning of the upload. However, I eventually found a clever, easy to use solution at Instuctables.com: setting the time through serial input. If you are not familiar with Arduino's serial communication, I recommend checking out these tutorials for sending and receiving information from serial. Essentially, you can type things into the serial window, and if you have written an appropriate sketch, the Arduino will do things based on what you type. You can also write sketches that print things in the serial window. Here is the sketch to set the RTC:

// This sample program allows the user to set the date and time of an RTC using I2C.
// Codes by:                            
// eGizmo Mechatronix Central           
// Taft, Manila, Philippines            
// http://www.egizmo.com                
// April 15, 2013                       

#include <Wire.h>
const int DS1307 = 0x68; // Address of DS1307 see data sheets
const char* days[] =
{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const char* months[] =
{"January", "February", "March", "April", "May", "June", "July", "August","September", "October", "November", "December"};

// Initializes all values:
byte second = 0;
byte minute = 0;
byte hour = 0;
byte weekday = 0;
byte monthday = 0;
byte month = 0;
byte year = 0;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(2000); // This delay allows the MCU to read the current date and time.

  Serial.print("The current date and time is: ");
  printTime();
  Serial.println("Please change the line settings on the lower right of the Serial Monitor to 'Newline'");
  Serial.println("Would you like to set the date and time now? y/n");

  while (!Serial.available()) delay(10);
  if (Serial.read() == 'y' || Serial.read() == 'Y')

  // This set of functions allows the user to change the date and time
  {
    Serial.read();
    setTime();
    Serial.print("The current date and time is now: ");
    printTime();
  }

  Serial.println("Thank you.");
}

// Continuous function for converting bytes to decimals and vice versa
void loop() {
}
byte decToBcd(byte val) {
  return ((val/10*16) + (val%10));
}
byte bcdToDec(byte val) {
  return ((val/16*10) + (val%16));
}

// This set of codes is allows input of data
void setTime() {
  Serial.print("Please enter the current year, 00-99. - ");
  year = readByte();
  Serial.println(year);
  Serial.print("Please enter the current month, 1-12. - ");
  month = readByte();
  Serial.println(months[month-1]);
  Serial.print("Please enter the current day of the month, 1-31. - ");
  monthday = readByte();
  Serial.println(monthday);
  Serial.println("Please enter the current day of the week, 1-7.");
  Serial.print("1 Sun | 2 Mon | 3 Tues | 4 Weds | 5 Thu | 6 Fri | 7 Sat - ");
  weekday = readByte();
  Serial.println(days[weekday-1]);
  Serial.print("Please enter the current hour in 24hr format, 0-23. - ");
  hour = readByte();
  Serial.println(hour);
  Serial.print("Please enter the current minute, 0-59. - ");
  minute = readByte();
  Serial.println(minute);
  second = 0;
  Serial.println("The data has been entered.");

  // The following codes transmits the data to the RTC
  Wire.beginTransmission(DS1307);
  Wire.write(byte(0));
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekday));
  Wire.write(decToBcd(monthday));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.write(byte(0));
  Wire.endTransmission();
  // Ends transmission of data
}

byte readByte() {
  while (!Serial.available()) delay(10);
  byte reading = 0;
  byte incomingByte = Serial.read();
  while (incomingByte != '\n') {
    if (incomingByte >= '0' && incomingByte <= '9')
      reading = reading * 10 + (incomingByte - '0');
    else;
    incomingByte = Serial.read();
  }
  Serial.flush();
  return reading;
}

void printTime() {
  char buffer[3];
  const char* AMPM = 0;
  readTime();
  Serial.print(days[weekday-1]);
  Serial.print(" ");
  Serial.print(months[month-1]);
  Serial.print(" ");
  Serial.print(monthday);
  Serial.print(", 20");
  Serial.print(year);
  Serial.print(" ");
  if (hour > 12) {
    hour -= 12;
    AMPM = " PM";
  }
  else AMPM = " AM";
  Serial.print(hour);
  Serial.print(":");
  sprintf(buffer, "%02d", minute);
  Serial.print(buffer);
  Serial.println(AMPM);
}

void readTime() {
  Wire.beginTransmission(DS1307);
  Wire.write(byte(0));
  Wire.endTransmission();
  Wire.requestFrom(DS1307, 7);
  second = bcdToDec(Wire.read());
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read());
  weekday = bcdToDec(Wire.read());
  monthday = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}


When you upload this sketch, open the serial window:



I recommend also opening NIST in a separate window so that you can see accurate time. Follow the instructions that appear in the serial window to set the date and time. I changed those instructions a little from the original Instructable, to make it clearer. Specifically, the line setting needs to be set to "Newline", and I found that the program didn't accept uppercase "Y" as a serial input- I needed to use lowercase. Also note that this sketch doesn't allow you to set time to the second- I recommend hitting "send" for the minute right as the time changes from one minute to the next. For example, if it's 9:14:50, type 15 when it asks for the minute, and hit send when it changes to 9:15:00.




Once the time is set, your RTC will keep track of it for the next several years, even if the Arduino just sits on a shelf, without needing any maintenance. The RTC on Adafruit's data logger knows how many days are in each month and adjusts for leap years, but doesn't account for Daylight Savings.

Another accessory that is useful for photogate projects is the breakout board. A breakout board simplifies the photogate- instead of five leads and a resistor to deal with, you just have three wires (after some soldering, of course). This makes it much easier to put the photogate into a circuit, and you get to choose how long those three wires are, which is useful if you want to use the photogates at some distance away from the Arduino.  A breakout board for Sparkfun's photogates costs $1.50.


The final addition to our collection of electronics is the Mux shield. The Mux shield gives you the ability to use 48 signal pins, instead of the dozen or so that are standard on Arduinos. We only plan to use eight photogates for our current feeder design, but we wanted the electronics to be adaptable for future projects, so we are using a Mayhew Labs Mux shield. They can be bought from Sparkfun for around $25.

There are several possible ways to assemble both the Mux shield and the data logger. For the feeder project, we are making a shield sandwich: Arduino Uno on the bottom, Mux shield in the middle, data logger on top. Because we are using several shields, we went with stacking headers for both shields. We put the data logger on top so that the SD card would be easily accessible, and we chose female right-angle connectors for the Mux shield, because it's in the middle of the sandwich and we wanted to make sure the pins would be accessible.


The Arduino Sandwich

We haven't assembled the circuit in its final form yet (it works, but it's still on a breadboard), and this post is already a bit long, so I'll post about the final circuit and the sketch that runs it next week.

4 comments:

  1. That's really cool. I'm looking forward to seeing it in action.
    Just out of curiosity, how hard is it to access the rtc? Would it be possible to use the rtc to initialize the internal arduino clock?

    ReplyDelete
  2. I think you could, but it wouldn't be any better than just using the RTC for timekeeping. It would be better than having to set the internal clock manually every time you use it, for what it's worth. There are sketches that let you tell the Arduino what time it really is and make the Arduino use that to convert its internal time into real time (ie, It was 11:49:14 when I was turned on. It's been 30 seconds since I turned on. So the time is now 11:49:44), and you could use the RTC to send the “It was 11:49:14 when I was turned on” part. It would be less of a hassle and you wouldn't have to play the guessing game of figuring out what time it will be when the sketch finishes uploading. But you would still need the RTC to resend the time every time you turn the Arduino on. If you're going to go to the trouble of buying and setting up an RTC, you might as well get the time straight from it- I don't think you'd really gain anything by making the Arduino's internal clock a middleman.

    ReplyDelete
  3. Makes sense. What I was wondering though, is that if there are any native functionalities that use the arduino internal, you wouldn't need to (re)write them to use the RTC instead (on the other hand, you can log the time it gets turned on separately and do the addition afterwards).

    ReplyDelete
  4. I know this was 3 years ago, but hopefully you can answer my question. Did you have to solder that right-angle connector to the Mux Shield?

    ReplyDelete