Intro to Arduino for Indoor Grow Lights

This tutorial is designed to prepare participants to learn enough basic programming and electronics skills to understand, implement, and customize indoor grow lights. The tutorial is separated into individual labs that build on each other and eventually get you to the basic functionality for the indoor grow lights.

Setup

Set up laptop

Check your parts

The standard kit of parts for this workshop should have:

  • 1 x FredBoard
  • 1 x USB interface board
  • 8 x male to male wires
  • 4 x female to male wires
  • 1 x LCD
  • 1 x 100 ohm resistor (gold brown blue red)
  • 1 x 10 ohm resistor (gold, black, blue, red)
  • 1 x potentiometer (knob)
  • 1 x LED
  • 1 x Power LED
  • 1 x MOSFET transistor (3 pronged black thing)

Check your install

  • Board:
    • We’re assuming you’re using the hackerfarm FredBoard. You can alternatively use any standard Arduino and a breadboard. If you’re using a Fredboard, make sure your board is plugged into your computer via USB cable and the power switch is set in the USB position. That means power is coming from the USB rather than the external DC input jack.
  • IDE
    • Open Arduino
    • Check library is installed properly
      • Files > Examples > look for I2CLCD under custom libraries

  • Check hardware board files are installed properly
    • Tools > board > Select Freakduino
    • Tools > version > Freakduino Standard
    • Tools > Port > Select COM port


You’re ready to go!

Lab 0 – Hello World
This is a basic lab to verify that your system is properly running. Plug in board to USB. Open Arduino IDE.

The Arduino Serial library allows your board to communicate with you and vice versa. You can see what the state of the system is internally by printing out specific messages. It’s an extremely useful and fundamental debugging tool.

Here, we’ll be using the Arduino Serial library to print “hello world” to the console. We’ll also print messages using both the Serial.print() and Serial.println() command so you’ll be able to see what the difference is. I recommend you to experiment with both commands because they come in quite useful.

To start, we initialize the Serial library in the setup() function using the Serial.begin(baudrate) command. This establishes the speed we communicate with the board. Then we print to the console using the Serial.print() and Serial.println() command. To see the output, click on the Serial Console button to open up the console. Make sure the settings are set to 57600 so the console communicates properly with the board.

Functions we’ll use:

// initialize the serial port and set it to 57600 bps.
Serial.begin(57600);

// print string to the serial port
Serial.print(string) 

// Print string to the serial port with a carriage return and newline at the end.
Serial.println(string)

Code:

void setup() 
{
 Serial.begin(57600);
}

void loop() 
{
 Serial.print("Hello,");
 Serial.println("Hello world");
}

Lab 1 – Blink an LED
In this lab, we will construct an LED circuit that can be made to blink. Resistors limit the amount of current that flow in a circuit. You can also think of it as a pipe that limits the flow of water. The narrower the pipe, the more the water flow is limited. The same goes for resistors. The higher the resistance, the narrower the “electron pipe” will be, limiting the flow of electrons. Without a resistor, an infinite amount of current would flow in a circuit causing overheating, fires, and frying components.

 Functions we’ll use:

/* PinMode sets the pin to an input or output. 
 The pin number refers to the pin number on the pin diagram. 
 An INPUT sets the pin to input so you can read if its high (1) or low (0)*/
pinMode(pin, dir)
// pin = pin number
// dir = INPUT or OUTPUT

/* If the pin mode is set to output, you can control it using digitalWrite to 
write a HIGH (1) or LOW (0) to it  */
digitalWrite(pin, val)
// pin = pin number
// val = LOW or HIGH or 0 or 1

/* returns 0 or 1 depending on if the reading is high or low If the pin is set to input, 
you can read if the pin is HIGH (1) or low (0) */
digitalRead(pin)
pin = pin number

/* delays a specific amount of milliseconds specified */
delay(msec)
msec = number of milliseconds to delay

In this lab, we’re going to connect an LED to a resistor and then hook that up to a pin on our Fredboard to drive it high and low. The other side of the resistor will be connected to GND (ground) which completes the circuit. You should see the LED blinking at the rate you set in the delay.

[ADD PICTURE OF CIRCUIT CONNECTED TO PIN 9] [ADD PICTURE OF BREADBOARD CONNECTION ON FREDBOARD]

Code:

void setup()
{
    pinMode(9, OUTPUT);
}

void setup()
{
    digitalWrite(9, HIGH);
    delay(300);
    digitalWrite(9, LOW);
    delay(300);
}
Lab 2 – Power Blink

In this lab, we’re going to keep the same code to blink an LED but use a transistor to drive a power LED. Congratulations on blinking an LED. It may seem trivial, but if you can control an LED, you can control anything. Turning on an LED is the same as turning on an air conditioner, heating element, motor, etc. The difference is that we rarely use a pin to provide power to a device. This is because the microcontroller pins can only provide a very limited amount of current to power a device.

We normally have an “interface circuit” and the pin of the microcontroller would just turn on and off the interface. In this case, we’re going to interface to a power LED using a transistor. The transistor we’re using is called a MOSFET and you can think of it as a simple switch, not unlike a common light switch.

One side of the MOSFET is connected to the power source (5V in this case) and one side is connected to GND. There is one more pin that is connected to the microcontroller pin and this controls when the transistor turns ON and OFF. The transistor can provide much more current to the power LED than the pin can. You would also control motors or any other high current devices in approximately the same way.

Now wire up the circuit according to the following diagram and test out the blink code again.

[ADD CIRCUIT DIAGRAM] [ADD PIC OF CIRCUIT AND BLINK]
Lab 3 – Fade

In this lab, we’ll be learning how to do fading and dimming. Fading an LED means that rather than having a full ON or a full OFF, we’re going to occupy some place in between where it won’t be full brightness, but the LED will still be on. This is also similar for controlling motor speeds.

The first thing we need to understand is that when we start occupying areas between HIGH and LOW or binary states, then we start moving from the realm of digital to the realm of analog. For example, the digital system we’re working on, signals will only have a value of 5V or 0V. However if we want to dim an LED, we’re going to need to have voltages that fall into areas between 0 and 5V. Analog voltages for our system can be any value between 0 and 5V.

To get these voltage values from 0 to 5V, we actually use an engineering trick. We turn the signal on and off very fast and change the ratio of the ON-time to the OFF-time to create the “average voltage” we want. In the case of an LED, we’re turning the LED on and off so fast that our eyes can’t perceive the change. It will just average the amount of light which would be the brightness of our average voltage driving the LED. This method of creating any “average” voltage we want over some specified range by switching the pin on and off quickly is called pulse width modulation. By varying the ratio of ON to OFF time, we can generate any voltage between 0 and 5V.

Functions we’ll use:

analogWrite(pin, val)
pin = pin number
val = 0 to 255
uses PWM
only for certain pins

delay(time)
blocking delay in msec
time = msec

Code:

int val = 0;
int fadeAmount = 5;

void setup()
{ 
    pinMode(9, OUTPUT);
}
void loop()
{ 
    val = val + fadeAmount;
    analogWrite(9, val);     
    delay(10);
}

Results:
You should see the LED connected on pin 9 slowly fade up. Once it hits the maximum fade value of 255, it will roll over back to 0 and the LED will turn off. Then it will start fading up again. Technically, we’d like to avoid rolling over the fade value. To prevent this, we can use an “if” statement to stop the value from incrementing when it reaches 255 or near 255. If you want to see a good example of this, check out the “Fade” example in the Arduino IDE. It can be found in the File menu under “File/Examples/Basics/Fade”.

Lab 4a – Knob

So far, we’ve mainly been working with outputs. Outputting text to the serial port, outputting visual displays using LEDs. In this lab, we’re going to start working with inputs. Inputs are whatever you feed into the system. It could be sensor data, a keyboard interface, pushing buttons, etc. In this case, we’ll be using a knob, a.k.a. a potentiometer, to feed information into our system. We’ll use the position of the knob to control how bright our LEDs will be.

First let’s learn how to read a control knob. A knob or potentiometer works on a fundamental electronic principle called a voltage divider. If we connect the top pin of the potentiometer to 5V and the bottom pin to GND or 0V, the middle pin will output a voltage between 0 and 5V depending on the position of the knob. Here’s a picture of the potentiometer and how it works:

To be able to read the voltage, we’re going to use a hardware feature of the microcontroller on the Fredboard called the ADC or Analog to Digital Converter. The ADC converts a voltage between 0 and 5V into a 10-bit number between 0 and 1023. A value of 0 would be 0V and 1023 would be 5V with everything in between being linear. Here is a graphic I drew to teach about the ADC.

To use the ADC, we’re going to feed wire up the knob to the breadboard on the Fredboard as follows:

  • Pin 1: 5V power rail
  • Pin 2: A0 on the Fredboard
  • Pin 3: 0V ground rail
[ADD PICTURE OF CONNECTION]

Once the connection is setup, let’s add the code.

Functions we’ll be using:

val = analogRead(pin)

// pin = Analog pin we will be reading (A0 to A5)
// val = function return value. It will be a value between 0 and 1023.

Code:

void setup()
{
    Serial.begin(57600);
}

void loop()
{
    int val = analogRead(A0);
    Serial.println(val);
}

Result:

This code initializes the Serial port and then continuously reads an analog value on A0. It uses the ADC to convert the analog voltage to a value between 0 and 1023 and then outputs the value as text on the Serial port display. To view the text, you need to open the Serial console in the Arduino IDE. When you turn the knob, you should see the printed value change.

Note: You may have noticed we didn’t use the pinMode function to initialize the knob pin. This is because all pins are initialized to input by default. We only need to initialize the pin if we want it to be output. You can also explicitly initialize the pin to be INPUT which would be clearer for others to understand.

Lab 4b – Knob

Now lets try to actually do something with the knob value. We have the previous code from the Fade lab where we controlled the LED brightness using analogWrite. This time, we’re going to control the LED brightness by turning the knob. We’ll do this by reading the value from the knob, translating that into a brightness value for the LED, and then writing that value to the LED.

Code:

void setup()
{
    pinMode(9, OUTPUT);
}

void loop()
{
    int val = analogRead(A0);
    
    // we need to divide the value by 4 to 
    // translate between the 0 to 1023 range
    // of the ADC and the 0 to 255 range of 
    // the LED 
    val = val / 4;
    analogWrite(9, val); 
}

Result:

If everything went well, you should be able to use the knob to control the brightness of the LED. Using a user input to control an output is called interaction and it’s an essential part of product design.

Lab 5a – LCD Display

This final lab is also a 2-parter. In the first part of this lab, we’ll be connecting up an LCD display and displaying some text on it. LCD displays are extremely useful to give user readable information. Normally, LCD displays require many connections but we’ll be using a special type of display which uses only four pins for control. To send information to the LCD, we use a serial protocol called I2C. We don’t need to worry about this too much though because we’re just going to use the I2CLCD library which abstracts a lot of the details so you can just focus on displaying the message you want to use.

Before we start this lab, make sure you have the I2CLCD library installed. You can check by looking at the File/Examples menu listing and searching for the I2CLCD examples folder. You should be able to see it. If this all checks out, let’s go to the code.

Functions we’ll be using:

// Create an LCD object
LiquidCrystal_I2C lcd(addr, columns, rows)
// addr = LCD's I2C address. This will be either 0x27 or 0x3F depending on the LCD
// columns = number of characters the LCD can display per row
// rows = number of rows the LCD has

// initialize the LCD, usually in the setup function
lcd.begin()

// print a string to the LCD
lcd.print(string)

// clear the LCD
lcd.clear()

// move the cursor to the 0,0 position of the LCD
lcd.home()

// move the cursor to some position on the LCD
lcd.setCursor(col, row);

Code:

#include 

// create an LCD object with I2C address of 0x3F
LiquidCrystal_I2C lcd(0x3F, 16, 2);

void setup()
{
    lcd.begin();
    lcd.print("Hello world!");
}

void loop()
{
}

Result:

If everything goes well, this code should print out “Hello world!” on the first row of the LCD. If you can’t see any text, you might want to check if the LCD bias is set correctly. There’s a small knob on the back of the LCD that you can turn with a screwdriver. This sets the voltage bias which affects the LCD contrast. If it’s set too low, you won’t be able to see anything and if it’s set too high, you’ll just see a black bar.

Also, if you wanted to print something on the second row, you can use the function lcd.setCursor(0, 1) to set the cursor to row 1 (it starts from row 0). Don’t forget that if you want to print something on the LCD, its best to clear the LCD before printing new data on it. Otherwise, you might have some remnants of old text on the display.

Lab 5b – LCD Display

Finally, this will be the last lab for this tutorial. This should tie everything together and give you a functional design you can already use for your indoor grow lights. It would be a very basic design, but with the main functionality there, everything else are just details.

In this lab, we’re going to use the knob to control the brightness of the LED and display the brightness value on the LCD. This will leverage what we learned in the previous lab (4b) to use the knob to control the LED brightness. We’ll add the extra steps of initializing the LCD and printing the value on the LCD.

Code:

#include 

// create an LCD object with I2C address of 0x3F 
LiquidCrystal_I2C lcd(0x3F, 16, 2); 

void setup()
{
    pinMode(9, OUTPUT);  
    lcd.begin(); 
}

void loop()
{
    int val = analogRead(A0);
    val = val / 4;
    analogWrite(9, val);
    lcd.clear();
    lcd.print("LED: ");
    lcd.print(val);
    delay(10);
}

Result:

This code ties all the previous labs together by using the knob to control the LED brightness and displaying it on the LCD. You might notice that the LCD is a bit dimmer than normal. This is because it’s constantly refreshing the data. A smarter way to do this is to only refresh the LCD when the data has changed. It’ll be up to you to implement that part but it shouldn’t be too difficult now that you’ve built up all this skill.

FINISHED!

Congratulations!!!

You now possess the skills to control your own technology. You can read inputs, write outputs, turn things on and off, and write to displays. That comprises pretty advanced features for most products. Check out the other tutorials we’ll be posting later on to learn how to do even more cool stuff 🙂

Akiba