Taillieu.Info

More Than a Hobby..

Arduino

  • A Beginner's Guide to Arduino

    After some years of experimenting with Arduino, I decided that the time has come to share the knowledge I've acquired. So I here it goes, a guide to Arduino, with the bare basics for beginners and some more advanced explanations for people who are somewhat more familiar with electronics.

    Every step will consist of a detailed explanation, then a summary, followed by a more advanced approach.

    If you're a complete beginner, I recommend reading the explanation first, and then the summary. There will (almost certainly) be some parts of the explanation you don't understand. Don't worry, it is absolutely normal, it will become clear after reading some other examples in the next steps, just don't get discouraged!

    I'll provide some links to the Arduino reference page, Wikipedia, and some other interesting sources. If you want to know more about about a certain subject, these are great places to start. Again, if you don't understand a word of those links, don't worry, it is absolutely not necessary for this Instructable, and especially for beginners, they can be very confusing or even demotivating. If that's the case, it might be better to skip them for now. But don't give up!

    Although a tutorial like this might be very helpful, you'll learn mostly by experimenting yourself. Use this Instructable as a starting point, as a reference, but make your own projects, modify the given examples, try new things, search the internet, the possibilities are pretty much endless!

    Step 1: What Is Arduino?

    Well, first things first: What is Arduino?
    Let's take a look at the introduction from the Arduino website:

    Arduino is an open-source prototyping platform based on easy-to-use hardware and software. Arduino boards are able to read inputs - light on a sensor, a finger on a button, or a Twitter message - and turn it into an output - activating a motor, turning on an LED, publishing something online. You can tell your board what to do by sending a set of instructions to the microcontroller on the board. To do so you use the Arduino programming language (based on Wiring), and the Arduino Software (IDE), based on Processing.

    That actually says it all.
    You can find the complete introduction here.

    Maybe a little more information about the board:

    The Arduino Board itself is a blue circuit board, the size of a credit card (but they also have models in other sizes). It has two rows of connectors (the 'headers'), a power connector and a USB connector. The brain of the board is an Atmel microcontroller. It's like a really small, very low power 'computer'. (It only has 32KB of storage, 2KB of RAM, and the 8-bit processor runs at only 16MHz.) For most applications, however, this is more than enough. The pins of the processor connect to the headers, and you can connect them to virtually anything you can imagine. You just need to write some lines of code to control them. The I/O pins (Input/Output) can be used as input pins, to connect buttons or knobs, temperature sensors, light sensors, or even keyboards and mouses, digital musical instruments … or they can be used as output pins, to connect LEDs, drive motors, control the lights in your home, connect to small displays or even connect to the Internet, so that it can check your mail, post tweets... Through the USB connection you can also use it to control your computer, or use your computer to control the Arduino.

    As you can see, the sky's pretty much the limit !

    You can buy an Arduino from their website or from a local reseller for about $22 (€20).

    To get an idea of what you can do with an Arduino board, check out the Arduino blog or the Arduino channel here on Instructables.

    (image credit: arduino.cc)

    Step 2: Before You Begin...

    How not to fry your Arduino

    Before you begin plugging things into your new Arduino, it may be good to know what can damage the board.

    1. Drawing more than 40mA from an output pin.
      An Arduino can only supply 40mA per output pin, so you cannot drive a motor or a speaker directly, for example, and you cannot connect an LED directly (without a resistor). In the course of this Instructable, I'll explain what you should do instead.
      Shorting an output in to the +5v, +3.3v or the ground pins, will also kill your board: If an output pin is at 5v for example, and you connect it to the ground, it draws an enormous amount of current, and kills your Arduino almost instantly.
      The pins go through the circuit board, so make sure you don't place the Arduino on a conductive (metal) surface, because it will short out the pins.
    2. Drawing more than 200mA from all output pins together.
      The ATmega chip on your Arduino can only supply 200mA in total, so driving more than 10 LEDs @ 20mA each, for example, will eventually damage your board.
    3. Supplying more than 5v (3.3v) to an input pin.
      Supplying more than the operating voltage of the Arduino on any pin is very dangerous. Some Arduinos that run at 3.3v have 5v tolerant pins, but that's about it. This also holds true for other devices, like sensors or wireless chips: always check the voltages: if you connect the output of a 5V Arduino to a 3.3V chip, you might kill it.
    4. Supplying more than 5v to the 5v pin.
      The 5v of the Arduino board goes directly to the ATmega chip, that is rated for an absolute maximum of 6v.
    5. Supplying more than 12v to the Vin pin.
      There's an onboard 5v voltage regulator on the board, that will overheat and die if you feed it with more than 12v.
    6. Drawing more than 500mA from the 5v pin (when running off an external power supply.
      The onboard 5v voltage regulator can only supply 500mA of current. The 5vUSB has a polyfuse to limit the current to 500mA.
    7. Drawing more than 50mA from the 3.3v pin.
      The onboard 3.3v voltage regulator can only supply 50mA of current. This means that you can not connect power hungry 3.3v devices like an ESP8266 or nRF24L01 directly to the Arduino: you need an external 3.3v voltage regulator.
    8. Reversing the polarity of the power supply.
      If you swap the 5v or Vin pin with the GND pin, you'll kill the board almost instantly.
      The barrel jack has a diode to protect against reverse polarity.
    9. Connecting a load to the Vin pin while using USB power.
      If you connect a load to the Vin pin while the 5v to the Arduino comes from the USB connection, current will flow backwards through the voltage regulator, damaging it.
    10. Static electricity
      Although most chips have clamping diodes as protection against ESDs (electrostatic discharges), it may be wise to us an anti-static wrist strap, or to remove the carpet under your desk.

    Step 3: Software

    Arduino IDE

    For programming our Arduino, we'll need the Arduino IDE (integrated development environment).
    It can be downloaded from the site.

    Windows:

    1. Go to the site, go to Download, and select the Windows installer.
    2. Consider donating some money, if you want to support the project, and click download.
    3. Click the downloaded file to run it.
    4. Grant administrator permission.
    5. Agree to the License Agreement.
    6. Select the appropriate boxes, you'll need the Arduino Software and the USB driver, the other three are optional.
    7. Accept the default installation folder, or pick another one. Then click install.
    8. When you're prompted whether or not you want to install the Arduino USB Driver (device software), click install.
    9. Wait for the installer to complete, and launch the Arduino IDE.

    (A complete installation guide can be found on the Arduino website as well.)

    Ubuntu:

    1. Go to the site, go to Download, and select the right Linux version.
    2. Consider donating some money, if you want to support the project, and click download.
    3. Open a terminal window (CTRL+ALT+T), and run these commands, changing the filename appropriately
    4. cd Downloads
    5. tar xf arduino-1.6.11-linux64.tar.xz
    6. sudo mv arduino-1.6.11/ /opt/arduino-1.6.11/
    7. /opt/arduino-1.6.11/install.sh
    8. sudo usermod -a -G dialout $USER

    This goes to the Downloads folder, unzips the downloaded file, moves it to the /opt/ folder, and runs the install script. This install script will create a desktop file, and a MIME type to associate .ino files with the Arduino IDE. Finally, you have to add (-a = append) your user to the 'dialout' group (-G), in order to have access to the serial ports. ($USER is a system variable for the current user) If you open the Arduino IDE now, you'll see that the Tools > Port option is grayed out. When your user is added to the dialout group, log out, and sign back in. Your Arduino's serial port should now be available in the IDE.

    Arduino IDE + Teensyduino

    If you have a Teensy board, you'll need the Teensyduino add-on for the Arduino IDE. The installation is very simple, and a very good install guide can be found on the Teensy site.

    Teensyduino currently doesn't support the latest versions (1.6.10 & 1.6.11 @07-09-2016) of the Arduino IDE yet, so you'll have to download a previous version. (1.6.9)

    If you're running Linux, you may come across this error while installing Arduino:

    bash: /opt/arduino-1.6.6/install.sh: Permission denied

    If this is the case, try running

    sudo chmod +x /opt/arduino-1.6.6/install.sh

    This adds (+) the permission to be executed (x). Then try running /opt/arduino-1.6.6/install.sh again.

    Example sketches

    I added a .ZIP file with all the example sketches I'll be using throughout this Instructable, download and unzip it so you can follow along, or even modify them to your own needs if you want to.

     

    Step 4: Hardware & Electronics

    Before we begin, I'll explain some of the basic electronic components. If you only just started with electronics, this is for you!

    Sometimes I'll use some physics to explain how a certain component works, this is just a side note, it doesn't really matter if you don't understand this yet. It'll take some time to get used to.
    If you want to go further into electronics, however, you'll find out that electronics is just applied physics.

    I also provided some links to videos on YouTube that helped me understand the basic principles of the different components.

    Basic physics

    Electricity is the flow of electric charge carriers: electrons (in most cases).

    Electrons are the negatively charged particles that whirl around the positively charged nucleus (core, plural: nuclei) of an atom.

    Electrons can move easily through metals, like copper, silver, gold... We call these materials conductors.
    These materials have freely moving electrons.

    Materials like plastic, wood, glass, air... don't conduct electricity very well. They are called insulators.
    They don't have moving electrons or other charge carriers.

    A piece of material that has more negative charges (electrons) than positive ones (nuclei with positive protons), is negatively charged.
    A piece of material that has less negative charges than positive ones, is positively charged.
    (Note that only the electrons can move, the positive nuclei are stuck in a grid.)

    Just like magnets, opposite charges attract each other: when you have one piece of material that has more electrons, and one piece that has less electrons, the electrons in the negative piece will be attracted to the positive piece. If there's a conductor in between these pieces, these electrons will 'flow' to the positive part: This is electric current.

    Current expresses the amount of charges that flow through a conductor per unit of time. Its unit is Amps (Ampère), and is defined as C/s, where C is Coulomb (charge) and s is seconds (time). Its symbol is I.

    A battery has a negative side that has more electrons, and a positive side that has fewer electrons. Like I said earlier, the electrons will try to reach the positive side, but they cannot go through the internal circuit of the battery itself. This gives the electrons potential energy. This is the energy that is released as light and heat in a bulb, as motion (kinetic energy) in a motor... The difference in potential energy of a charge at the positive and a charge at the negative side, is called the voltage. The unit is Volts, and is defined as J/C, where J is Joule (SI-unit of energy) and C is Coulomb (SI-unit of charge). This expresses how much energy a certain charge (read: certain amount of electrons) releases.
    The symbol for Volts is V or U (from the German word 'Unterschied', difference, and refers to the potential difference).

    Power is the amount of energy that is released per unit of time. The SI unit is Watts, and is defined as J/s where J is Joules, and s is seconds. If you multiply current by voltage (C/s ∙ J/C) the C cancels out, so you get J/s. This means that voltage multiplied by current gives you the wattage.

    In most schematics, the conventional current flow is used: arrows are drawn from the positive side to the negative side. In practice, however, only electrons can move, so the actual direction of the current flow is from the negative side to the positive side.

    Resistors

    Resistors are components with - as the name implies - an electrical resistance, in other words, they limit the flow of electrons, so they are often used to limit the current.

    The SI unit of resistance is Ohms, often written as the Greek letter omega (Ω). They are often used with the unit prefixes kilo (k) and mega (M). E.g. 1.2MΩ = 1M2Ω = 1,200kΩ = 1,200,000Ω = 1,200,000E = 1,200,000R. (note that writing a digit after the unit prefix is the same as writing it after the decimal point. Also, in some schematics, E or R are used instead of Ω).

    The value of a resistor is indicated by 4 (or 5) colored bands, using the resistor color code:
    The first 2 (or 3) bands are the 2 (or 3) first digits of the value, and the 3rd (or 4th) band is the power of ten that comes after those 2 (or 3) digits. This is also called the multiplier, and is just the number of zeros you have to add. The last band is the tolerance, and is mostly silver or gold.
    E.g. red red red gold = 22 x 100Ω = 2,200Ω = 22 x 10² Ω = 2k2Ω = 2.2kΩ, with a tolerance of 5%; green blue black brown red = 560 x 10Ω = 5,600Ω = 5k6Ω = 5.6kΩ, with a tolerance of 2%.

    The relationship between resistance, voltage and current can be calculated using Ohm's Law.

    I = V/R

    where I is the current in Amps, V the voltage in Volts, and R the resistance in Ohms.
    This is a very, if not the most important formula in electronics, so try to remember it!

    Capacitors

    A capacitor is an electrical component that can store electrical charge (in the form of electrons).
    Although they are fundamentally different, in some ways, it behaves like a small rechargeable battery. 
    When a voltage is applied to a capacitor, the potential difference (a difference in number of electrons → the side with more electrons has a negative charge, compared to the other side) These electrons can flow out of the capacitor again, when the voltage is no longer applied, just like a battery.

    Capacitors are used in filters, for example to filter out the 50/60Hz noise from your power supply, or to filter high frequencies out of your music when you turn on the low-pass filter, or turn the bass and treble knobs on your amplifier. In these cases, the capacitor charges and discharges really quickly.
    Another use for the capacitor, is filtering out DC voltage.

    The SI unit of capacitance is Farad, or F. This is a very large unit, and most often, you'll see prefixes like pico (p), nano (n) or micro (µ).

    On some smaller capacitors, the capacitance is written using a three-digit number. The first two digits are the first two digits of the value, and the third digit is the power of ten to multiply it with. The unit of the value you get is picofarad.
    E.g. 104 = 10 x 10⁴ = 100,000 pF = 100 nF = 0.1 µF (= 0.0000001 F)

    Larger capacitors, the electrolytic type, (mostly the cylindrical ones) have a polarity, marked by a grey line. If you connect them the wrong way around, they can explode, be careful!

    Transistors

    A transistor is a semiconductor device, that is used to switch or amplify a signal. You can think of it as a switch, that can be operated by using a very weak signal, a current controlled switch.

    A transistor has three terminals: they are called the base (B), the emitter (E) and the collector (C).
    The emitter 'emits' electrons, and they are 'collected' by the collector. The base is used to control this flow of electrons.
    If a small current flows from the base to the emitter, a much larger current will flow from the collector to the emitter. How much larger this C-E current is, depends on a constant, specific to the type of transistor. This constant is called the DC current gain, and has the symbol of the Greek letter bèta (β) or Hfe. 
    E.g. if you have a transistor with β = 100, and your B-E current = 10mA, your C-E current will be 1A.
    This principle is used in amplifiers.

    Obviously, the transistor cannot keep on amplifying forever: at a certain point, the transistor will just act like a switch: the transistor is now in saturation mode.

    There are two types of transistors: NPN and PNP. This has to do with the semiconductors inside.
    The difference is the direction in which the current flows, more on this in the examples in the following steps.

    MOSFETs

    Another type of transistor is the MOSFET, acronym for Metal Oxide Semiconductor Field Effect Transistor.
    The MOS just stands for the materials it is made of, and FET signifies that the amount of current that is let through is controlled by a field, an electric field, more specifically. Physics tells us, that the higher the voltage, the stronger the electric field, so we can control the current using a voltage, whereas the normal (Bipolar Junction Transistor or BJT) uses current to control the current.

    A MOSFET also has three pins: a gate (G), a drain (D) and a source (S).
    The source is where the electrons come from, and they flow to the drain. This flow is controlled by the voltage at the gate (and its accompanying electric field). By analogy with the transistor, the gate can be compared to the base, the source to the emitter, and the drain to the collector.

    An advantage of a MOSFET over a BJT is the higher efficiency: when fully turned on, a MOSFET has a D-S resistance of a few tens of milliohms. This results in much less power (heat) dissipation when driving high-current loads. 
    Also, no current flows from the gate to the source.

    A disadvantage though, is that you need about 10v on the gate for most MOSFETs to be fully on. This is 2-3 times higher than the voltage of an Arduino output pin, for example.

    Diodes

    Just like a transistor, a diode is a semiconductor device. One of the interesting properties of a diode, is that they only conduct electricity in one direction. 
    For example, Arduino boards have a diode in series with their power input jack, to prevent you from reversing the power, and damaging the chip.

    Diodes have a forward voltage drop ranging from 0.5v to 0.7v. This means that if you measure the voltage before the diode, it will be about 600mV higher than after the diode.

    Of course, a diode has its limits: if the reverse voltage is too high, it will break, causing it to let current pass in the wrong direction. In some diodes, this is done in a controlled way. These diodes are called zener diodes. They will only conduct if the voltage is higher than a certain value, specific to the zener.
    This value is constant, so zener diodes can be used as a reference in voltage regulators.

    LEDs

    An LED, acronym for Light Emitting Diode, is like a normal diode, but they emit the energy (that is lost because of their forward voltage drop) as light, instead of heat. Their voltage drop is higher than a normal diode: ranging from 1.2v for an infrared LED, up to 3.5v for blue, white and ultraviolet LEDs.

    If the current going through the LED is to high, it will die. To prevent this, a resistor in series is used. 
    Always do this, otherwise, you'll kill the LED withing a second.

    Relays

    A relay is a mechanical current-controlled switch. It consists of a coil, next to a piece of metal, that is pulled back by a spring. When current flows through the coil, it generates a magnetic field that attracts the piece of metal, and makes a connection.

    The advantage is that you can control very high-current or AC loads, and they add virtually no extra resistance.
    The disadvantages are that relays are slow, since they have to move physically, they are more fragile, due to the moving parts, and they can create sparks.

    (To prevent sparks and interference when switching heavy loads, you should use a snubber circuit.)

    Other parts

    Of course there are countless other components you can use in your Arduino projects:

    Microphones and speakers: Dynamic microphones have a coil and a magnet to convert the vibrations of the air to electrical signals. Similarly, speakers use a coil that moves in a permanent magnetic field to generate those vibrations, when fed with an AC signal. Electret microphones translate air movement to changes in capacity. Piezo disks convert vibration to voltage, and vice versa, so they can be use as both a mic and a small speaker.

    Switches: switches are easy input devices for your Arduino, they exist in all shapes and sizes.

    Variable resistors or potentiometers: this is just circular resistive trace, and a wiper, connected to a turning shaft, that changes the resistance as it moves along the trace.
    Small versions without a shaft are called trimpots.

    ICs and chips: There's an immensely wide variety of ICs available, like voltage regulators, microprocessors, op-amps, amplifiers, logic gates, memory, timers, and so on.

    Sensors: You can find a sensor for virtually anything, light sensors, temperature sensors, distance sensors, alcohol sensors, even GPS modules, cameras... Other variants are optointerrupters, reed (magnetic) switches...

    Rotary or optical encoders: they convert movement to a series of pulses, like the volume knob in your car, or knob on your microwave oven.

    Displays: LCD displays can be used (some with touchscreen), or simple 7-segment LED displays, even small OLED displays are available.

    Fans, coils and motors: computer fans, solenoids, DC motors, stepper motors, servos, and so on.

    Power

    You can power your Arduino from a USB port, but this solution is limited to 5v and only 500mA, so if you want to use things like motors, or things that require a higher voltage, you'll need a power supply. 
    A benchtop power supply is the best solution, I think: They have current limiting features, adjustable voltages, and they can deliver a lot of power. Most of them also have some convenient 12v and 5v output, besides their adjustable output. But they tend to be quite expensive...

    A solution can be a wall-wart adapter, that plugs right into your Arduino. The on-board voltage regulator of the Arduino will step it down to 5v for the chip itself. The regulator can take any voltage between 6v and 12v, according to the specs.

    Another great power solution is a computer power supply: they have lots of power, thermal protection, short circuit protection, and deliver the most common voltages (3v3, 5v, 12v). There are loads of Instructables on how to hack an old computer PSU, for example: https://www.instructables.com/id/A-Makers-Guide-to-...
    A disadvantage is that the current protection is not sensitive at all, since it is designed for computer components that can draw over 30A or more in total, so your circuit may explode and catch fire, destroying anything that it's connected to, as long as it draws less than the rated current, the PSU will happily keep on supplying power.
    Also, the PSU uses really high voltages, inside a metal case, so hacking it isn't without any risks...

    You could also build your own power supply of course, but it will probably be cheaper to just buy a decent benchtop power supply.

    Power sources for mobile applications can be coin cell batteries, if the circuit doesn't draw a lot of power, or standard AA batteries, a 9v battery, rechargeable Ni-MH or Li-ion batteries, a USB powerbank, or even solar panels.

    Storage

    I use two drawer cabinets to store all small components, and a dozen of other boxes for motors, PCBs, cables etc. Some have small compartments, to store screws, nuts and bolts.

    If your Arduino or some other IC or chip came in a shiny plastic bag, don't throw it away! It is probably an antistatic bag, to protect components that are prone to damage due to ESD (ElectroStatic Discharge), use them to store your chips.

    Also, most ICs come in a piece of antistatic foam, keep them for storing your chips, it protects them against ESD, and keeps the legs from bending.

    Tools

    The basic tools you'll need are wire cutters and wire strippers, probably some pliers and a set of small screwdrivers. A multimeter comes in handy very often, and if you have two of them, you can measure both voltage and current at the same time, which is a big plus, though not at all necessary. 
    You'll also need a soldering iron, and some solder, maybe a desoldering pump, to salvage parts from an old PCB.

    For prototyping, you'll need a solderless breadboard, and some jumper wires. You could also use thin copper wire with a solid core. Either way, you'll need some wire, I usually buy red, black and white wire, about 10m each. (Red is used for positive, black for negative or ground, and white for 'other things') You'll be surprised of how fast you use it up.

    Some perfboard can come handy for permanent circuits.

    Step 5: Blink: Digital Outputs

    Blink: first Arduino code

    When you plug in your Arduino for the first time, you'll see a green light (with 'ON' written next to it - this is the power LED) and an orange light that blinks (with 'L' written next to it). This is the default 'Blink' program, it turns the internal LED on for a second, then turns it off for a second, repeating forever.

    Let's take a look at the code: Open the Arduino IDE and go to File > Examples > 01.Basics > Blink.

    The first thing you'll notice, are the first 14 lines that are lighter than the rest. Al text placed between the */ /* signs, is a comment. This is a multi-line comment. On line 17, there are some more comments, they use the // operator, everything on that line, that comes after the // is a comment. The next line is just normal code again, you don't have to close this single line comment, unlike the multi-line comment.

    Comments are used to make your code more readable, so it is strongly recommended that you use them in your own programs. It's not really necessary in a small program, like Blink, but when you are writing code of over a thousand lines, you'll be very thankful if you've added some comments, to help you understand what a particular piece of code does, and how it works. 
    You can also use the comment operators to (temporarily) disable a piece of code, without having to delete it permanently. This works, because comments do not get uploaded to the Arduino. (They are ignored by the compiler, the piece of software that converts the code you write in the Arduino IDE to commands that the Arduino can understand.) This also means that they do not take up any space in the Arduino's (limited) memory, only on your computer's hard disk.

    Arduino reference: Comments

    The next bit of code we encounter is 'void setup(){'
    This is the setup routine, it runs only once, every time the Arduino is started up. (void is a data type, it means no information is returned by the setup, more on this later. The two brackets are used in every function, to pass data through; setup doesn't need any data, so the brackets are empty. Don't worry if you don't understand this yet, we'll cover it in detail in the step about functions.)
    Everything between the two curly brackets or braces after 'void setup()' is the code that executes during the setup. Make sure you always close your brackets, otherwise, you'll get strange errors. The IDE helps you with this by highlighting the other bracket, if you select one.

    Arduino reference: void

    Arduino reference: setup

    Arduino reference: curly braces

    The first real command is 'pinMode(13, OUTPUT);'. As you might have guessed, this has to do with the two rows of pins on your Arduino: Those pins can either be used as an input or as an output. The first number is the pin we want to use as an output, 13 in this case, since all Arduino boards have an onboard LED connected to pin 13. OUTPUT, the second argument of the pinMode function, is a constant. This is a value that is defined by the software itself, and has been given an easy name. Constants will have a blue color. 
    (The value of OUTPUT is 1, which is a bit counterintuitive, since its O looks like a 0, and the I of the INPUT constant looks like a 1. pinMode(13,OUTPUT)exactly the same as pinMode(13,1) )

    By default, the Arduino's pins are set as an input, but by using the pinMode function, we've now set pin 13 as an output. We haven't told it what value we want to output yet, so it will just be 0. This means that, inside the chip, pin 13 is connected to 0v, this is the ground. If you would connect the 5v pin to pin 13 now, you would create a short circuit! Be careful!

    Arduino reference: pinMode

    Arduino tutorials: Digital Pins

    In the Arduino IDE, and other C-like programming languages, every statement is ended with a semicolon (;), as you can see in this Blink example. When you get cryptic errors when trying to upload, one of the first things to check are the semicolons. Most of the times, you'll get an error like this: Blink:16: error: expected ',' or ';' before...
    16 is not the line where there's a missing semicolon, but the line with the next command/statement.

    Arduino reference: ; semicolon

    The next structure element is 'void loop(){'
    The code between the curved brackets is executed after the setup is finished, and will repeat forever (at least until you restart the Arduino, or upload another program).

    Arduino reference: loop

    The next function is 'digitalWrite(13, HIGH)'
    This 'writes' pin 13 high, in other words, it connects it internally to the 5v pin. The LED on the Arduino is connected between the ground and pin 13, so now there's 5v across the LED, and it will light up.

    Be careful not to short pin 13 to the ground now, it will create a short circuit!

    You can see the same function being used with the LOW constant as well, this will connect pin 13 to the ground (inside the chip). Now there's no voltage difference across the LED, and it will go out.

    Instead of HIGH and LOW, you could also use 1 and 0, or true and false.

    Arduino reference: digitalWrite

    The last function is a very intuitive one: delay(1000)
    It just waits for a certain amount of time, in milliseconds. In this case, it will wait 1000 ms, or 1 second, before executing the next command.

    Arduino reference: delay

    When we arrive at line 29, we start all over at line 25, because we're in the loop.

    Summary:

    1. In the setup, that only runs once when the program is started, we set pin 13 as an output.
    2. In the loop, we make the output of the led HIGH (5v), wait 1,000ms, make it LOW (0v) and wait for another second. This loop will be repeated forever (at least until you restart the Arduino, or upload another program)
    • /*this is a comment */ this is not
    • this is not a comment // this is a comment
    • every statement ends with a semicolon ;
    • void setup(){ } is the function that runs once, when the Arduino starts up
    • void loop(){ } is the function that repeats forever, after the setup has run
    • pinMode(pin,OUTPUT); or pinMode(pin,1); sets the given pin as an output
    • digitalWrite(pin, state); sets a given pin high (5v) or low (0v). State can be HIGH or LOW, 1 or 0, true or false.
    • delay(time); waits for a given amount of time, in milliseconds.

    Step 6: Uploading a Program to the Arduino

    As an example, we'll upload the Blink example to the Arduino, but since it's already installed by default, change the value of the delay functions to 500 instead of 1000, otherwise we won't see any difference.

    Now connect your Arduino to your computer, if you haven't already. Wait for your computer to recognize the new USB device, and go to the Tools > Board menu in the Arduino IDE, and select your board. Then in Tools > Port, select the right port. In Windows, this will probably be a COM port. If there are multiple ports available, unplug your Arduino, then plug it back in, and see which of the ports disappears and reappears, to know the port of your Arduino. 
    On linux, it's probably /dev/ttyACM0 (/dev/ttyS0 is the serial port on your motherboard, so that's not the right one. If you are an older Arduino or a cheap Chinese clone, it could be listed as /dev/ttyUSB0).

    In the bottom right corner, you should now see the name of your board, and the port it's connected to.

    Now click the right-pointing arrow in the top left corner to upload Blink to the board. You could also use the shortcut CTRL+U. 
    If all goes right, it should start compiling, and then upload. While it uploads the TX and RX lights should flash.
    When it's complete, your led on pin 13 should now blink twice as fast.

    Compiling means that the human readable code you wrote is 'converted' to a series of binary numbers that the Arduino can understand. This binary file is then copied into the Arduino's memory during the upload.

    Step 7: Driving More LEDs

    Well, let's just face it: flashing one little LED is not that impressive... So in this step, I'll show how you can drive more LEDs.

    Calculating the resistor values for our LEDs

    Before you begin, we'll have to calculate the resistor to use in series with our LED. If you connect the LED directly to the Arduino, it will draw way too much current, resulting in a fried LED or even a fried Arduino.

    The formula we'll need, is Ohm's Law: R = VI

    But the problem here is that we don't know the voltage and the current of the resistor yet... Let's find it!

    We connect the resistor in series with our LED, and we know that the voltage of the Arduino's output pin is 5v, so if we add the voltage of the LED to the voltage of the resistor, this should equal 5v. Therefore: VR + VL = 5v, and VR = 5v - VL
    Since they are in series, this also means that all electrons that pass through the LED, will go through the resistor as well. Since current is defined as the amount of electrons per unit of time, we know that the current through the resistor is equal to the current through the LED. Therefore: IR = IL.

    Now we can use Ohm's Law to find the resistance of our resistor: R = VR/IR = (5v - VL) / IL

    (image 1)

    Note that if the current is given in milliamps (mA), you'll have to divide it by 1000, to get Amps, the SI unit of current. Otherwise, you won't get your answer in Ohms (but in kilo-ohms instead). This holds true for every physics formula: if you enter your values in their respective SI units, you'll always get an answer in an SI unit.

    If you are using a 3.3v Arduino, you can just substitute the 5v with 3.3v. This is just the supply voltage, it can be anything.

    The values for VL and IL can be found in your LED's datasheet, or you can use the table below.
    IL should be less than 20mA, otherwise, you'll kill your LED.

    VL is the LED's forward voltage drop. (LEDs that emit lower energy light, with longer wavelengths, like red and infrared have a much lower voltage drop than light with higher-energy photons, like blue or ultraviolet light.)

    Color Forward voltage (VL)
    Red 1.7v - 2.2v
    Orange 2.0v
    Yellow 2.1v
    Green 2.2v
    Blue 3.2v - 3.8v
    White 3.2v - 3.8v

    This is just an approximation, though, it will not hold true for every LED.

    You probably won't have a resistor of the exact value you just calculated, so round up to the next value in the E-12 series. This series only has the values 1.0, 1.2, 1.5, 1.8, 2.2, 27, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, and those values multiplied by a power of ten, like 10, 100, 1,000, 10,000 etc.
    For example, my result was 65Ω, so I took a resistor of 68Ω.
    It is better to take a resistor with a higher value, so you don't kill your LED.

    Connecting the LEDs to the Arduino

    Like I explained earlier, an LED is basically a diode, so it lets the current pass in only one direction. If we connect the LED the other way around, nothing will happen.

    An LED has a cathode and an anode: in schematic representation, the direction of the arrow is the conventional current flow direction, so it points to the negative side: the cathode. 
    When you take a close look at an LED, you'll see that one side is flat, and the other is round. Also, one leg is shorter than the other: the flat side, with the shorter leg is the cathode, and we'll connect this side to the negative, or ground of the Arduino.

    It doesn't matter where you put the resistor, as long as it's in series with the LED, so you can connect it either to the cathode or to the anode.

    If we know that only one LED will be on at the same time, we can use one resistor for all our LEDs.

    Take a look at images 2-3-4, then connect the resistor to the ground and one of the horizontal rails of your breadboard, and an LED with the short leg into the same rail, and the long leg in pin 12 on the Arduino.

    Note that you have to calculate the specific resistor for your LED. You can use the formula above, or use an online tool, or an app (I use this tool and this app). If you click the question marks next to the fields, the tool will give you some extra info, and the app has a drop-down menu for selecting the color.

    If you are in doubt, or - like me - just too lazy to look it up and find the right resistor, you can just use any resistor between 220Ω and 330Ω. This only holds true if you use it with a 5v Arduino! 270Ω and 330Ω are a bit high to use with a 3v3 Arduino, in that case, use something between 100Ω and 220Ω. If you want to use an LED with a higher voltage, you'll need to calculate it.

    When you have connected the LED and resistor to the Arduino, you can replace pin 13 in the Blink example by 12. You can use the shortcut CTRL+F: in the 'Find' field, enter 13, and in the 'Replace with' field, enter 12, then click 'Replace All'. Now upload the sketch to your Arduino: the LED you've attached should now blink.

    Still not impressed? No? Well, you're right...
    But now you've got the basics, we can do something more spectacular...

    More LEDs

    Connect 5 extra LEDs, to pins 2, 4, 6, 8 & 10 with their longer leg, and connect their shorter leg to the same rail on the breadboard as the LED on pin 12 and the resistor.

    Now open the example Blink6-a from the .ZIP file you downloaded in step 3.

    If you remember the Blink example, it shouldn't be too hard to predict what this program does. Upload it to your Arduino, and check if your hypothesis was correct!

    Optimizing the code

    If you take a closer look, you'll see that some pieces of the code are just 6 times the same commands, with just a different pin number... Well, there's a way to solve this: we call it the for-loop.

    Open the blink6-b sketch from the .ZIP file. When you upload it to the Arduino, you'll see that it does exactly the same as blink6-a, but it has much fewer lines of code.

    This is all thanks to the two for-loops that are used. 
    But before I can explain the for-loop, I'll first have to explain how variables work:

    On the first line, there's a new expression 'int delayTime = 200;' This is the so-called declaration of the variable 'delayTime'. A variable is just a piece of memory, where you can store pretty much anything you like. A variable has a data type, a name, and a value: in this case the data type is 'int': an integer, a whole number and can positive or negative. The name is 'delayTime', this is just an arbitrary name you give the variable, it can have letters and numbers in it, and some symbols like an underscore. If the name consists of more than one word, capital letters are used for every new word, because you can't use spaces. Choosing appropriate names for your variables will make a huge difference in the readability of your code. With 'int delayTime;', the variable is correctly declared, but doesn't have a value yet. Assigning an initial value to the variable is called initializing. In this case, we initialize variable delayTime to 200. Now every time we use 'delayTime' in our code, it will be replaced by the number 200. If you read a variable without first initializing it, it will just give you 0, in the best case, but probably just a random value that happened to be in that place of the memory, possibly causing errors in your program.

    You also have to know that a variable has a so-called scope. In this example, delayTime is declared at the top, so it is a global variable. This means that you'll be able to access it inside every function, every loop, in the whole program. A variable can also be local, meaning you can only use it in the scope in which it is defined. For example, if we were to move the first line to the setup, we would get the error

    'delayTime' was not declared in this scope

    when we'd try to access it in the main loop (delay(delayTime);), because this is a different scope than setup.
    But local variables can come in handy, when you don't have lots of memory to spare, for example, since the local are 'deleted' when you leave the scope they are declared in.
    Most of the time, the boundaries of a scope are curved brackets.

    But why use this variable? Well, instead of having to change all the delay(200); functions, we can just change the first line. In this case it's not very useful, but if you have really large program, it really matters.

    Arduino reference: variables

    Arduino reference: int

    Arduino reference: variable scope

    Another useful thing about variables is that you can change them, while your code runs. And this is exactly what happens in a for-loop. The first part between the brackets is just the declaration of a certain variable 'i', and we initialize it to 2. The next part is 'i <= 12', this means that the for-loop will repeat as long as i is less than or equal to 12. The third and last part 'i = i+2' means that every time the loop is repeated, the value of i will be increased with 2.

    All this means that it will first execute the code inside the brackets with a value of 2 for i, sets pin 2 as an output. Now it has reached the end of the code, so 2 is added to i → i is now equal to 4, and the code runs again with this new value for i: pin 4 is set as an output. 2 is added again, i is now equal to 6, the code is run again, 2 is added... and so on. Until i equals 12. When the loop gets executed for i = 12, everything is normal, but when it reaches the end of the code now, and 2 is added again, i doesn't meet the condition 'i ≤ 12' (i is now 14). The program exits the for-loop. 
    Every pin with an LED attached is now set as an output, with only two lines of code, instead of six.

    Arduino reference: for-loop

    Sumary:

    Finding the right resistor for your LED

    1. Look up the forward voltage in the LED's datasheet, or in the table above. This is VL
    2. Look up the forward current in the LED's datasheet, or use something between 2 and 20mA, and convert this number to Amps. This is IL
    3. Find the voltage of your supply, 5v or 3.3v for most micro-controllers like Arduino. This is Vs
    4. Now use this formula to find the resistor value: R = (Vs - VL) / IL
    5. Round this value up to the closest resistor you have. You can always use a higher value than the resistance you calculated, but if you use a lower resistance, this will drastically shorten the lifespan of your LED. If the resistance is too high, the LED will be very dim.
    • The round side of the LED, with the longer leg, is the anode, and is the positive side.
    • The flat side of the LED, with the shorter leg, is the cathode, and is the negative side.
    • CTRL+F opens the search/find/replace window in the Arduino IDE
    • int delayTime; this is the declaration of a variable of data type int, called 'delayTime'
    • int delayTime = 200; this is the declaration of a variable of data type int, called 'delayTime', and its initialization to a value of 200.
    • Global variables can be accessed everywhere in the program, local variables only in the scope where they were declared.
    • for(int i = 0; i<10;i=i+1){ } is a for-loop that initializes variable i to a value of 0, adds 1 to i every time it repeats, and repeats as long as i < 10 (10 times).

    Extra: Calculating the power dissipation in the resistor

    If you use a 5v power supply, like the one on the Arduino, a normal ¼ watt resistor will be enough, but when you use a higher supply voltage, or an LED that draws more current, the power dissipation in the resistor will be too high, and it will burn out.

    Therefore, we need to calculate what the power dissipation in the resistor is.

    (Image 6)

    The formula to calculate power is P = V∙I. So we can just calculate the voltage across the resistor: the supply voltage minus the voltage across the LED: VR = Vs - VL.
    And the current through the resistor is the same as the current through the LED: IR = IL.

    Therefore: PR = (Vs - VL)∙IL

    In the example shown in image 6, the power dissipation in the resistor is very low, so a ¼ watt resistor will be sufficient, but if the calculated value is higher, you'll need a more powerful (= thicker) resistor.

    These values are, however, just a theoretical assumption.

    If you really want to know the actual power the resistor dissipates, you'll have to measure the current or the voltage across it, or in the best case, both.

    In the case you can measure both the current and the voltage (case A), you can just use the same formula.

    If you can, however, only measure one of these values, you can use Ohm's Law to substitute either the voltage or the current in the formula for power. (case B & C)

    Only case A gives you the real power dissipation, in case B & C, you'll need the value of the resistor. The value written on the resistor has a certain tolerance, so you'll have some deviation in your wattage as well.

    Step 8: Even More Blinking LEDs

    Programming the LED sequence

    Open the example blink7.

    On line 3, you'll see a new structure: we call this an array. An array is basically a list of variables, in this case, it is a list of variables of the type int. We use square brackets to indicate that it is an array. To initialize the array, we use curved brackets, and the values are separated by commas.

    When we want to use a value from an array, we'll need to specify which place in the array we want the value of. Let's use the array in blink7 as an example :

    int array[] = {1,2,3,4,5,6,5,4,3,2};

    if we want to get the first value of the array, we use

    array[0]

    The zero between square brackets is called the index. Arrays are zero-based, this means that the first element in the array has index zero. This can be confusing at first, for example, array[5] will return 6, where you'd expect it to return 5.
    You can imagine that this can cause a lot of problems... That's why this error has its own name: an off-by-one error, or OBOE for short.

    When you try to read a value that isn't inside the array, array[10] for example, the Arduino will just read the next place in the memory, without realizing that the value it's reading isn't a part of the array anymore. It will just give you the value it finds at that particular spot in its memory.
    But things get even worse when you are writing to an index outside of the array, because you may be overwriting other data, like variables or pieces of code that happen to be at that place in memory! A bad idea...

    If you want to declare an array without initializing it yet, you can use

    array[10];

    Note that 10 is the number of elements, while the last element will be array[9] !

    If you initialize it on the same line, like in blink7, the Arduino IDE will count the elements for you, and you don't have to specify anything between the brackets.

    If you want to know the number of elements in the array, you can use the sizeof(array) function. This function returns the size of the array, in bytes (1 byte = 8 bits). This however, isn't the amount of elements, in blink7, sizeof(array) will return 20. This is because every element is an int, and an int is 2 bytes long. So the total number of elements is 20/2 = 10.
    We use this to exit our for-loop when we've read the whole array: As long as the index is less than the number of elements, we can safely read the array. We start with i = 0, since the first element has index 0. This time we only increase i with 1. The notation 'i++' is exactly the same as writing 'i = i + 1', it's just shorter. Another way of writing this would be 'i += 1'.

    Since LED #1 is connected to pin 2, LED #2 to pin 4, 3 to 6 etc, we multiply the LED number by 2 to get the pin number.

    Arduino reference: Array

    Arduino reference: Sizeof

    Arduino reference: Increment

    Arduino reference: Compound Addition

    You can change the values in the array to make your own sequence, and you could even add or delete elements, since we made our program independent of the length of the array, by using the sizeof() function.

    Summary:

    • An array is a list of values (or characters, or other arrays) and uses square brackets []
    • This is the declaration of an array: 'int array[10];'
    • This is the declaration and initialization of an array: 'int array[] = {1,2,3,4,5,6,5,4,3,2};
    • Array indices are zero-based, meaning the first element has index 0
    • sizeof(array) returns the size in bytes of the array
    • sizeof(data type) returns the size in bytes of the data type
    • sizeof(array)/sizeof(data type of array) gives you the number of elements in the array

    Extra: 2-dimensional arrays (Matrices)

    In an array, the elements can not only be data types, like ints, but also other arrays. This allows you to have so-called 2-dimensional arrays, that can be compared to matrices.

    This is used in example blink8: now you can set both the led number and the delay in the array.

    int array[][2] = {
      {1, 600},
      {2, 100},
      {3, 100},
      {4, 100},
      {5, 100},
      {6, 600},
      {5, 100},
      {4, 100},
      {3, 100},
      {2, 100}
    };

    Note that we have to specify all dimensions except the first one between the square brackets, when declaring a multi-dimensional array.

    The syntax to get a value out of the array is

    array[row][column]

    Open the example matrix_sum. This example won't do anything if you upload it, it doesn't have any outputs, it's just for learning purposes.

    It creates 4 matrices (2D arrays) , two of which have values. Then it just calculates the sum of the two matrices, and the transposed matrix for the first one.

    This is done by using nested for-loops. You can follow this explanation on the image above. 
    The numbers are the order the for-loop will go over them. i is used for the rows, j for the columns. They start at the first column and the first row (1,1) in matrix notation, [0][0] for array notation, then the column is incremented (1,2) or [1][0], the column is incremented again (1,3) or [2][0] when j is incremented again, the j-loop exits, because j is no longer less than three. i is incremented, j resets to zero: (2,1) or [0][1], j is incremented: (2,2) or [1][1], then (2,3) or [2][1]. i is incremented, j resets to zero: (3,1) or [2][0], then (3,2) or [2][1], and finally (3,3) or [2,2]. Now j exits, and i exits as well.

    The calculation of the transposed matrix is similar, it just swaps the columns and the rows:

    transposeMatrix[i][j] = matrixA[j][i];

    Inside these arrays, you can use more arrays, basically creating multi-dimensional spaces. In theory, he number of dimensions is unlimited, but once you use more than three dimensions, it gets really complicated, so other methods are preferred.

    Step 9: Input From a Button

    Of course, you can use the I/O pins of the Arduino as inputs as well. In this step, we'll just use push buttons as input devices, but of course, you can use any switch.

    Pull-up and pull-down

    The Arduino works with logical inputs: 1 = 5v, 0 = 0v. To make our button output these voltages, we'll use a pull-up or a pull-down resistor. (image 1 & 2)
    In the case of a pull-down resistor (image 1), we connect one leg of the switch to 5v, and the other leg through a resistor (10kΩ in this case) to ground (0v). The leg with the resistor connected goes to the input pin on the Arduino.

    This way, when the button is not pressed (and doesn't connect the 2 legs), the input is at 0v, because it's connected to ground through the resistor. When you press the button, the input is at 5v, because it's directly connected to 5v through the switch. The resistor doesn't matter when you press the button, it just makes sure that the input is at 0v when the button is not pressed.

    A pull-up resistor (image 2) works in exactly the same way, but everything is swapped: the first leg is connected to ground, instead of 5v, the second is connected to 5v, through a resistor (hence the name pull-up resistor, since it pulls it up to 5v). The input pin still connects to the side with the resistor, but now, it is high when the button is not pressed, and goes low when the switch is closed.

    Button Logical state pull-up Logical state pull-down
    released 1 0
    pressed 0 1

    Now, connect a push button with a pull-down resister to pin 3 of the Arduino, and a push button with a pull-up resistor to pin 5. Then connect two LEDs (with their appropriate resistor) to pins 10 and 12. (image 3 & 4)

    Now open example button2, and open it. This program just reads the two inputs, and sets the outputs in the same state.

    There are only two new things, and they are really obvious: instead of the OUTPUT constant, we use INPUT to set the pins of our buttons as inputs, and the digitalRead(pin) function just returns the state of the given input pin.

    Note: using pinMode(pin, INPUT) is actually unnecessary, since all pins on the Arduino are inputs by default, but it's often done anyway, to make the code more readable.

    When you upload the sketch, press the buttons, and you'll see that the table above is indeed correct: the LED on pin 12 is always on, until you press the button on pin 5, this is because it has a pull-up resistor.

    If you want the LEDs to light up only when you push the button, you can use the Boolean not-operator: this just changes a 'true' into a 'false' (or a 1 into a 0) and vice versa. In C++ (in the Arduino IDE), this operator is an exclamation mark (!)

    digitalWrite(12, !digitalRead(5));

    Internal pull-up resistors

    It would be really inconvenient if we had to use an extra resistor and an extra piece of wire, every time we want to use a normal switch. That's why the chip on the Arduino has a built-in pull-up resistor on every pin.

    There are two ways to enable them:

    pinMode(pin,INPUT);
    digitalWrite(pin, HIGH);
    pinMode(pin,INPUT_PULLUP);

    Both have the same effect, but the latter one is preferred, because it is more readable.

    Note: if you forget to use pinMode(pin, OUTPUT), and you use digitalWrite(pin, HIGH) afterwards, you'll just enable the pull-up resistor, because all pins are set as inputs by default.

    Now connect the push buttons without the resistors, just the connection to the ground (as shown in image 5)
    You can see that we don't need to use the 5v pin of the Arduino anymore, and if we were to produce this at a large scale, those two resistors we saved would make a significant difference in production cost.

    Open the example button2-b. As you can see, I used the two ways to enable the pull-up resistors. Also note that I used the 'not' operator, so the LEDs are on when the button is pressed.

    Sumary

    • To use buttons and switches with your Arduino, you have to use a pull-up or pull-down resistor.
    • pinMode(pin, INPUT_PULLUP); enables the internal pull-up resistors of the Arduino.
      digitalWrite(pin, HIGH); on an input pin has the same result.
    • digitalRead(pin) returns the state of the input pin 1 = 5v, 0 = 0v. 
      If you use a button with a pull-up resistor (e.g. the internal one), 1 means that the button is not pressed, 0 means it's pressed.
    • You can use the not-operator (!) to swap 1 and 0. E.g. !digitalRead(pin) returns 0 when the button is not pressed, and 1 when the button is pressed.

    Extra: Direct port manipulation (advanced)

    DigitalRead, digitalWrite and pinMode are great and simple functions, but they are relatively slow. Also, you can't turn on 2 pins on or off at exactly the same time, and writing 8 bits simultaneously for parallel communication is not possible either. Sometimes, when you're running short on memory, these 3 functions can use a lot of the available space, too.

    The solution to these problems is direct port manipulation. The Atmel chip has some (3 on most Arduinos) registers for the I/O pins, these are just bytes that store the info on whether a pin is an input or an output, whether it is set high or low, etc. Every bit of these bytes corresponds to an I/O pin on the Arduino.

    On the Arduino Uno, port D contains pins 0 to 7, port B pins 8 to 13, and port C A0 to A5.

    There are 3 registers to control the I/O (where x is the port letter):

    • DDRx: Data Direction Register: this sets whether the pins of the port are inputs(1) or outputs (0). (pinMode)
    • PORTx: Port Data Register: This is to set outputs high or low, and disable or enable the input pull-up resistors. (digitalWrite)
    • PINx: Port Input Register: This byte contains the state of the digital inputs. If the pin is an output, it will just give you the output state.

    In the image above, you can see the entire pin mapping of the Arduino Uno, the port numbers are in the yellow fields next to the pins. (image credit)

    Since every bit of the byte represents one pin, it is easier to write the values in binary notation. You can do this by adding a capital B before the number, for example, B111 is 7 in decimal (22 + 21 + 20).

    Similarly, you can use a leading 0 to use octal notation, or 0x for hexadecimal notation, however in this case using these two notations doesn't really make sense.

    When counting bits, the rightmost (least significant, LSB) bit is bit 0, so it corresponds to the first pin of the port, while the MSB (most significant bit) corresponds to the eighth pin of the port.

    Some examples:

    Setting pin 7 to an output, and pins 0-6 as inputs:

    DDRD = B10000000;

    Setting (output) pin 7 high:

    PORTD = B10000000;

    Enabling the internal pull-up resistor on (input) pin 6:

    PORTD = B01000000;

    Reading the state of pins 0 to 7:

    byte state = PIND;

    However, using it like this can cause some problems: e.g. in the second example, pin 7 is set high, but all other pins in the port are set to zero, regardless of their previous state. To change only one pin at a time, we can use some bitwise operators.

    To set one bit high, without changing the other bits, we can use the bitwise or-operator ( | ). Note: this is only one |, whereas the boolean or-operator is ||. Bitwise means that it is applied to every bit separately. We use a mask to set the right bit high: the bit we want to set high is 1, and all other bits are 0.

    byte previousPORTD = PORTD; // read the data register, and store it in a variable
    PORTD = previousPORTD | B10000000; // set bit seven high

    If a bit in the mask is one, this bit will be set to 1 in the PORTD register, if it is zero, it will just keep the value in previousPORTD. You can check out the truth tables and some examples in the images above.

    To set one bit low, without changing the other bits, we can use the bitwise and-operator ( ). Note: this is only one &, whereas the boolean and-operator is &&. Now we have to invert our mask: the bit we want to set low is zero, and all the other bits are one.

    byte previousPORTD = PORTD; // read the data register, and store it in a variable
    PORTD = previousPORTD & B01111111; // set bit seven low

    This notation works just fine, but we can make it a little more readable. Instead of writing a whole binary number for our mask, we can use the left bitshift operator (<<). it just shifts all digits to the left for a given number of places. For example: 1<<2 = B100, B101<<1 = B1010 and so on. This is also an easy way to calculate powers of two: 1<<7 = B10000000 = 128 = 27

    But we're going to use it to create our mask: for example, the mask B10000000 can be written as 1<<7, now you can easily see that it is the eighth pin in the register, without having to count the zeroes.

    To create the inverse mask, for the and notation, we can use the bitwise not-operator ( ~ ) to invert every bit: B01111111 can be written as ~(1<<7). (see image)

    If you just want to flip one or more bits, you can use the exclusive or-operator. (xor^ ). This returns 1 if one of the input bits is one, and 0 if both inputs are the same.

    byte previousPORTD = PORTD; // read the data register, and store it in a variable
    PORTD = previousPORTD ^ B10000000; // flip bit seven

    We can use compound operators to shrink the code: x = x + 1; can be written as x += 1; for example. The same goes for bitwise operators. We won't need the temporary variable anymore.

    PORTD |= 1<<7; // set bit 7 high
    PORTD &= ~(1<<7); // set bit 7 low
    PORTD ^= 1<<7; // flip bit 7

    To get one specific bit from the input register, for example, you could use the bitRead(byte, bit) function:

    boolean state = bitRead(PIND, 6); // read the state of the 6th pin of port D

    you could use some basic math to achieve the same result:

    boolean state = (PIND>>6)%2; // read the state of the 6th pin of port D

    This uses a right bitshift (>>) and a modulo operator (%): >> does the same as <<, but in the other direction. If PIND is B10101010, for example, PIND>>6 = B10, basically, it chops off the last 6 (binary) digits. The bit we wanted to check is now the rightmost bit. Modulo gives you the remainder of a division, e.g. 10%3 = 1, because 3*3 + 1 = 10, 5%6 = 5, because 0*6 + 5 = 5, 23%8 = 7, because 2*8 + 7 = 23. x%2 will give you a 0 if x is even, and 1 if x is odd. In binary notation, the last digit (rightmost bit) of an even number is 0, and the last digit of an odd number is 1. So if we just want to know the last digit of a binary number, we can just use x%2.

    Another way to get only one bit of a number is using the conditional operator ( ? : ) :

    boolean state = (PIND & (1<<6)) == 0 ? 0 : 1; // read the state of the 6th pin of port D

    PIND & (1<<6) will only keep the 6th bit of PIND, all other digits will be 0. If PIND is B10101010, for example, PIND & (1<<6) = B00000000, and if PIND is B01010101, PIND & (1<<6) = B01000000. From these examples, you can see that the result is zero if bit 6 was 0. So if we test if this result == 0, we know the state of bit 6. We use the conditional operator: condition ? resultIfTrue : resultIfFalse. If the condition is true, the operator will return the resultIfTrue, if it's false, it will return resultIfFalse.

    Note on compatibility: the port-to-pin mapping depends on the chip. This means that you have to change your program if you want to use another Arduino. For personal use, this isn't so much of a problem, but if you're writing programs or libraries for the community or to share online, you should take this into account.

    Arduino reference: Integer Constants

    He killed my wire: direct port manipulation tutorial

    Arduino reference: Port Manipulation

    The Atmel ATmega 328p datasheet p.91 14.4

    Arduino reference: bitRead

    Step 10: Communication With the Computer

    Up to this point, we only used the USB connection to upload new programs to the Arduino. But we can also use the connection to send data from and to the computer.

    Some Arduino boards like the Leonardo have a microcontroller that handles the USB communication all by its own, but most boards have a second, smaller microcontroller, solely for the communication. On the Arduino Uno, this is the small black square between the USB connector and the TX-RX LEDs. The communication between this chip and the main microcontroller is done using a serial connection, then the second chip tells the computer 'Hey, I'm a serial port', and then simply converts the serial data from the main chip to USB format, and converts the messages from the computer to serial for the main microcontroller.

    Serial means that bits are sent over the same wire, one after the other, whereas parallel connections send 8 bits or more simultaneously, on separate wires (like the large parallel printer port on the back of some older computers).

    The Arduino uses two serial lines: one from the Arduino to the USB chip, the transmit line (TX), and one line from the USB chip to the Arduino, the receive line (RX). These letters are written next to pin 0 and 1. This means that these pins are in use when you have the connection to the computer running, so you can't use them for LEDs or buttons etc. If you stop the communication again, you can just use them as normal I/O pins. 
    If you want to connect the Arduino to another device using serial communication, you also have to use these two pins.

    Sending inputs to the computer

    Open example serialButton, and upload it.
    The breadboard configuration is the same as in the previous step.
    Then open the serial monitor: Tools > Serial Monitor, click the magnifying glass in the top right corner or hit CTRL+SHFT+M. Make sure autoscroll is enabled, and the baud is set to 9600.

    You'll see a bunch of ones. Now press the push button connected to pin 3, and you'll see zeros. This is just the raw input from the pin.

    Now open the serial plotter: Tools > Serial Plotter or CTRL+SHFT+L. This will plot the values into a graph.

    Let's take a look at the code:

    In the setup, we add a new command: Serial.begin(9600). This is just to start the communication, and the 9600 is the baud rate, the number of pulses per second, so the speed of the serial connection. 9600 is just the default value. If you set this to a different value, you'll have to change it in the serial monitor as well. Otherwise, it will be out of sync, and give you very strange characters. The opposite of Serial.begin(...) is Serial.end(). You can use this when you have to use pins 1 and 0 as normal I/O again, after using the serial connection, however it's not really recommended.

    In the loop, you'll see the same Serial keyword, this time used with theprintln(...) function. This just prints out the value that's specified between the brackets, followed by a new line (ln).
    (Note that this doesn't just convert it to binary to send it over serial, instead, it converts it to ASCII, and then sends it over serial, so that the computer can print it out. If you want to send binary bytes over serial, use the Serial.write(...)function.)

    To get a new line, you could also use Serial.print(...) together with the \n(newline) character or the \r (carriage return) character, that indicate a line ending, instead of the ln.

    Serial.print(digitalRead(3));
    Serial.print('\n');

    The single quotation marks indicate that it is a character.

    Another special character is the \t (tab), let's use it to print the inputs of both switches. This is example serial2Buttons. Upload it, and open the serial monitor to see the result.

    Arduino reference: Serial

    Sending commands to the Arduino

    The communication also works the other way around: let's write a program to control LEDs from the computer.
    Open the example serialLEDs.

    Upload it, open the serial monitor, and try sending values between 0 and 3. Now send 4. Get how it works?
    Let's check out the code:

    The setup should look quite familiar, except one command: this is a while-loop. A while-loop repeats, as long as the condition between the brackets is true (you could compare it to a for loop, but without the first and last argument, only the condition.) I explicitly used the curved brackets to indicate it is a loop, but you could also just use a semicolon instead: while(!Serial);
    Serial returns true when the serial communication is active (when you open the serial monitor, for example). So if we add a not-operator (!), the expression is true when the communication is not active. So the while-loop keeps on repeating while the communication is not active, and essentially waits for it to become active. Then we know we can start sending data with the println(...) function. If we wouldn't use the while-loop to wait, some boards like the Leonardo (and other boards that have USB capabilities in the main chip) will just lose the first data. It does try to send it to the computer, but nothing there is listening for serial input.

    In the loop, there's another new statement: the if-statement, this is probably the most important statement in computer science. It does exactly what the name implies: it executes a piece of code, only when a certain condition is true. Otherwise, the code between the curved brackets is ignored.

    Now I'll take a moment to explain how the Arduino receives serial messages:
    As I explained earlier, serial sends one bit after the other, byte by byte. This means that your message, "test", for example, gets split up in pieces of 1 byte. A character is one byte in size, so it will look something like 't' 'e' 's' 't' when you send it over serial. When the Arduino receives these bytes, it will store them in a buffer (just a small piece of memory to temporarily store it). It receives it byte by byte, so the buffer will look something like this "" (empty) "t", "te", "tes" "test". 
    When the buffer is empty, the Serial.available() function will return 0, if there's received data in the buffer, it will return the number of bytes in the buffer, so 4 in this case. If you call the Serial.read() function, it will read the first byte ('t') from the buffer, delete it from the buffer, and shift the buffer, so it now contains "est", and Serial.available() returns 3. If you call Serial.read() again, it will return 'e', and the buffer will be "st". You can keep on reading until Serial.available() equals zero. (If you want to know the first byte without deleting it while doing so, you can use the Serial.peek() function.)

    So the first if(Serial.available > 0) will check if there's any data in the buffer. If so, it will read the first byte, and store it in the variable serialValue. Then it will check if the value it just read is '0'. Note the single quotation marks, this indicates character zero (ASCII: '0' = 48), and not 0 as a value, since the serial monitor sends it as text. If the value is '0', it will turn off both LEDs. If the value is not '0', code in the 'else' section will execute: so it will now check if the value is '1', if so, it turns on the first LED and turns of the second. If it's not '1' either, it will check if it's '2', if so, it turns on the second LED, and turns off the first one. If it's not '2', it will check if it is '3', if so, it turns on both LEDs, otherwise, it executes the code in the last else section, and prints what values you should enter.

    You can check the flowchart in the image if the explanation wasn't clear enough.

    Note that a double equality sign is used to check if two values are the same. If you would use a single equals sign, ( if(serialValue = '0') ) it won't check anything, it will just assign a value of '0' to the variable serialValue. This is a very common mistake.

    Other operators to test values are < (less than) > (greater than) <= (less than or equal to) >= (greater than or equal to) != (not equal to). 
    Inside of your if-statement, you can also use logical operators (Boolean operators), to check multiple conditions: && (and), || (or)

    Some examples:

    5 > 3 → true
    5 < 3 → false
    3 > 3 → false
    3 >= 3 → true
    5 != 3 → true
    3 == 3 → true

    to check if a value x is between 1 and 100:

    (1 <= x) && (x <= 100)

    another way of writing this (not recommended, just as an example)

    !( (x<1) || (x>100) )

    You can try to figure out how it works yourself, and then check with the truth tables in the image above.

    Note: Just like in mathematics, brackets are used to indicate the order of operations, for example, in the last expression, 'x<1' will be tested first, then 'x>100', then '||', and finally '!' .

    Arduino reference: While

    Arduino reference: If (and comparison operators)

    Arduino reference: Else

    Arduino reference: Boolean operators

    _

    Summary

    • Most Arduinos have a second chip for USB communication. This chip communicates with the main microcontroller using a serial connection.
    • Serial means that one bit is sent after the other, one at a time. There's a transmit line and a receive line (TX and RX respectively).
    • You can use the Serial Monitor (CTRL+SHFT+M) and the Serial Plotter (CTRL+SHFT+L) to show the data the Arduino is sending, and to send data to the Arduino.
    • Serial.begin(baud); starts the serial communication with the computer. The default baud rate is 9600.
    • Serial.end(); ends the serial communication.
    • Serial.print(text); prints text to the computer, it can be read in the serial monitor/plotter. Note that numbers are converted to ASCII: e.g. Serial.print(0); will send a serial value of 48 (ASCII code for the zero character).
    • Serial.println(text); does the same as print, but will add a new line after the message.
    • '\n' is a newline character, '\r' is a carriage return, and '\t' is the tab character (for indentations)
    • Serial.write(byte); sends a raw byte over serial. For example, Serial.write(48); will print a 0-character in the serial monitor.
    • while(condition) {... } is called the while-loop. Code between the curly brackets will be executed and repeated as long as the condition between normal brackets is true.
    • Serial returns true when the serial communication is active (when you open the serial monitor, for example).
    • while(!Serial); will repeat 'nothing' (read 'wait') as long as the serial communication isn't active.
    • if(condition) { if-code } else { else-code } will execute the if-code if the condition is true, and execute the else-code if the condition is false.
    • Serial data received by the Arduino is stored in a buffer, it stays there until you read it or until the buffer overflows.
    • Serial.available(); returns the number of bytes available in the buffer.
    • Serial.read(); will return the first byte in the buffer, and delete it afterwards.
    • Serial.peek(); will return the first byte in the buffer, without deleting it.
    • In your conditions, you can use these test operators: == (equal to), < (less than), > (greater than), <= (less than or equal to), >= (greater than or equal to), != (not equal to).
    • And you can also use the logical && (and) and || (or) operators.

    Extra: Switch

    In the last example, we used a lot of if... else statements. Although this is the fastest way to do it, it's not easy to read. If you want to compare a variable to some given values, you can use a switch.

    Open the example serialLEDsSwitch.

    As you can see, the switch starts with the 'switch' keyword, followed by the variable you want to check between brackets. Between the curved brackets, our cases are defined. They use the syntax 'case value:', followed by the code you want to execute if the given variable equals the value in this 'case'. After the case-specific code, the 'break;' keyword is used to close the 'case'.
    Note that the value you enter can not be a variable. If you want to compare 2 variables, you'll have to use if-statements.
    The code in the 'default:' case is executed if the variable doesn't match any of the values of other cases. This case is optional and can be omitted.

    Arduino reference: switch / case

    Step 11: Analog Inputs and Outputs.

    Some of the Arduino's I/O pins can also be used as digital inputs and outputs, to measure voltages (input) or dim LEDs (output) for example.

    Analog Inputs

    Most Arduinos have between 6 and 12 analog input pins. They can measure voltages ranging from 0v to the input voltage (5v or 3v3)
    An the board, these pins are labeled A0-A5, and in case of the Leonardo, some of the pins on the digital side can also be used as analog inputs. They are marked with a dot, and the name (A6-A11) is written on the back.

    Note that reading an analog input is (relatively) slow, compared to reading digital pins. This is because the Arduino measures voltages using an internal reference voltage generator (DAC, Digital-to-Analog Converter), and then comparing the input voltage to the reference voltage, then changing the reference voltage, comparing again, changing the reference voltage, comparing... until the two voltages are equal. http://apcmag.com/arduino-analog-to-digital-conver...

    The resolution of the internal DAC is 10 bits. This means that the maximum number it can read is 10 bits long, or 210 = 1024, so a number from 0 (B0000000000) to 1023 (B1111111111). 1023 means the input is 5v (or 3v3) and 0 means 0v.

    Potentiometers

    A potentiometer, variable resistor or pot for short, is just a knob with a wiper that slides over a round strip of resistive material. This way, it varies the resistance between the wiper and the endpoints.

    We're going to hook up our potentiometers and faders as simple voltage dividers. You can read more on this Wikipedia page if you're not familiar with this principle.

    If you take a look at the schematic, you can see 2 resistors. R1 is the resistor between the right pin of the potentiometer and the wiper (center pin), and R2 the resistor between the left pin and the wiper. Take a look at the formula as well. Since our potentiometer has a fixed value (50kΩ, for example), R1 + R2 will always be 50kΩ, while R2 can vary between 0Ω and 50kΩ. (If R2=50k then R1=0, and vice versa) Therefore, the fraction will always result in a number between 0 and 1. Multiply this ratio by 5V (Vsubin/sub), and you'll get a voltage between 0V and 5V on your output. This voltage can be read by the Arduino's ADC (analog to digital converter), and represents the position of the potentiometer (or fader). So basically, you connect the left pin to the ground, the right pin to the 5V pin on the Arduino, and the center pin to an analog input. (image 3)

    Connect a potentiometer to pin A0, and open the example AnalogReadSerial (File>Examples>01.Basics).

    The only new function is analogRead(pin). It's quite self-explanatory, it just gives you the 10-bit value, representing the voltage on the given pin.
    The program will just print them out over serial, so open the serial monitor (CTRL+SHFT+M) or the serial plotter (CTRL+SHFT+L) and twist the potentiometer. You should see values ranging from 0 to 1023. 
    Setting the delay to 10 or more, instead of 1ms may give you better results in the serial plotter.

    You can map the values from the 0-1023 range to any other range, for example from 0 to 100. This can be done using the map function. Take a look at example AnalogReadSerialMap. The syntax of the map function is: map(value, lowerLimitInput, upperLimitInput, lowerLimitOutput, upperLimitOutput) value is just the value to map, in this case our sensor reading. The range of this input is 0 to 1023, so these are our input limits. We want the output to range from 0 to 100, so these are our output limits. This means that if the sensor reads 1023, the output value will be 100. 
    We could have achieved the same result by using sensorValue * 100 / 1023.

    To convert it to a ratio, we have to use a data type other than int: float (floating point). If we divide our sensor value by 1023, we get a ratio between zero and one. 
    We can either change the data type of the sensorValue variable to float, or convert the value from an int to a float. The first method is used in AnalogReadSerialRatio-a, the latter one in AnalogReadSerialRatio-b.

    If we don't convert our value to a float first, the result will be treated as an int as well. The values after the decimal point will just be ignored, for example, 1/2 = 0, but 1.0/2 = 0.5. Normal numbers like '1' will be treated as ints, unless you add a decimal point (1.0), then it will be treated as a float. If one of the factors in a calculation is a float, the result will also be a float.

    To convert from an int to a float, you can use the float(number) function, or you could use the c++ notation for typecasting (converting from one data type to another) (float) number . 
    To convert from a float to an int, you can do this in the same way: int(number) or (int) number, but note that this will just truncate the number at the decimal point, it will just ignore the values that come after the decimal mark. For example, int(1.1) = 1, but int(1.9) = 1 as well, even int(1.99999) will give 1. To round the number, use the round(number) function, For example, round(1.1) = 1, round(1.5) = 2, round(1.99) = 2.

    https://www.arduino.cc/en/Reference/Cast

    https://www.arduino.cc/en/Reference/FloatCast

    Measuring voltages

    Since an analog value of 1023 corresponds to 5v (or 3.3v for 3.3v microcontrollers), you can easily convert this to a voltage by using analogRead(A0) * 5.0 / 1023 . This is used in the AnalogReadSerialVoltage example.

    To read voltages higher than 5v (3.3v), you'll need 2 resistors, to create a voltage divider. We can transform the formula above to get Vsubin/sub if we know Vsubout/sub. (see image) 
    Connect one resistor (R2) from the ground to the analog input, then connect the ground of the voltage to measure to the Arduino's ground, and then connect another resistor (R1) from the voltage to measure to the analog pin. (see image) Use the formula above to calculate the appropriate resistor values. Any values between 10k and 100k should work fine. If the resistance is too low, it will draw too much current, and influence the reading a lot.

    Too measure 12v for example, I use R1=47k and R2=22k. This gives me a maximum voltage of 15.87v, if I'd go higher than this voltage, I'd break my Arduino.

    Note: if R2 is - for whatever reason - disconnected or interrupted, the high voltage will be connected to the Arduino directly (through R1) and will probably damage or destroy it. So don't change the resistors if a high voltage is applied.

    Open the example AnalogReadSerialHighVoltage.

    At the top of the file, there are some constant declarations. Like a variable, constants can store values of all sorts, but unlike variables, constants can not be changed while the program is running. This means they are stored in the program storage space, instead of the dynamic memory (RAM), leaving more space for variables and arrays etc.

    Change the values of these constants according to your setup. The ratio is calculated automatically, so you don't have to change it. You could use the color codes of your resistor to get a theoretical value, but you'll get a much better approximation if you measure the resistors using a multimeter. The same goes for the operating voltage.

    Analog outputs

    The Arduino can't output analog voltages, it can only output either 5v or 0v. To output voltages in between, it uses a technique called PWM (Pulse-Width Modulation).
    The Arduino creates a square wave, and then varies the on- and off-times of the wave. For example, 2ms on, 2ms off; or 1ms on 3ms off. This is referred to as the duty cycle of the square wave. 2ms on, 2ms off is a duty cycle of 50%; 1ms on 3ms off is a duty cycle of 25%. (see image)

    You can now calculate the average voltage, which is the area under the curve divided by the amount of cycles. Let's take a look at the 50% duty cycle example: the area (evaluated over one cycle) is just a rectangle of 5 by 0.5, so the area is 2.5. Divided by the amount of cycles still gives 2.5, so the average voltage is 2.5v.
    In other words, the average voltage can be written as the duty cycle multiplied by the supply voltage. For example, a duty cycle of 25% would be 5v · 0.25 = 1.25v . 
    These average voltages are indicated in red in the images.

    Your eyes are way too slow to see the underlying square wave, so this method is perfectly fine for dimming LEDs.

    Open the example analogPotDimmer.

    Connect an LED (+ resistor) to digital pin 5, and a potentiometer to analog pin A0. Turning the potentiometer dims the LED.

    The only new function is analogWrite(pin, duty cycle). It just sets the duty cycle of the pwm on a pin. Note that the duty cycle is a value from 0 to 255, this corresponds to 0%-100%

    Another example is analogWriteDimmer. Connect a pushbutton to pin 2, and an LED to pin 5. When you press and hold the button, the LED gets brighter, when you release it, then press and hold it again, its brightness will decrease.

    https://www.arduino.cc/en/Reference/AnalogWrite

    Step 12: Driving More LEDs or Other Loads

    Up until now, we only used components that draw very little current. But if we want to drive things that draw more than 20mA, the current supplied by the Arduino's output will not be sufficient. We'll need some sort of current amplifier, and that's when the transistor comes in.
    When you want to drive things that run off a different voltage than the Arduino, you'll also need a transistor.

    A small current from the base to the emitter results in a much higher current from the collector to the emitter.
    More information can be found in step 3.

    Measuring voltage and current

    Before we can start to build our transistor circuit, we'll need to know the voltage and current draw of the load you want to use. 
    Connect your load (motor, fan, LEDs, bulb, heating element, solenoid...) to the appropriate power supply, set your multimeter to DC volts and measure the voltage across the load, or directly from the load. Voltage is measured in parallel with the load. (see image)

    Now disconnect the negative wire of the load from the power supply. Then plug the red wire of your multimeter into the amps connector, and set it to DC amps. Then connect the black wire of the multimeter to the ground of the power supply, and the red wire of the multimeter to the negative wire of the load. Current is always measured in series with the load. (see image)

    Note: remember to plug your red wire back into the voltage connector of the multimeter, if you try to measure voltage with the current input, you will basically create a short circuit, and blow the multimeter's fuse or even completely destroy it. Some higher end multimeters will beep and show a warning when it's set to voltage while the current connector is used.

    Calculating the base resistor for the transistor (linear current gain)

    A transistor has a certain current gain, typically around 100. The symbol for DC current gain is a Greek letter bèta (β) or HFE
    Icollector-emitter = Ibase-emitter · HFE.
    Find the β value for your specific transistor in the data sheet. There should be a graph called "DC current gain". (see images) On the horizontal axis, you can find the collector current, this is the current drawn by the load. Note that most of the time, a logarithmic scale is used. 
    Write down the β value corresponding to your load current.

    We need to know the base-emitter current, so divide the collector current by the current gain β.

    Ibase-emitter = Icollector-emitter / HFE

    Now take the supply voltage of your Arduino, and subtract 0.7v. This is because the base-emitter silicon junction of the transistor has a voltage drop of 700mV. (You don't have to know why this is, just know the voltage drop is there.)
    Now use Ohm's law to calculate the resistance of the base resistor.
    Rbase = (VArduino - 0.7v) / Ibase-emitter

    Note: if the base current is greater than 20mA (more than the Arduino can supply), you'll have to use a transistor with a higher β value or a Darlington transistor.

    For example, I want to drive a motor at 200mA, 12v with a BD139 NPN transistor and a 5v Arduino:

    As you can see in the second graph, at 200mA, the current gain is about 97.
    Ibase-emitter = 0.2A / 97 = 0.00206A ≈ 2.1mA

    Rbase = (5v - 0.7v) / 2.1mA = 4.3v / 0.0021A ≈ 2048Ω → 1.8kΩ

    Calculating the base resistor for the transistor (Saturation)

    In most cases you don't want to use the formula above however: this is only true in the linear region of the transistor. It called is linear because the relation between the base current and the collector current is linear. (If the base current goes up, the collector current goes up as well). This is also called the active region.

    However, there comes a time when an increase in base current will no longer cause a further increase in collector current: we say that the transistor is saturated, or in its saturation region. This means that a maximum amount of current flows from the collector to the emitter, and that the voltage drop across the collector and the emitter is at its lowest. This is what we want if we're using the transistor as a switch.

    (The lower the voltage across C-E, the lower the power dissipation in the transistor, which is a good thing. This voltage is approximately 200mV, but in practice, this varies widely depending on the transistor model, current, temperature etc.)

    The equation above no longer holds true, so we have to find a different one: as a general rule of thumb, we say that the base current required to saturate the transistor is about 5-10% of the collector current:

    IB (sat) = IC / 10

    If you know the base current and voltage, you can now use Ohm's law to calculate the required base resistor. For example:

    To drive a 200mA motor, for example, we'll need a base current of 0.200A / 10 = 0.020A. Using Ohm's law:

    (5V - 0.7V) / 0.020A = 215Ω → 220Ω

    we get a base resistance of 220Ω.


    Note: When you use an inductive load, like a solenoid, relay, motor etc. you'll have to use a flyback diode. This is to prevent the transistor from being damaged by voltage spikes caused by the solenoid. (You get self-inductanceinside of the coil when it is suddenly turned of.) (see image) You can use almost any rectifier diode, I used a regular 1N4007, for example.

    Note: the Arduino's ground should always be connected to the ground of the transistor circuit.

    Note: You can only use this method with low-voltage DC loads.

    Low-current MOSFETs

    A normal transistor (BJT, Bipolar Junction Transistor) as described above, is operated by the base-emitter current. MOSFETs (Metal Oxide Semiconductor Field Effect Transistors) are controlled by the gate voltage. (see step 3)

    In the datasheet of your MOSFET, find the gate voltage to drain current graph. (see image, graph is for a BUZ11 MOSFET)
    As you can see, at 3.3v, the current is still pretty low, and useless in most cases. However, at 5v, the drain current might be enough for your specific application.

    It is recommended to use pull-down (gate bleeder) resistor on the gate of the MOSFET to prevent an electric field from building up, and turning on the MOSFET, since it is very sensitive.

    The gate acts like a capacitor, so when turning it on and off, there's a very high current that flows into or out of it. To prevent this, a resistor is connected in series with the gate. To ensure fast switching, this gate resistor should have a relatively small resistance, 270 ohms, for example.

    Just like with normal transistors, you should also use a flyback diode when switching inductive loads.

    (see images for schematics)

    High-current MOSFETs

    To get higher currents, we have to get a higher electric field, so we need a higher gate voltage.

    We could use transistor to do this, but it is easier to use an opto-coupler, or opto-isolator. This is basically an infrared LED and a phototransistor (light sensor) in one package. When the LED is turned on, the phototransistor conducts, so the gate is now at a higher voltage. 
    It looks just like an IC with only 4 (or 6) legs.

    Using an opto-coupler also means that there is no electrical connection between the Arduino and the MOSFET, so if the higher-voltage circuit fails, it is almost impossible that it gets to the Arduino, and destroys it. This is a great advantage.

    Logic level MOSFETs

    Some MOSFETs are designed to work at high currents without needing a high gate voltage. Because they can be connected directly to an Arduino's output pin (5V), they are called logic level MOSFETs.

    It is possible to use them with 3.3V signals, but the maximum drain current will be much lower. (Since the relationship between gate voltage and drain current is far from linear, as you can see in the graphs.)

    A popular logic level MOSFET is the FQP30N06L.

    Relays

    To drive high-voltage or AC loads, you'll need a relay. See step 3 for more information.

    The Arduino can't drive a relay directly, so you'll need a (small) transistor. A relay is an inductive load, so you'll need a flyback diode to protect your transistor. 
    Use the method above to calculate the base resistor.

    Take a look at the image above for the schematic.

    Warning: Wall power can kill you, if you're not careful enough. Never leave 115V or 230V connections exposed, and unplug your circuit when you're working on it.

    Summary

    • If you want to drive things like motors or lights that draw more than 20mA or run at voltages other than 5v or 3.3v, use a transistor, MOSFET or relay.
    • Always use a resistor on the base of a transistor to control the base current.
    • Always use a pull-down resistor on the gate of a MOSFET.
    • Always use a flyback diode when switching inductive loads.

    Extra: PNP transistors

    In the previous paragraphs, we only used NPN transistors, that take a positive signal to turn on. PNP transistors on the other hand turn on when a negative voltage is applied to the base, resulting in a "negative" base-emitter current. (negative, compared to the emitter, in a PNP transistor, the emitter emits "positive charges". It is still only the electrons that move, and a positive charge just means the absence of electrons.)

    Take a look at the image above for the schematic. Just like with the NPN variant, the arrow at the emitter indicates the direction of the current.

    Note: the PNP transistor will conduct when the Arduino output pin is low.

    Step 13: Driving Motors

    DC motors

    With the techniques explained in the previous step, you can only spin the motor in one direction. To change the direction, you'll need an H-brigde (sometimes called a full bridge). It consists of 2 NPN and 2 PNP transistors, or 2 N-channel and 2 P-channel FETs.

    Take a look at the image for a typical MOSFET H-bridge circuit.

    Note: you can't just replace the MOSFETs in this schematic by transistors: Transistors need base current, FETs need gate voltage.

    Let's find out how this circuit works:

    We'll call the left input input A, and the right one input B.

    When input A is low, transistor Q1 doesn't conduct. This means that the gates of Q2 and Q3 are high (they are connected to VSS through R1). Q3 is an N-channel MOSFET, so it starts conducting (because it has a positive gate voltage). Q2 is a P-channel MOSFET, so it doesn't conduct (because it has no voltage difference between the gate and the source, both are connected to VSS). 
    The left terminal of the motor is now connected to ground, via Q3.

    When input B is high, Q4 conducts. This means that the gates of Q5 and Q6 are low. (They are connected to ground through Q4, and R2 doesn't matter in this case). Q6 is an N-channel MOSFET, so it doesn't conduct (because it has no voltage difference between the gate and the source, both are connected to ground).
    Q5 is a P-channel MOSFET, so it starts conducting (because it has a negative gate voltage, relative to the source).
    The right terminal of the motor is now connected to VSS through Q5.

    In this case, the motor will spin counter-clockwise.

    The second image is an equivalent circuit for this situation.

    You can already guess that if input A is high, and B is low, the motor will spin clockwise. If A and B are both high or both low, the motor won't spin, because both terminals are connected to either VSS or ground. (so no voltage difference)

    Although you could build this circuit yourself, it is way easier to use an IC. For example, I got some L6202 chips out of an old printer. Another H-bridge chip is L298 or L293. 
    They connect directly to 2 digital pins on the Arduino, and most of them also have an 'enable' pin, which you can use with a third pwm pin, to control the motor's speed.

    Adafruit has a really good tutorial on how to use them: https://learn.adafruit.com/adafruit-arduino-lesson...

    Stepper motors

    Another commonly used motor is the stepper motor.

    A normal DC motor has a spinning coil inside two permanent magnets. Stepper motors on the other hand, have a moving magnet (the rotor) and some stationary coils (the stator). By activating the coils in a specific sequence, the rotor will spin.

    The following videos will help you understand how it works:

    For driving a unipolarstepper, you'll just need 4 NPN transistors, or 4 N-channel MOSFETs. (see image)

    To find the pinout for your stepper, look up the datasheet, or use a multimeter, and measure the resistance between the wires. Some wire combinations will have a resistance that's 2 times higher than the others, these are the outer two wires in the schematic.

    Connect the two center wires to the positive wire of the power supply, and the outer wires to the collectors of the drive transistors (see schematic). Calculate the appropriate base resistors, as explained in the previous step, and connect them to pins 8, 9, 10, 11 of the Arduino. Don't forget to connect the ground of the power supply to the ground of your Arduino.

    For driving a bipolarstepper, you'll need 2 H-bridges. Connect the outputs of each H-bridge to one coil of the stepper. Connect the inputs of the H-bridges to pins 8, 9, 10, 11 of the Arduino. Don't forget to connect the ground of the power supply to the ground of your Arduino. Connect the enable line to VSS.

    Note: stepper motors draw a lot of current, so you cannot use the onboard power supply of the Arduino. You should also use high-power transistors or MOSFETs. Check the temperature of the transistors, and add a heat sink if necessary.

    Now open the stepper_oneRevolution example (File > Examples > Stepper) and change the number of steps per revolution to match your motor.

    At the top of the file, there is a line

    #include<Stepper.h>

    This just adds the code o the Stepper.h file to the sketch, so you can use its functions. This is called the stepper library.

    On line 24, we create an instance of the Stepper class. The instance is called 'myStepper'(this name is just arbitrary), and has 5 parameters: the number of steps in one revolution (360°), and the 4 pins that connect to the bases of the transistors.

    A class has a set of functions, to run a function for a certain instance, a period (full stop) is used: instance.function(arguments);

    myStepper.setSpeed(60);

    Remember Serial.print(... )? This works in a similar way.

    The setSpeed(rpm) funnction sets the speed, in rotations per minute (so it depends on the number of steps per revolution).

    Another function of the Stepper class is step(steps), it just turns the motor for a given number of steps. If this number is positive, it will move clockwise, if it's negative, it will move counterclockwise.

    Upload the example to the Arduino, and the motor should turn 360° clockwise, then 360° counterclockwise, and so on. If it doesn't turn, but only vibrates, try swapping 2 output pins, until it works. You can swap the physical pins to the Arduino, or just change the pin order on line 24. (e.g. 9, 8, 10, 11 instead of 8, 9, 10, 11)

    The usage of classes makes it very easy to create multiple Stepper instances. Take a look at example _2steppers_oneRevolution.

    When a stepper is not moving, it will keep one coil on to block the motor, so it doesn't move. This draws a lot of current, however, and the stepper itself and the transistors may get very hot. 
    To stop this, you can just perform a digitalWrite(pin, LOW) on the 4 pins of the stepper.

    If you use a drive IC (like an H-bridge or a darlington array), you could also connect the enable pin to your Arduino. If you set it high, the motor will be activated, and when you set it low, there will be no voltage across the motor at all.

    You could create your own little function to turn of the stepper, like I did in example Stepper_stop

    voidstepperOff(){
    digitalWrite(8,LOW);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
    }

    You can make functions that do pretty much anything, for example if you have to execute a certain series of commands multiple times in your program. A good tutorial on classes, functions and libraries is the Library Tutorial on the Arduino site: https://www.arduino.cc/en/Hacking/LibraryTutorial

    Arduino reference: Stepper library

    Step 14: Things Not (yet) Covered in This Instructable

    There is of course no way to cover everything in only one Instructable, that's why I'll put some useful links to other tutorials on subjects I didn't include in this Instructable.

    LCD displays

    Arduino tutorial: Hello World

    Arduino reference: Liquid Crystal

    Servo motors

    Arduino reference: Servo

    Arduino tutorial: knob

    Speakers and audio output

    Arduino tutorial: Tone Melody

    Google Code: Tone

    Ultrasonic sensors

    Arduino tutorial: Ping

    MIDI over USB

    Custom Arduino MIDI Controller Instructable

    The community

    Arduino has an enormous online community, so Google will almost always give you some very helpful results. If you can't find what you're looking for, you can always ask for help on the forum. Just create a free account, it's really worth it!

    Step 15: Final Thoughts

    To conclude this Instructable, I would like to stress the importance of experimenting. You'll learn so much more if you try it yourself.

    Find yourself a cool project, and go for it.

    Try new things, stay curious!

    If you liked this Instructable, I would like to ask you to consider voting for me in the Arduino all the Things! Contest.

    If you have any requests, notes, things I missed, questions... don't hesitate to use the comment section below ↓ !

    Thank you for reading,

    Tttapa, 25-01-2016

  • A Beginner's Guide to the ESP8266

    Some time ago, I wrote a Beginner's Guide to Arduino that seems to be very popular, so I decided to create a follow-up: A Beginner's Guide to the ESP8266. That's right, a tutorial on how to use the world's most popular $3 Wi-Fi board.
     
    This is going to be a very in-depth tutorial, covering some networking concepts as well. If you're a beginner, and just want to go straight to the more exciting Wi-Fi part, feel free to do so, I included short TL;DR's in the longer, more technical parts.
     
    A short overview of what I'll cover in this article: 
    1. What is an ESP8266? A short overview of what an ESP8266 is, and what you can do with it
    2. Deciding on what board to buy: There's loads of different ESP8266 available these days, finding the one that's best for you can be hard
    3. Installing the software: you need to install some software to program the ESP8266, and maybe a USB driver
    4. Setting up the hardware: some modules and boards need some external components
    5. The ESP8266 as a microcontroller: the ESP8266 can be used as a normal microcontroller, just like an Arduino
    6. Network protocols: Before we start using the Wi-Fi capabilities of the ESP8266, I'll teach you some of the network protocols involved
    7. Setting up a Wi-Fi connection: That's probably why you're reading this, right?
    8. Name resolution: Find the ESP8266 on your local network using mDNS
    9. Setting up a simple web server: This enables you to add web pages to the ESP8266, and browse them from your computer or phone
    10. Setting up an advanced web server: a more advanced server with a real file system that allows you to upload new files over Wi-Fi
    11. OTA - uploading programs over Wi-Fi: You don't have to upload programs over USB, you can use Wi-Fi instead
    12. Wirelessly controlling your RGB lighting: Change the color of your LED strips using your phone or computer
    13. Getting the time: Connect to a time server using NTP and sync the ESP's clock
    14. Monitoring sensors: log the temperature in your living room, save it in flash memory and show it in a fancy graph in your browser
    15. Getting email notifications: Turn on a notification light when you've got unread emails
    16. Advanced features: use DNS, captive portals, Wi-Fi connector libraries, OSC...
     
    This guide expects some basic knowledge of microcontrollers like the Arduino. If that's something you're not already familiar with, I'd recommend you to read my Beginner's Guide to Arduino first, it covers a lot of the basics that I won't go into in this article.
    I really want to focus on the ESP8266-specific things, like Wi-Fi and other network protocols, the ESP's hardware, software, IoT, etc...

    What is an ESP8266?

    The ESP8266 is a System on a Chip (SoC), manufactured by the Chinese company Espressif. It consists of a Tensilica L106 32-bit micro controller unit (MCU) and a Wi-Fi transceiver. It has 11 GPIO pins* (General Purpose Input/Output pins), and an analog input as well. This means that you can program it like any normal Arduino or other microcontroller. And on top of that, you get Wi-Fi communication, so you can use it to connect to your Wi-Fi network, connect to the Internet, host a web server with real web pages, let your smartphone connect to it, etc... The possibilities are endless! It's no wonder that this chip has become the most popular IOT device available. 
     
    There are many different modules available, standalone modules like the ESP-## series by AI Thinker, or complete development boards like the NodeMCU DevKit or the WeMos D1. Different boards may have different pins broken out, have different Wi-Fi antennas, or a different amount of flash memory on board.
     
    (*) The ESP8266 chip itself has 17 GPIO pins, but 6 of these pins (6-11) are used for communication with the on-board flash memory chip.

    Programming

    There are different ways to program the ESP8266, but I'll only cover the method using the Arduino IDE. This is really easy for beginners, and it's a very familiar environment if you've used Arduino boards before. 
    Just keep in mind that it's not limited to this option: there's also an official SDK available to program it in real C, this is very useful if you want to optimize your code or do some advanced tricks that aren't supported by the Arduino IDE. Another possibility is to flash it with a LUAinterpreter, so you can upload and run LUA scripts. Or maybe you're more familiar with Python? Then you should check out the MicroPython firmware to interpret MicroPython scripts. I'm sure there's other languages available as well, so just do a quick Google search and write your code in the language of your choice.

    Requirements

    You'll need a couple of things in order to follow this guide:
    • An ESP8266 board
    • A computer that can run the Arduino IDE (Windows, Mac or Linux)
    • A USB-to-Serial converter, it is very important that you use a 3.3V model*
    • A USB cable
    • A 3.3V power supply or voltage regulator*
    • A Wi-Fi network to connect to
    (*) Your board may already include these. More information can be found in the next chapter.
  • ABC - Arduino Basic Connections

  • Adding a PCF 8591 ADC/DAC to ESP8266-01

    The ESP8266-01 is a great WiFi enabled  microcontroller but it only has 4 I/O pins broken out. Fortunately it does support I2C protocol so in spite of  the low number of pins, there still is a lot of hardware that can be added.
    As the ESP8266-01 has no analog inputs at all, adding an ADC to it is something I wanted to do. After all,  sensors as LDR or NTC are still analog.
    The PCF8591 is such an ADC: it is  a single-chip, single‑supply low‑power 8‑bit CMOS data acquisition device with four analog inputs, one analog output and a serial I²C‑bus interface. Three address pins A0, A1 and A2 are used for programming the hardware address, allowing the use of up to eight devices connected to the I²C‑bus without additional hardware. I doubt whether I need more than 8 of those chips. Lets just start with one. Although one can get the individual chip, I have chosen for a module that actually already has some sensors on it:

    • AIN0 – Jumper P5 – Light Dependent Resistor (LDR)
    • AIN1 – Jumper P4 – Thermistor
    • AIN2 – Not connected
    • AIN3 – Jumper P6 – Potentiometer
    pcf8591-circhttps://arduinodiy.files.wordpress.com/2016/10/pcf8591-circ1.jpg?w=150 150w, https://arduinodiy.files.wordpress.com/2016/10/pcf8591-circ1.jpg?w=300 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; vertical-align: middle; display: block; margin: 0px;">
    YL-40 circuit

    The I2C address of the PCF8591 is determined by the pins A0-A2. As they are close to the Ground pin, let’s start with grounding them (as they are on the module).
    pcf8591adreshttps://arduinodiy.files.wordpress.com/2016/10/pcf8591adres.png?w=150 150w, https://arduinodiy.files.wordpress.com/2016/10/pcf8591adres.png?w=300 300w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; vertical-align: middle; float: right; margin: 0.375em 0px 1.75em 1.75em; display: block;">The address is 1001A2A1A0. With A2-A0 being LOW, that is 1001000=0x48.

    base A2A1A0 Hex Dec
    1001 000 48 72
    1001 001 49 73
    1001 010 4A 74
    1001 011 4B 75
    1001 100 4C 76
    1001 101 4D 77
    1001 110 4E 78
    1001 111 4F 79

    In some programs you will see the address as “0x90>>1” Which is 48 as well. The “0x90” counts the LSB of the 8 bit address, which is the R/W bit. With the Write Bit Low (=active) the full address is 10010000=0x90, but the rightshift 1 removes the LSB again, making it 0x48.
    The module is hardwired to 0x48 as the three address lines are soldered to ground. So if you would want to use more than one module on the same I2C port you would need to do some de-soldering (or use   bare PCF8591 chips ofcourse).

    https://arduinodiy.files.wordpress.com/2016/10/pcf8591.jpg?w=150&h=136 150w, https://arduinodiy.files.wordpress.com/2016/10/pcf8591.jpg?w=300&h=271 300w, https://arduinodiy.files.wordpress.com/2016/10/pcf8591.jpg?w=768&h=694 768w, https://arduinodiy.files.wordpress.com/2016/10/pcf8591.jpg 912w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; vertical-align: middle; display: block; margin: 0px;">
    Sunfounder board (expensive)

    A similar but needlessly more expensive, non configurable board without the sensors is the sunfounder board.

    https://arduinodiy.files.wordpress.com/2016/10/pcf8591-ad-da-board-pcf8591-module-8-bit-a-d-d-a-converter-with-i2c-connector_640x640.jpg?w=150 150w, https://arduinodiy.files.wordpress.com/2016/10/pcf8591-ad-da-board-pcf8591-module-8-bit-a-d-d-a-converter-with-i2c-connector_640x640.jpg?w=300 300w" sizes="(max-width: 597px) 85vw, 597px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; vertical-align: middle; display: block; margin: 0px;">
    Mini PCF8591 AD DA Shell Module

    There is a (more expensive)  fully configurable module, that allows to set the  I2C address with jumpers. That module is daisy chainable with other I2C modules in the same range (there is for example a PCF8547 digital I/O module with similar connections). Making a module yrself is not hard either:

    PCF8591https://arduinodiy.files.wordpress.com/2017/10/img_20171011_190303.jpg?w=1604&h=2048 1604w, https://arduinodiy.files.wordpress.com/2017/10/img_20171011_190303.jpg?w=117&h=150 117w, https://arduinodiy.files.wordpress.com/2017/10/img_20171011_190303.jpg?w=235&h=300 235w, https://arduinodiy.files.wordpress.com/2017/10/img_20171011_190303.jpg?w=768&h=981 768w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; vertical-align: middle; display: block; margin: 0px;">
    PCF8591 configured as 0x48

    The control byte sets the operating mode of the PCF8591 and is described in section 7.2 of the datasheet, The upper nibble of the control register is used for enabling the analog output, and for programming the analog inputs as single-ended or differential inputs.
    The lower nibble selects one of the analog input channels defined by the upper nibble. If the auto-increment flag is set the channel number is incremented automatically after each A/D conversion.
    If the auto-increment mode is desired in applications where the internal oscillator is used, the analog output enable flag in the control byte (bit 6) should be set. This allows the internal oscillator to run continuously, thereby preventing conversion errors resulting from oscillator start-up delay. The analog output enable flag may be reset at other times to reduce quiescent power consumption.

    As it is not my intention to explain the full innerworkings of the PCF8591, but just to show it is working with the ESP8266-01, I will skip a full technical discussion. For now it is enough to know that the PCF8591 can be read byte for byte, but it can also be read in ‘burst mode’, in which we read the 4 analog values all at once. The program I present is burstmode with autoincrement of the address. The reason we read 5 bytes instead of 4 is because the first byte contains old data. As the datasheet states in paragraph 8.4: “The first byte transmitted in a read cycle contains the conversion result code of the previous read cycle.”

    #include "Wire.h"
    int PCF8591=0x48; // I2C bus address
    byte ana0, ana1, ana2, ana3;
    void setup()
    {
     Wire.pins(0,2);// just to make sure
     Wire.begin(0,2);// the SDA and SCL
    }
    void loop()
    {
     Wire.beginTransmission(PCF8591); // wake up PCF8591
     Wire.write(0x04); // control byte: reads ADC0 then auto-increment
     Wire.endTransmission(); // end tranmission
     Wire.requestFrom(PCF8591, 5);
     ana0=Wire.read();// throw this one away
     ana0=Wire.read();
     ana1=Wire.read();
     ana2=Wire.read();
     ana3=Wire.read();
    }
    

    Obviously when you have these values read you will need to do something with them: print them out, put them on yr own webpage or upload them to e.g. Thingspeak. As printing from the ESP8266-01  is not always easy, I will show you how to upload the values to Thingspeak:

    #include  // ESP8266WiFi.h library
    #include "Wire.h"
    int PCF8591=0x48; // I2C bus address
    byte ana0, ana1, ana2, ana3;
    
    const char* ssid     = "YourNetworkSSID";
    const char* password = "YourPassword";
    const char* host = "api.thingspeak.com";
    const char* writeAPIKey = "YourWriteAPI";
    
    void setup() {
      // Initialize sensor
     Wire.pins(0,2);// just to make sure
     Wire.begin(0,2);// the SDA and SCL
    
    //  Connect to WiFi network
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
      }
    }
    
    void loop() {
     Wire.beginTransmission(PCF8591); // wake up PCF8591
     Wire.write(0x04); // control byte: reads ADC0 then auto-increment
     Wire.endTransmission(); // end tranmission
     Wire.requestFrom(PCF8591, 5);
     ana0=Wire.read();
     ana0=Wire.read();
     ana1=Wire.read();
     ana2=Wire.read();
     ana3=Wire.read();
    
    // make TCP connections
      WiFiClient client;
      const int httpPort = 80;
      if (!client.connect(host, httpPort)) {
        return;
      }
    
      String url = "/update?key=";
      url+=writeAPIKey;
      url+="&field1=";
      url+=String(ana0);
      url+="&field2=";
      url+=String(ana1);
      url+="&field3=";
      url+=String(ana2);
      url+="&field3=";
      url+=String(ana3);
      url+="\r\n";
      
      // Request to the server
      client.print(String("GET url + " HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" + 
                   "Connection: close\r\n\r\n");
        delay(1000);
    }
    

    DAC
    The PCF8591 does not only have  4 ADC channels but also 1 DAC channel. Writing to the DAC is as follows:

    #define PCF8591 (0x48) // I2C bus address
    void setup()
    {
     Wire.pins(0,2);// just to make sure
     Wire.begin(0,2);
    }
    void loop()
    {
     for (int i=0; i<255; ++i)
     {
     Wire.beginTransmission(PCF8591); // wake up PCF8591
     Wire.write(0x40); // turn on DAC b1000000
     Wire.write(i); 
     Wire.endTransmission();
     }
    }
    

    Calculations
    A the board normally uses the 3.3v supply as the reference voltage:
    The input voltage is determined with:
    vIn = value * (3.3 / 255)
    and the output voltage is:
    vOut = (value / 255) * 3.3
    or to find the value for a given voltage:
    value = (vOut / 3.3) * 255

    So if for instance I would write  the value of 50 to the DAC. The voltage would be: 0.64V
    In order to test that, I hooked up Aout to the A0 of an ESP 8266-12 and found a value of 192.
    To calculate that to a voltage that is  (192/1023)=0.18V.  (Remember, the ESP gives readings from 0-1023, whereas 1023 being 1 Volt.)  So that is not particularly close.
    Oddly though when I hooked up the Aout to AIN2 or AIN1 that didn seem to give reliable readings. A value of 50 written to Aout should give a value of 50 on AIN, but oddly it didnt

    In my version of the board the NTC channel only varied between 255 and 254, changing the temperatuur didnt seem to have any influence, but removing jumper P4 made the value go all over the place so i presume the channel is ok, and only the NTC might not be OK.

    Differential Input
    The PCF8591 is capable of more, it is  for instance possible to do differential measurements.
    Suppose you want to  measure the difference between AIN0 and AIN1.
    You do that as follows:

    #include "Wire.h"
    int PCF8591=0x48; // I2C bus address 
    int Raw = 0;
    float Voltage = 0.0;
    
    void setup()
    {
     Wire.pins(0,2);// just to make sure
     Wire.begin(0,2);
      Serial.begin(9600); //Not on an ESP8266-01 
      Wire.beginTransmission(PCF8591); // Wake up PCF8591
      Wire.write(0x11); // control Byte for differential input mode 
      Wire.endTransmission(); //
    }
    void loop()
    {
      Wire.requestFrom(PCF8591, 1); // Get Data from channel 1
    
     RawValue=Wire.read();
     Voltage = (Raw * 3.3 )/ 255.0;
     Serial.print("Raw= ");
     Serial.print(Raw);
     Serial.print(" Voltage = ");
     Serial.println(Voltage,3);
     delay(1000);
    }
    

    If you want to hook up this chip to a Raspbery Pi, have a look here.
    There are other ways of expanding the ADC capabilities of the ESP8266:

  • Arduino

  • ARDUINO BASIC PC WITH VGA OUTPUT

    Step 1: Build the Arduino Master With TinyBasic and PS2 Keyboard

    TinyBasic Plus and the VGAx library work for Arduino IDE 1.6.4.

    First download it from the Arduino official web page. If you have a newer versions on your PC, the best is to download it in .zip format and uncompress them on your PC. Click this link to download the Windows version.

    You need then the PS2keyboard library. You can find it at the bottom of this page. Just uncompress it and copy the PS2keyboard folder in: arduino-1.6.4\libraries

    Finally, in this page, download the file: TinyBasicPlus_PS2_VGAx.ino, uncompress and upload it on your Arduino.

    This is a variation of the standard TinyBasic Plus where i have added the PS2 library and modified the code to accept the variables from it.

    More details on TiniBasic Plus and tutorials can be found at this link.

    If there are no problems, and compatibility issues, Tiny Basic is already running. You can test it trough a serial monitor in your PC. For this purpose I use PuTTY, but many other programs are available.

    You have to set the correct COM port (it is the same you find in the Arduino IDE) and baud rate = 4800

    Here you can already test some program in Basic just by typing them with your PC keyboard (NB later on I will show how to connect the PS2 keyboard directly to the Arduino).

    Try for instance:

    10 PRINT "Hello, World!"

    20 GOTO 10

    RUN

    You can then stop the infinite loop just by typing ctrl+c.

    Note that this combination will not work for the PS2 keyboard.

    In the next step I will show how to connect the PS2 keyboard to Arduino.

     

    Step 2: Connect the PS2 Keyboard to the Master Arduino

    Picture of Connect the PS2 Keyboard to the Master Arduino

    I got all the informations and library from this Instructable.

    Essentially you need to connect the folowing four pins:

    • keyboard Data to Arduino pin 8,
    • keyboard IRQ (clock) to Arduino pin 3;
    • you need to connenct GND and +5V as well.

    I got an old PS2 female connector from a broken PC motherboard. You can simply unsold it with a heat gun.

    In the picture shown in this step, you can find the function of the needed pins of the PS2 connector.

    Step 3: Upload the VGAx Library and Code on the Second Arduino and Put Everything Together

    Picture of Upload the VGAx Library and Code on the Second Arduino and Put Everything Together

    First download VGAx-PC.ino code at the bottom of this page and copy it on your PC in a directory with the same name.

    Download the VGAx library from this link on GitHub. The easiest way is to copy it in the Arduino software subfolder named "libraries", to be immediately recognized.

    IMPORTANT: this library works for Arduno IDE 1.6.4 but it is not fully compatible with elder or newer versions.

    Upload the VGAx-PC.ino in your second Arduino board (I tested it for the Nano version but the Uno should work as well).

    A warning for low available memory is normal. If you do not have other errors everything is ok and you can immediately start to build your own 8-bit PC.

    For this you need:

    • two Arduino Uno Rev. 3 or two Arduino Nano 3.x (ATmega328)
    • a DSUB15 Connector, i.e. a VGA female connector or a VGA cable to be cut.
    • resistors: 2 x 68 Ohm and 2 x 470 Ohm
    • a PS2 female connector
    • wires
    • facultative: a breadboard or a strip board

    The schematic is reported at the top of this step. An example of a finished “console” is shown in the introductive step.

  • Arduino Boards Pin mapping

    Often I found myself, searching for pin mapping of arduino board pins to actual micro-controller pins, like Arduino uno digital pin 0 is PD0 in atmgea328. So I thought of putting all information at one place. I have added summary of each board also.

    Arduino Uno Pin mapping :

    Arduino uno Pin mappinghttp://icircuit.net/wp-content/uploads/2014/09/Arduino-uno-300x168.png 300w" sizes="(max-width: 892px) 100vw, 892px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino uno Pin mapping

    Arduino Due Pin mapping:

    Arduino Due Pin mappinghttp://icircuit.net/wp-content/uploads/2014/09/Arduino-Due-Pin-mapping-300x269.png 300w" sizes="(max-width: 1024px) 100vw, 1024px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino Due Pin mapping

    http://www.robgray.com/temp/Due-pinout-A4.png', 'Source']);" title="Due pin out" target="_blank" style="box-sizing: inherit; background-color: transparent; text-decoration: none; color: rgb(56, 183, 238); transition: background-color 0s ease 0s, color 0.2s linear 0s; font-size: large; font-family: sans-serif;">Source:robgray.com

    Arduino Due summaryhttp://icircuit.net/wp-content/uploads/2014/09/Arduino-Due-summary-300x119.png 300w" sizes="(max-width: 632px) 100vw, 632px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino Due summary

     Arduino Leonardo Pin mapping:

    Arduino Leonardo pin mappinghttp://icircuit.net/wp-content/uploads/2014/09/Arduino-Leonardo-300x158.png 300w, http://icircuit.net/wp-content/uploads/2014/09/Arduino-Leonardo.png 1106w" sizes="(max-width: 1024px) 100vw, 1024px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino Leonardo pin mapping

    Arduino Mega 2560 / Mega ADK:

    Arduino Mega 2560 Pin mappinghttp://icircuit.net/wp-content/uploads/2014/09/megapdf-212x300.jpg 212w, http://icircuit.net/wp-content/uploads/2014/09/megapdf-724x1024.jpg 724w" sizes="(max-width: 1240px) 100vw, 1240px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino Mega 2560 Pin mapping

    http://forum.arduino.cc/index.php?PHPSESSID=b0e2fe8d5f09a2f88f1bd7009cdc71d5&/topic,146511.0.html', 'Source']);" title="Arduino Mega 2560 pin mapping" target="_blank" style="box-sizing: inherit; background-color: transparent; text-decoration: none; color: rgb(56, 183, 238); transition: background-color 0s ease 0s, color 0.2s linear 0s; font-size: large; font-family: sans-serif;">Source:forum.arduino.cc

    Arduino Mega 2560 summaryhttp://icircuit.net/wp-content/uploads/2014/09/Arduino-Mega-2560-summary-300x116.png 300w" sizes="(max-width: 866px) 100vw, 866px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino Mega 2560 summary

    Arduino Micro Pin mapping :

    Arduino Micro pin mappinghttp://icircuit.net/wp-content/uploads/2014/09/Arduino-Micro-pin-mapping-300x167.png 300w" sizes="(max-width: 956px) 100vw, 956px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino Micro pin mapping

    Arduino mini Pin mapping:

    Arduino Mini pin mappinghttp://icircuit.net/wp-content/uploads/2014/09/Arduino-Mini-300x155.png 300w" sizes="(max-width: 938px) 100vw, 938px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino Mini pin mapping

    Arduino nano pin mapping:

    Arduino nano pin mappinghttp://icircuit.net/wp-content/uploads/2014/09/Arduino-nano-pin-mapping-300x173.png 300w, http://icircuit.net/wp-content/uploads/2014/09/Arduino-nano-pin-mapping-1024x592.png 1024w" sizes="(max-width: 1699px) 100vw, 1699px" style="box-sizing: inherit; border: 0px; height: auto; max-width: 100%; display: block; margin-left: auto; margin-right: auto;">
    Arduino nano pin mapping
  • Arduino Multi Function Shield

    Arduino Multi Function Shield for Arduino-Uno R3


     

     

  • Arduino R3 Multifunctional Expansion Board Shield

    Multi-function Shield

     
     
    The Multi-function Shield (HCARDU0085) designed for Arduino Uno / Leonardo board has a large range of features which makes it ideal for experiments, learning and advanced projects development.
     
    Besides the feature rich range of components fitted to the shield, there are also a range of expansion headers for convenient interfacing of external modules and components. The shield includes R3 type headers for easy connection to Arduino boards.

    Note:
    This shield includes a header for attaching an IR reciver (U4-IR-2). The pinout order is not suitable for directly connecting a SFH506-38. However the order is compatible with 1838B Infrared IR receiver (HCSENS0014).
    Please always check the schematic before connecting external components.
     
    Features
    • An LED display module (four-digit, seven-segment)
    • Two serial LED display driver ICs(74HC595)
    • Four LEDs
    • A multi-turn trimpot (10KOhm)
    • Three pushbuttons
    • A piezo-buzzer
    • A port for DS18B20 temperature sensor
    • A port for TSOP1838 infrared receiver module
    • A APC220 wireless module interface (serial/UART interface)
    • A reset button
     

    Pin Layout
    • Serial LED display driver (74HC595) - Latch 4, Clock 7, Data 8
    • Four LEDs - Pin 10,11,12,13
    • Trimpot (10KOhm)-Pin A0
    • Three pushbuttons - Pin A1,A2,A3
    • Piezo-buzzer - Pin 3 (digital on/off)
    • DS18B20/LM35 temperature sensor - Pin A4
    • Infrared receiver module (remote control) - Pin 2
    • Header for APC220 shield - Gnd, 5V , 0, 1 (rx/tx)
    • Reset pushbutton - Gnd
    • Free pins header (PWM) - 5, 6, 9, A5

    Circuit diagram
     
     
    Looking at the schematic, it looks like using the DS18B20 temperature sensor (and the infrared receiver module) requires a bit of research. As indicated in the top silkscreen layout, the flat (labeled) side of the temperature sensor must face the bottom side of the Multi-function shield fronting the three pushbuttons. Also, the legend “U5-18b20-LM35-A4” has an arrow pointing up toward the middle pin (A4) of the temperature sensor header (GND on the left, DQ in the middle, and 5 V on the right). The jumper J1 feeds 5 V to the middle pin DQ through a 10K resistor (pull-up configuration). Similarly, pin notation for the infrared receiver module is OUT (D2) - GND - 5V.

    Some Pictures:

      
  • Compare Arduino board specs

    This table shows a quick comparison between the characteristics of all the Arduino and Genuino boards.

    Arduino Retired boards specs

  • ESP8266 Advanced

    DNS Captive Portal

    When using the ESP8266 in access point mode, you probably want to redirect users to the right page. You can do this by creating a captive portal, using DNS. It's basically just a DNS server that will convert all host names to the ESP's own IP address. 
    This technique is also used by open Wi-Fi networks that redirect you to a login page before you can start browsing the internet.

    Wi-Fi configuration

    If you want to be able to change the Wi-Fi connection settings without re-uploading the code, you could take a look at the WiFiManager library by tzapu. This will try to connect to known networks, but if it fails, it will start a Wi-Fi access point. You can then connect to this access point, open the browser, and pick a network to connect to. The new configuration is saved.
    The WiFiManager library uses a captive portal to present you with the right Wi-Fi settings page.
    You could also implement a Wi-Fi manager yourself, or you can just check out the example that comes with the ESP8266 Arduino Core (Examples > DNSServer > CaptivePortalAdvanced).

    I²S

    The ESP8266 has an I²S bus on the RXD pin. It can run at 80MHz, and has DMA (direct memory access), so it's really fast. Its main purpose is to connect an I²S DAC (Digital to Analog Converter) to have an audio output, but you can use it for other things as well. 
    For example, CNLohr managed to transmit analog television, by connecting an antenna wire to the I²S pin. You can also use it to control WS2812Bs LEDs. You can even use it to communicate over Ethernet (not really useful, and definitely not recommended, but it works).
    Another great use for the I²S bus is outputting data to shift registers. This gives you extra outputs that are reasonably fast, for things like LEDs or stepper motors.

    Other examples

    You can find lots of other examples in the Arduino IDE, I'd recommend to check those out as well.

    YouTube

    There's some great channels on YouTube that do amazing things with the ESP8266. Here's a short list of the ones I'm currently following. If you've got more recommendation, just leave a comment!
  • ESP8266 Data logging

    A common use for IoT devices like the ESP8266 is monitoring sensors. Using the code in the previous example, we can request the time, and save some sensor values to a file. If we run a server as well, we can show this data in a pretty graph in a webpage.

    Temperature logger

    In the following example, we'll use a DS18S20 temperature sensor to log the temperature over time and save it to the SPIFFS. It can then be displayed in a graph in the browser.

    Installing libraries

    First, download the Dallas Temperature library by Miles Burton and the OneWire library by Jim Studt: Go to Sketch > Include Library... > Manage Libraries and search for 'Dallas Temperature' and 'OneWire' (make sure you download the correct version).

    Hardware

    Connect the ground of the DS18S20 temperature sensor (pin 1) to the ground of the ESP, connect the data pin (pin 2) to GPIO5, and VCC (pin 3) to the 3.3V of the ESP. Finally, connect a 4k7Ω resistor between the data pin and VCC.

    Libraries, constants and globals

    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <ESP8266WiFi.h>
    #include <ESP8266WiFiMulti.h>
    #include <WiFiUdp.h>
    #include <ArduinoOTA.h>
    #include <ESP8266WebServer.h>
    #include <ESP8266mDNS.h>
    #include <FS.h>
    
    #define ONE_HOUR 3600000UL
    
    #define TEMP_SENSOR_PIN 5
    
    OneWire oneWire(TEMP_SENSOR_PIN);        // Set up a OneWire instance to communicate with OneWire devices
    
    DallasTemperature tempSensors(&oneWire); // Create an instance of the temperature sensor class
    
    ESP8266WebServer server = ESP8266WebServer(80);       // create a web server on port 80
    
    File fsUploadFile;                                    // a File variable to temporarily store the received file
    
    ESP8266WiFiMulti wifiMulti;    // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    const char *OTAName = "ESP8266";         // A name and a password for the OTA service
    const char *OTAPassword = "esp8266";
    
    const char* mdnsName = "esp8266";        // Domain name for the mDNS responder
    
    WiFiUDP UDP;                   // Create an instance of the WiFiUDP class to send and receive UDP messages
    
    IPAddress timeServerIP;        // The time.nist.gov NTP server's IP address
    const char* ntpServerName = "time.nist.gov";
    
    const int NTP_PACKET_SIZE = 48;          // NTP time stamp is in the first 48 bytes of the message
    
    byte packetBuffer[ NTP_PACKET_SIZE];     // A buffer to hold incoming and outgoing packets
    The only new things here are the OneWire and DallasTemperature libraries, to get the temperature from the sensor.

    Setup

    void setup() {
      Serial.begin(115200);        // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println("\r\n");
    
      tempSensors.setWaitForConversion(false); // Don't block the program while the temperature sensor is reading
      tempSensors.begin();                     // Start the temperature sensor
    
      if (tempSensors.getDeviceCount() == 0) {
        Serial.printf("No DS18x20 temperature sensor found on pin %d. Rebooting.\r\n", TEMP_SENSOR_PIN);
        Serial.flush();
        ESP.reset();
      }
    
      startWiFi();                 // Start a Wi-Fi access point, and try to connect to some given access points. Then wait for either an AP or STA connection
    
      startOTA();                  // Start the OTA service
    
      startSPIFFS();               // Start the SPIFFS and list all contents
    
      startMDNS();                 // Start the mDNS responder
    
      startServer();               // Start a HTTP server with a file read handler and an upload handler
    
      startUDP();                  // Start listening for UDP messages to port 123
    
      WiFi.hostByName(ntpServerName, timeServerIP); // Get the IP address of the NTP server
      Serial.print("Time server IP:\t");
      Serial.println(timeServerIP);
    
      sendNTPpacket(timeServerIP);
    }
    In the setup, there's not much new either, we just start the temperature sensor, and check if we can communicate with it. If no temperature sensor is found, the ESP resets. 

    Getting the temperature from the sensor may take some time (up to 750ms). We don't want our loop to take longer than a couple of milliseconds, so we can't wait 750ms. If we did, the HTTP server etc. would start to misbehave. 
    The solution is to request the temperature first. The sensor will then start reading the analog temperature, and stores it in its memory. In the meantime, the loop just keeps on running, the server refreshes etc. After 750ms, we contact the sensor again, and read the temperature from its memory.
    To tell the library that we don't want to wait for the analog to digital conversion of the sensor, we use setWaitForConversion.

    Loop

    const unsigned long intervalNTP = ONE_HOUR; // Update the time every hour
    unsigned long prevNTP = 0;
    unsigned long lastNTPResponse = millis();
    
    const unsigned long intervalTemp = 60000;   // Do a temperature measurement every minute
    unsigned long prevTemp = 0;
    bool tmpRequested = false;
    const unsigned long DS_delay = 750;         // Reading the temperature from the DS18x20 can take up to 750ms
    
    uint32_t timeUNIX = 0;                      // The most recent timestamp received from the time server
    
    void loop() {
      unsigned long currentMillis = millis();
    
      if (currentMillis - prevNTP > intervalNTP) { // Request the time from the time server every hour
        prevNTP = currentMillis;
        sendNTPpacket(timeServerIP);
      }
    
      uint32_t time = getTime();                   // Check if the time server has responded, if so, get the UNIX time
      if (time) {
        timeUNIX = time;
        Serial.print("NTP response:\t");
        Serial.println(timeUNIX);
        lastNTPResponse = millis();
      } else if ((millis() - lastNTPResponse) > 24UL * ONE_HOUR) {
        Serial.println("More than 24 hours since last NTP response. Rebooting.");
        Serial.flush();
        ESP.reset();
      }
    
      if (timeUNIX != 0) {
        if (currentMillis - prevTemp > intervalTemp) {  // Every minute, request the temperature
          tempSensors.requestTemperatures(); // Request the temperature from the sensor (it takes some time to read it)
          tmpRequested = true;
          prevTemp = currentMillis;
          Serial.println("Temperature requested");
        }
        if (currentMillis - prevTemp > DS_delay && tmpRequested) { // 750 ms after requesting the temperature
          uint32_t actualTime = timeUNIX + (currentMillis - lastNTPResponse) / 1000;
          // The actual time is the last NTP time plus the time that has elapsed since the last NTP response
          tmpRequested = false;
          float temp = tempSensors.getTempCByIndex(0); // Get the temperature from the sensor
          temp = round(temp * 100.0) / 100.0; // round temperature to 2 digits
    
          Serial.printf("Appending temperature to file: %lu,", actualTime);
          Serial.println(temp);
          File tempLog = SPIFFS.open("/temp.csv", "a"); // Write the time and the temperature to the csv file
          tempLog.print(actualTime);
          tempLog.print(',');
          tempLog.println(temp);
          tempLog.close();
        }
      } else {                                    // If we didn't receive an NTP response yet, send another request
        sendNTPpacket(timeServerIP);
        delay(500);
      }
    
      server.handleClient();                      // run the server
      ArduinoOTA.handle();                        // listen for OTA events
    }
    The loop looks a lot more complex, but it's actually pretty simple. It's all based on Blink Without Delay. 
    There's two things going on:
    1. Every hour, the ESP requests the time from an NTP server. Then it constantly checks for a response, and updates the time if it gets an NTP response. If it hasn't received any responses for over 24 hours, there's something wrong, and the ESP resets itself.
    2. Every minute, the ESP requests the temperature from the DS18x20 sensor, and sets the 'tmpRequested' flag. The sensor will start the analog to digital conversion.
      750ms after the request, when the conversion should be finished, the ESP reads the temperature from the sensor, and resets the flag (otherwise, it would keep on reading the same temperature over and over again). Then it writes the time and the temperature to a file in SPIFFS.
      By saving it as a CSV file in the filesystem, we can easily download it to the client (using the web server that is running), and it's easy to parse with JavaScript.
    If we miss the first NTP response, timeUNIX will be zero. If that's the case, we send another NTP request (otherwise, the next request would be an hour later, and the temperature logging only starts when the time is known).
     
    We also need to run the server and OTA functions to handle HTTP and OTA requests.

    Setup functions, server handlers and helper functions

    These functions haven't change since the previous example, so there's no need to cover them here. You do need them to get the program running, though. Download the ZIP archive with examples for the full sketch.

    HTML and JavaScript

    There's some HTML and JavaScript files to plot the temperature using Google Graphs. I won't cover it here, but if you wan't to know how it works, you can find the files in the ZIP archive.

    Using the example

    Set the SPIFFS size to 64KB or larger if you plan to use it for prolonged periods of time. (You could also increase the logging interval on line 80 to save space.)
    Enter your Wi-Fi credentials on lines 138-140, and hit upload. Then upload the webpages and scripts to SPIFFS using Tools > ESP8266 Sketch Data Upload.
    Make sure you have the temperature sensor connected, as described at the top of this page. Open a terminal to see if it works. You should see something like this:
    Connecting
    ..........
    
    Connected to SSID
    IP address:	192.168.1.2
    
    OTA ready
    
    SPIFFS started. Contents:
    	FS File: /favicon-144x144.png, size: 2.81KB
    	FS File: /temperatureGraph.js.gz, size: 1.17KB
    	FS File: /temp.csv, size: 42.50KB
    	FS File: /success.html.gz, size: 456B
    	FS File: /edit.html.gz, size: 700B
    	FS File: /main.css.gz, size: 349B
    	FS File: /index.html.gz, size: 795B
    	FS File: /manifest.json, size: 169B
    	FS File: /favicon.ico.gz, size: 1.91KB
    
    mDNS responder started: http://esp8266.local
    HTTP server started.
    Starting UDP
    Local port:	123
    Time server IP:	216.229.0.179
    Sending NTP request
    NTP response:	1488666586
    Temperature requested
    Appending temperature to file: 1488666627,20.00
    Temperature requested
    Appending temperature to file: 1488666687,19.94
    Temperature requested
    ...
    Let it run for a couple of minutes, to gather some temperature data. Then open a web browser, and go to http://esp8266.local/.
    You should get a graph showing the temperature curve. You can use the arrow buttons to travel through time, and the + and - buttons to zoom in or out. The reset button resets the zoom, and jumps back to the present. Refresh requests the latest temperature data.
     
    If you want, you can still go to http://esp8266.local/edit.html to upload new files.
     
    The web interface should look like this:

    ESP8266_Temperature_Logger.png

    It works on Windows, Linux and Android, but iOS seems to have some problems rendering the graph (in both Chrome and Safari).
  • ESP8266 Email notifier

    Another great use for IoT devices is displaying things like traffic information, weather forecast, social media updates... This requires us to send an HTTP GET request to the server of the service we'd like to access. Most popular services have API (Application Programming Interface) documents that explain that explain how you can retrieve certain information, and what format that information is in. In the following example, we'll look at Gmail specifically, but the code should be similar for other services.

    Showing the number of unread emails

    To communicate with Google's Gmail servers, we have to establish a secure connection to the server and send a secure HTTPS request with our email address and password. Gmail will then respond with an XML document containing all kinds of information, like (parts of) your most recent messages and the number of unread emails.
     
    To make sure we don't send our Google password to a malicious server, we have to check the server's identity, using the SHA-1 fingerprint of the SSL certificate. This is a unique sequence of hexadecimal characters that identifies the server.

    Allowing access to the email feed

    The only way (I know of) to get email information from Google on the ESP currently is the Google Atom Feed. This is an older method, so you have to change your Gmail settings to allow access to the feed.
    Go to https://www.google.com/settings/security/lesssecureapps to enable access for "less secure apps":blocked sign-in attempt-2.pngless secure apps-2.png
     
    Until there's support for the new OAuth2 protocol on the ESP, we'll have to use the old, less secure method.

    Hardware

    Connect an LED (+ resistor) to pin 13, as an unread email indicator.

    The Code

    #include <WiFiClientSecure.h>   // Include the HTTPS library
    #include <ESP8266WiFi.h>        // Include the Wi-Fi library
    #include <ESP8266WiFiMulti.h>   // Include the Wi-Fi-Multi library
    
    ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    const char* host = "mail.google.com"; // the Gmail server
    const char* url = "/mail/feed/atom";  // the Gmail feed url
    const int httpsPort = 443;            // the port to connect to the email server
    
                                          // The SHA-1 fingerprint of the SSL certificate for the Gmail server (see below)
    const char* fingerprint = "D3 90 FC 82 07 E6 0D C2 CE F9 9D 79 7F EC F6 E6 3E CB 8B B3";
    
                                          // The Base64 encoded version of your Gmail login credentials (see below)
    const char* credentials = "ZW1haWwuYWRkcmVzc0BnbWFpbC5jb206cGFzc3dvcmQ=";
    
    const byte led = 13;
    
    void setup() {
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
    
      pinMode(led, OUTPUT);
    
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting...");
      int i = 0;
      while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
        delay(250);
        Serial.print('.');
      }
      Serial.println('\n');
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());              // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer
      Serial.println('\n');
    }
    
    void loop() {
      int unread = getUnread();
      if (unread == 0) {
        Serial.println("\r\nYou've got no unread emails");
        digitalWrite(led, LOW);
      } else if (unread > 0) {
        Serial.printf("\r\nYou've got %d new messages\r\n", unread);
        digitalWrite(led, HIGH);
      } else {
        Serial.println("Could not get unread mails");
      }
      Serial.println('\n');
      delay(5000);
    }
    
    int getUnread() {    // a function to get the number of unread emails in your Gmail inbox
      WiFiClientSecure client; // Use WiFiClientSecure class to create TLS (HTTPS) connection
      Serial.printf("Connecting to %s:%d... \r\n", host, httpsPort);
      if (!client.connect(host, httpsPort)) {   // Connect to the Gmail server, on port 443
        Serial.println("Connection failed");    // If the connection fails, stop and return
        return -1;
      }
    
      if (client.verify(fingerprint, host)) {   // Check the SHA-1 fingerprint of the SSL certificate
        Serial.println("Certificate matches");
      } else {                                  // if it doesn't match, it's not safe to continue
        Serial.println("Certificate doesn't match");
        return -1;
      }
    
      Serial.print("Requesting URL: ");
      Serial.println(url);
    
      client.print(String("GET ") + url + " HTTP/1.1\r\n" + 
                   "Host: " + host + "\r\n" +
                   "Authorization: Basic " + credentials + "\r\n" +
                   "User-Agent: ESP8266\r\n" +
                   "Connection: close\r\n\r\n"); // Send the HTTP request headers
    
      Serial.println("Request sent");
    
      int unread = -1;
    
      while (client.connected()) {                          // Wait for the response. The response is in XML format
        client.readStringUntil('<');                        // read until the first XML tag
        String tagname = client.readStringUntil('>');       // read until the end of this tag to get the tag name
        if (tagname == "fullcount") {                       // if the tag is <fullcount>, the next string will be the number of unread emails
          String unreadStr = client.readStringUntil('<');   // read until the closing tag (</fullcount>)
          unread = unreadStr.toInt();                       // convert from String to int
          break;                                            // stop reading
        }                                                   // if the tag is not <fullcount>, repeat and read the next tag
      }
      Serial.println("Connection closed");
    
      return unread;                                        // Return the number of unread emails
    }

    How it works

    The setup should be pretty familiar by now. 
    The only new thing is the getUnread() function:
    First, it starts an HTTPS connection to the Gmail server on port 443. Then it checks if the fingerprint of the certificate matches, so it knows that it's the real Google server, and not some hacker. If the certificate doesn't match, it's not safe to send the credentials to the server.

    If it matches, we send a HTTP GET request to the server:

    GET /mail/feed/atom HTTP/1.1\r\n
    Host: mail.google.com\r\n
    Authorization: Basic aVeryLongStringOfBase64EncodedCharacters=\r\n
    User-Agent: ESP8266\r\n
    Connection: close\r\n\r\n
    The request contains the URI we want to access (in this case this is the Atom feed URL), the host (which is mail.google.com), and the base64-encoded version of your login credentials.
    As you can see, the different lines of the header are separated by a CRLF (Carriage Return + Line Feed, \r\n). Two CRLF's mark the end of the header.
    The Gmail server will process our request, and send the feed as a response over the same HTTPS connection. This response is an XML document, that consists of tags with angled brackets, just like HTML. If you need a lot of data, it's recommended to use a proper XML parser library, but we only need one tag, so we can just skim through the response text until we find the <fullcount>x</fullcount> tag. The number inside this tag is the number of unread emails in the inbox.
    We can just convert it to an integer, and stop reading.
     
    This is the format of the XML feed, you can see the fullcount tag on line 5:
    <?xml version="1.0" encoding="UTF-8"?>
    <feed xmlns="http://purl.org/atom/ns#" version="0.3">
        <title>Gmail - Inbox for Dit e-mailadres wordt beveiligd tegen spambots. JavaScript dient ingeschakeld te zijn om het te bekijken.;/title>
        <tagline>New messages in your Gmail Inbox</tagline>
        <fullcount>5</fullcount>
        <link rel="alternate" href="https://mail.google.com/mail" type="text/html" />
        <modified>2017-03-05T15:54:06Z</modified>
        <entry>
            <title>New sign-in from Firefox on Linux</title>
            <summary>New sign-in from Firefox on Linux Hi ESP8266, Your Google Account Dit e-mailadres wordt beveiligd tegen spambots. JavaScript dient ingeschakeld te zijn om het te bekijken. was just used to sign in from Firefox on Linux. ESP8266 Test Dit e-mailadres wordt beveiligd tegen spambots. JavaScript dient ingeschakeld te zijn om het te bekijken. Linux Sunday,</summary>
            <link rel="alternate" href="https://mail.google.com/mail?account_id=Dit e-mailadres wordt beveiligd tegen spambots. JavaScript dient ingeschakeld te zijn om het te bekijken.&;amp;message_id=123456789&amp;view=conv&amp;extsrc=atom" type="text/html" />
            <modified>2017-03-05T15:52:45Z</modified>
            <issued>2017-03-05T15:52:45Z</issued>
            <id>tag:gmail.google.com,2004:123456789123456789</id>
            <author>
                <name>Google</name>
                <email>Dit e-mailadres wordt beveiligd tegen spambots. JavaScript dient ingeschakeld te zijn om het te bekijken.;/email>
            </author>
        </entry>
    
       ...
    
    </feed>
    

    The loop just prints the number of unread emails, and turns on an LED if you have unread messages.

    Getting the fingerprint of the Gmail server

    Like I mentioned before, we need a fingerprint to check the identity of the server. To get this fingerprint, execute the following command in a terminal (Linux & Mac):
    openssl s_client -connect mail.google.com:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin | sed 's/:/ /g'
    Copy the hexadecimal fingerprint string and paste it into the sketch on line 12. For example:
    const char* fingerprint = "D3 90 FC 82 07 E6 0D C2 CE F9 9D 79 7F EC F6 E6 3E CB 8B B3";

    Encoding your login credentials

    To get access to the feed, you have to enter your email address and password. You can't send them as plain text, you have to encode them to base64 first. Use the following command in a terminal (Linux & Mac):
    echo -n "Dit e-mailadres wordt beveiligd tegen spambots. JavaScript dient ingeschakeld te zijn om het te bekijken.:password" | base64
    Then add it to line 15 of the sketch. For example:
    const char* credentials = "ZW1haWwuYWRkcmVzc0BnbWFpbC5jb206cGFzc3dvcmQ=";

    Other APIs

    Many services send their data in JSON format. If you just need one piece of information, you may be able to use the same approach of scanning the entire JSON text for a certain word, but it's much easier to use a JSON parser, like the ArduinoJson library. It will deserialize the JSON text, and create a JSON object, you could compare it to an associative array. You can browse the entire tree structure, and easily find the data you're looking for.
    The downside is that it uses more memory.
  • ESP8266 Establishing a Wi-Fi connection

    Like I mentioned in the previous chapter, the ESP8266 can operate in three different modes: Wi-Fi station, Wi-Fi access point, and both at the same time. We'll start by looking at the configuration of a Wi-Fi station.
     

    Station mode

    Connecting to one specific network

    #include <ESP8266WiFi.h>        // Include the Wi-Fi library
    
    const char* ssid     = "SSID";         // The SSID (name) of the Wi-Fi network you want to connect to
    const char* password = "PASSWORD";     // The password of the Wi-Fi network
    
    void setup() {
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
      
      WiFi.begin(ssid, password);             // Connect to the network
      Serial.print("Connecting to ");
      Serial.print(ssid); Serial.println("...");
    
      int i = 0;
      while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
        delay(1000);
        Serial.print(++i); Serial.print(' ');
      }
    
      Serial.println('\n');
      Serial.println("Connection established!");  
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());         // Send the IP address of the ESP8266 to the computer
    }
    
    void loop() { }
    
    The code to connect to a wireless access point is relatively straightforward: enter the SSID and the password of the network you want to connect to, and call the 
    WiFi.begin
     function. Then wait for the connection to complete, et voilà, your ESP8266 is now connected to your Local Area Network.
     
    Don't believe me? I'll prove it to you: open the Serial monitor (CTRL+SHIFT+M) and upload the sketch. You should see something like this:
    Connecting to SSID...
    1 2 3 4 5 6...
    
    Connection established!
    IP address: 192.168.1.3
    Now go to your computer and open up a terminal: On Windows, search for "Command Prompt", on Mac or Linux, search for "Terminal". You could also use the shortcuts: on Windows, hit  + R, type "cmd" and hit enter, on Linux, use 
    CTRL+ALT+T
     .
     
    Next, type 
    ping
     , and then the IP address you received in the Serial monitor. If you're on Mac or Linux, use 
    CTRL+C
     to stop it after a couple of lines. The output should look something like this:
    user@computername:~$ ping 192.168.1.3
    PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
    64 bytes from 192.168.1.3: icmp_seq=1 ttl=128 time=6.38 ms
    64 bytes from 192.168.1.3: icmp_seq=2 ttl=128 time=45.2 ms
    64 bytes from 192.168.1.3: icmp_seq=3 ttl=128 time=69.1 ms
    64 bytes from 192.168.1.3: icmp_seq=4 ttl=128 time=94.0 ms
    64 bytes from 192.168.1.3: icmp_seq=5 ttl=128 time=20.5 ms
    64 bytes from 192.168.1.3: icmp_seq=6 ttl=128 time=7.37 ms
    ^C
    --- 192.168.1.3 ping statistics ---
    6 packets transmitted, 6 received, 0% packet loss, time 5003ms
    rtt min/avg/max/mdev = 6.384/40.463/94.047/32.588 ms
     
    The ping command sends small packets to the IP address of the ESP8266. When the ESP receives such a packet, it sends it back to the sender. Ping is part of the second layer of the TCP/IP stack, the Internet layer. It relies on both the Data Link layer (Wi-Fi) and the Internet Protocol*. 
    You can see that in the example above, we sent 6 packets to the ESP, and we also received 6 response (echo) packets. This tells us that the Data Link, the Wi-Fi connection, and the Internet Protocol are working correctly. 
     
    We now know that the ESP can successfully communicate with other devices on the network, and if your local network is online (if it is connected to the Internet via your modem), the ESP can also communicate with any device on the web !
     
     
    Ping is a great tool to check if the ESP (or any device, really) is still connected to the network, and if it's still working fine.
    One drawback is that IP addresses can change over time, but that's a problem we'll address in one of the following chapters...
     
    (*) I'm simplifying things a bit here. Actually, ping is part of the Internet Control Message Protocol (ICMP), that's also part of the second layer, just like the Internet Protocol. Don't worry too much about it, just remember that if you can send ping packets to a device, you can also send IP packets.
     
     

    station.png

     
    The device with the antenna serves many different purposes: 
    • Access point: Other Wi-Fi devices can connect to it, to be part of the local network.
    • Router: It routes IP packets to the right sub-nets so that they will arrive at their destination. E.g. if the computer sends a message that is meant for the ESP over the Ethernet sub-net, the router will send the packet to the Wi-Fi sub-net, because it knows that's where the ESP is.
    • Modem: if the router can't find the addressee on the local network, the packet will be passed on to the integrated modem, and it will be sent to the Internet Service Provider over a DSL line, heading for the Internet, where lots of other routers will try to get the packet to the right destination.
    But in reality, you don't have to worry too much about it, because it's all done for you, in a fraction of a second without you even noticing it!
     

    Automatically connect to the strongest network

    The sketch above might be enough for your specific application, but if you need to be able to connect to multiple Wi-Fi networks, for example the Wi-Fi at home and the Wi-Fi at the office, it won't work. 
    To solve this problem, we'll use the Wi-Fi-Multi library: You can add as many networks as you like, and it automatically connects to the one with the strongest signal.
     
    #include <ESP8266WiFi.h>        // Include the Wi-Fi library
    #include <ESP8266WiFiMulti.h>   // Include the Wi-Fi-Multi library
    
    ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    void setup() {
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
    
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting...");
      int i = 0;
      while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
        delay(1000);
        Serial.print('.');
      }
      Serial.println('\n');
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());              // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer
    }
    
    void loop() { }
    
     

    Access Point mode

    To configure the ESP8266 as an access point, to allow other devices like smartphones or laptops to connect to it, you can use the softAP function:
    #include <ESP8266WiFi.h>        // Include the Wi-Fi library
    
    const char *ssid = "ESP8266 Access Point"; // The name of the Wi-Fi network that will be created
    const char *password = "thereisnospoon";   // The password required to connect to it, leave blank for an open network
    
    void setup() {
      Serial.begin(115200);
      delay(10);
      Serial.println('\n');
    
      WiFi.softAP(ssid, password);             // Start the access point
      Serial.print("Access Point \"");
      Serial.print(ssid);
      Serial.println("\" started");
    
      Serial.print("IP address:\t");
      Serial.println(WiFi.softAPIP());         // Send the IP address of the ESP8266 to the computer
    }
    
    void loop() { }
    
     
    To see if it works, open the Wi-Fi settings on your computer, look for a network called "ESP8266 Access Point", enter the password "thereisnospoon", and connect to it. Then open a terminal, and ping to 192.168.4.1 (this is the default IP address of our ESP AP). You'll see that the ESP responds to your pings. 
     
    However, if you try to go to an online website, you'll get a timeout or a DNS error. This is because the ESP itself is not connected to the internet. The sub-net that consists of the ESP and the computer is not connected to any other networks, so there's no way for a packet on this network to make it to the Internet.
     
    If you connected a second station to the ESP access point on the other hand, you would be able to ping from one station to the other without problems, because they're on the same network.
  • ESP8266 First Web Server

    The actual implementation of a web server is much easier than it sounds, because the ESP8266 Arduino Core includes some great libraries that handle pretty much everything for you. Let's look at a basic Hello World! example.
    #include <ESP8266WiFi.h>
    #include <WiFiClient.h>
    #include <ESP8266WiFiMulti.h> 
    #include <ESP8266mDNS.h>
    #include <ESP8266WebServer.h>   // Include the WebServer library
    
    ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    ESP8266WebServer server(80);    // Create a webserver object that listens for HTTP request on port 80
    
    void handleRoot();              // function prototypes for HTTP handlers
    void handleNotFound();
    
    void setup(void){
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
    
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting...");
      int i = 0;
      while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
        delay(250);
        Serial.print('.');
      }
      Serial.println('\n');
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());              // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer
    
      if (MDNS.begin("esp8266")) {              // Start the mDNS responder for esp8266.local
        Serial.println("mDNS responder started");
      } else {
        Serial.println("Error setting up MDNS responder!");
      }
    
      server.on("/", handleRoot);               // Call the 'handleRoot' function when a client requests URI "/"
      server.onNotFound(handleNotFound);        // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
    
      server.begin();                           // Actually start the server
      Serial.println("HTTP server started");
    }
    
    void loop(void){
      server.handleClient();                    // Listen for HTTP requests from clients
    }
    
    void handleRoot() {
      server.send(200, "text/plain", "Hello world!");   // Send HTTP status 200 (Ok) and send some text to the browser/client
    }
    
    void handleNotFound(){
      server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request
    }
    There's a lot of code that's the same as in the Wi-Fi and mDNS examples.
    The actual server code is pretty straightforward. First, we create a server instance that listens for HTTP requests on port 80. This is the default port for web servers. In the setup, we tell the server what to do with certain HTTP requests. If the URI '/' is requested, the server should reply with a HTTP status code of 200 (Ok) and then send a response with the words 'Hello world!'. We put the code for generating a response in a separate function, and the we tell the server to execute it when '/' is requested, using the 
    server.on
     function.
     
    We haven't specified what the server should do if the client requests any URI other than '/'. It should respond with an HTTP status 404 (Not Found) and a message for the user. We put this in a function as well, and use 
    server.onNotFound
     to tell it that it should execute it when it receives a request for a URI that wasn't specified with 
    server.on
     .
     
    Then we start listening for HTTP requests by using 
    server.begin
     .
    During the loop, we constantly check if a new HTTP request is received by running
    server.handleClient
     . If handleClient detects new requests, it will automatically execute the right functions that we specified in the setup.
     
    To test it out, upload the sketch, open a new browser tab, and browse to http://esp8266.local. You should get a webpage saying  
    Hello world!
     . If you try to go to a different page, http://esp8266.local/test, for instance, you should get a 404 error: 
    404: Not found
     .

    Turning on and off an LED over Wi-Fi

    We can use the web server to serve interactive pages, and to react to certain POST request. In the following example, the ESP8266 hosts a web page with a button. When the button is pressed, the browser sends a POST request to /LED. When the ESP receives such a POST request on the /LED URI, it will turn on or off the LED, and then redirect the browser back to the home page with the button.
     
    In order to perform this redirect, the ESP has to add a Location header to the response, and use a 303 (See Other) HTTP status code.
     
    The button to send the POST request in the browser is part of an HTML form. You have to specify the target URI to send the request to, and the request method, in this case this is "/LED" and POST respectively.
     
    Note that I changed the content type of the response from "text/plain" to "text/html". If you send it as plain text, the browser will display it as text instead of interpreting it as HTML and showing it as a button.
     
    #include <ESP8266WiFi.h>
    #include <WiFiClient.h>
    #include <ESP8266WiFiMulti.h> 
    #include <ESP8266mDNS.h>
    #include <ESP8266WebServer.h>
    
    ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    ESP8266WebServer server(80);    // Create a webserver object that listens for HTTP request on port 80
    
    const int led = 2;
    
    void handleRoot();              // function prototypes for HTTP handlers
    void handleLED();
    void handleNotFound();
    
    void setup(void){
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
    
      pinMode(led, OUTPUT);
    
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting...");
      int i = 0;
      while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
        delay(250);
        Serial.print('.');
      }
      Serial.println('\n');
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());              // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer
    
      if (MDNS.begin("esp8266")) {              // Start the mDNS responder for esp8266.local
        Serial.println("mDNS responder started");
      } else {
        Serial.println("Error setting up MDNS responder!");
      }
    
      server.on("/", HTTP_GET, handleRoot);     // Call the 'handleRoot' function when a client requests URI "/"
      server.on("/LED", HTTP_POST, handleLED);  // Call the 'handleLED' function when a POST request is made to URI "/LED"
      server.onNotFound(handleNotFound);        // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
    
      server.begin();                           // Actually start the server
      Serial.println("HTTP server started");
    }
    
    void loop(void){
      server.handleClient();                    // Listen for HTTP requests from clients
    }
    
    void handleRoot() {                         // When URI / is requested, send a web page with a button to toggle the LED
      server.send(200, "text/html", "<form action=\"/LED\" method=\"POST\"><input type=\"submit\" value=\"Toggle LED\"></form>");
    }
    
    void handleLED() {                          // If a POST request is made to URI /LED
      digitalWrite(led,!digitalRead(led));      // Change the state of the LED
      server.sendHeader("Location","/");        // Add a header to respond with a new location for the browser to go to the home page again
      server.send(303);                         // Send it back to the browser with an HTTP status 303 (See Other) to redirect
    }
    
    void handleNotFound(){
      server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request
    }
    As you can see, the 
    server.on
     function now takes three parameters: the URI, the request method (GET or POST) and the function to execute.
     
    Connect an LED to GPIO2, and upload the sketch. Then go to http://esp8266.local/ and click the button to turn the LED on or off.
     
    You can open the developer options in Chrome (F12) to check the HTTP request that are made when you click the button: you'll see that it first send a POST request, and then receives a 303 (See Other) HTTP status as a response. The response also has a Location header containing the URI "/", so the browser will send a GET request to the URI of this new location:
     

    chrome_post_LED.png

     
    If you check the page source (CTRL+U), you can see the simple HTML form that's used:
    <form action="/LED" method="POST">
        <input type="submit" value="Toggle LED">
    </form>

    Sending data to the ESP using HTTP POST

    In the previous example, we sent an empty POST request to the ESP8266. In the previous chapter however, I explained that it's possible to send all kinds of data in the body of the POST request. 
     
    In this example, I'll show you how to send a username and a password to the ESP. The ESP will then check if they are correct, and respond to the request with the appropriate page.
    #include <ESP8266WiFi.h>
    #include <WiFiClient.h>
    #include <ESP8266WiFiMulti.h> 
    #include <ESP8266mDNS.h>
    #include <ESP8266WebServer.h>
    
    ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    ESP8266WebServer server(80);    // Create a webserver object that listens for HTTP request on port 80
    
    void handleRoot();              // function prototypes for HTTP handlers
    void handleLogin();
    void handleNotFound();
    
    void setup(void){
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
    
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting...");
      int i = 0;
      while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
        delay(250);
        Serial.print('.');
      }
      Serial.println('\n');
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());               // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());            // Send the IP address of the ESP8266 to the computer
    
      if (MDNS.begin("esp8266")) {              // Start the mDNS responder for esp8266.local
        Serial.println("mDNS responder started");
      } else {
        Serial.println("Error setting up MDNS responder!");
      }
    
      server.on("/", HTTP_GET, handleRoot);        // Call the 'handleRoot' function when a client requests URI "/"
      server.on("/login", HTTP_POST, handleLogin); // Call the 'handleLogin' function when a POST request is made to URI "/login"
      server.onNotFound(handleNotFound);           // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"
    
      server.begin();                            // Actually start the server
      Serial.println("HTTP server started");
    }
    
    void loop(void){
      server.handleClient();                     // Listen for HTTP requests from clients
    }
    
    void handleRoot() {                          // When URI / is requested, send a web page with a button to toggle the LED
      server.send(200, "text/html", "<form action=\"/login\" method=\"POST\"><input type=\"text\" name=\"username\" placeholder=\"Username\"></br><input type=\"password\" name=\"password\" placeholder=\"Password\"></br><input type=\"submit\" value=\"Login\"></form><p>Try 'John Doe' and 'password123'...</p>");
    }
    
    void handleLogin() {                         // If a POST request is made to URI /login
      if( ! server.hasArg("username") || ! server.hasArg("password") 
          || server.arg("username") == NULL || server.arg("password") == NULL) { // If the POST request doesn't have username and password data
        server.send(400, "text/plain", "400: Invalid Request");         // The request is invalid, so send HTTP status 400
        return;
      }
      if(server.arg("username") == "John Doe" && server.arg("password") == "password123") { // If both the username and the password are correct
        server.send(200, "text/html", "<h1>Welcome, " + server.arg("username") + "!</h1><p>Login successful</p>");
      } else {                                                                              // Username and password don't match
        server.send(401, "text/plain", "401: Unauthorized");
      }
    }
    
    void handleNotFound(){
      server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request
    }
    
    The HTML in handleRoot is:
    <form action="/login" method="POST">
        <input type="text" name="username" placeholder="Username"></br>
        <input type="password" name="password" placeholder="Password"></br>
        <input type="submit" value="Login">
    </form>
    <p>
        Try 'John Doe' and 'password123'...
    </p>
    Upload the sketch and go to http://esp8266.local/, then type 'John Doe' into the username field, and 'password123' into the password field, and click 'Login'. You should get a welcome screen. If you leave on or both of the fields blank, you should get a 400 (Bad Request) error. If you enter a wrong username or password, you should get a 401 (Unauthorized) error.
     
    The data of the POST body can be accessed using 
    server.arg("key")
     , and you can check if a specific key exists using 
    server.hasArg("key")
     . The key name on the ESP8266 corresponds to the name argument in the HTML form on the web page.
     

     

    When we get a POST request, we first check if the necessary arguments (username and password) are present. If that's not the case, we send a 400 (Invalid Request) status.
    Then we check if the credentials match 'John Doe' & 'password123'. If that's the case, we respond with a status 200 (Ok) and a welcome page. If the username and/or password doesn't match, we send a 401 (Unauthorized) status.

    Inline functions

    In the previous examples, we passed 
    handleRoot
     and 
    handleNotFound
     to the 
    server.on
     function as a parameter (callback function). In some cases however, it's more readable to just write the definition of the function inline, like so:
    void setup(){
      //...
      server.onNotFound([](){
        server.send(404, "text/plain", "404: Not found");
      });
    }
    
     
  • ESP8266 Hardware

    Deciding on what board to buy

    ESP8266 is just the name of the chip, many companies have designed their own boards that use this chip, so there are many different ESP8266 boards on the market. If you don't know the difference between all these different models, you might have a hard time deciding on what board to buy.
     
    The easiest (and fastest) way to get an ESP8266 board is to buy one from a well-known electronics shop like Adafruit or SparkFun, but if you want it cheap, you should check out Ebay or other sites where you can order them directly from China.

    Development boards

    Some boards have all kinds of features on-board to help developing ESP8266 hardware and software: for example, a USB to Serial converter for programming, a 3.3V regulator for power, on-board LEDs for debugging, a voltage divider to scale the analog input...
    If you're a beginner, I would definitely recommend a development board. It's easier to get started if you don't have to worry about all these things.

    Bare-bones AI Thinker boards

    If you want to add an ESP8266 to a small project, or if you want a cheaper* board, you might want to buy a board that doesn't have these features. In that case, you can buy one of the many ESP-## modules developed by AI Thinker. They contain just the ESP8266 and the necessary components to run it. 
    To program the board, you'll need an external USB-to-Serial converter.
    With some modules, you get an on-board antenna (PCB or ceramic) and an LED, some boards have just an antenna connector, or no LEDs at all. They also differ in physical size, and flash memory size. An important thing to notice, is that some boards do not break out all GPIO pins. For example, the ESP-01 only has 2 I/O pins available (apart from the TX and RX pins), while other modules like the ESP-07 or ESP-12 break out all available I/O pins.
     
    (*) The board itself is cheaper, but you'll have to spend more on external parts.

    Overview

    Here's a table with some of the most popular ESP8266 development boards and their features:
     
    BoardGPIO3.3V VregUSB-to-SerialAuto-ResetAuto-ProgramFlashADC rangeExtra
    SparkFun ESP8266 Thing 11 + - + ±* 512KB (4Mb) 0-1V Battery charger, crypto element, temperature sensor, light sensor
    SparkFun ESP8266 Thing - Dev Board 11 + + + + 512KB (4Mb) 0-1V  
    Node MCU 11 + + + + 4MB (32Mb) 0-3.3V  
    Adafruit Feather HUZZAH with ESP8266 11 + + + + 4MB (32Mb) 0-1V Battery charger
    Adafruit HUZZAH ESP8266 Breakout 11 + - - - 4MB (32Mb) 0-1V 5V-tolerant RX and Reset pins
    ESP-## 4 - 11 - - - - 512KB (4Mb) – 4MB (32Mb) 0-1V Small and cheap
    You can find the full list of ESP-## modules here.
     
    As you can see, both the Node MCU and the Adafruit Feather HUZZAH are solid choices.
     
    (*) When auto-program on the SparkFun ESP8266 Thing is enabled, you can't use the Serial Monitor.

    Getting the hardware ready

    There are two main categories of ESP8266 boards: development boards with a USB interface (USB-to-Serial convertor) on-board, and boards without a USB connection.

    Development boards with a USB interface

    For example: NodeMCU, SparkFun ESP8266 Thing - Dev Board, SparkFun Blynk Board, Adafruit Feather HUZZAH with ESP8266 Wi-Fi...
     
    These boards will show up in Device manager (Windows) or in lsusb (Linux) as soon as you plug them in.
    They have a 3.3V regulator on-board, and can be programmed over USB directly, so you don't need any external components to get it working.
    The only thing you may need to do, is solder on some headers.

    Bare-bones boards and boards without a USB interface

    This category has 2 sub-categories: boards with a 3.3V regulator on-board, and boards with just the ESP8266 and a flash memory chip, without 3.3V regulator. If your board doesn't have a 5V to 3.3V regulator, buy one separately. You could use an LM1117-3.3 for example. The on-board 3.3V regulator of most Arduino boards is not powerful enough to power the ESP.

    To program the board, you'll need a USB-to-Serial converter. The FTDI FT232RL is quite popular, because it can switch between 5V and 3.3V. It is essential that the USB-to-Serial converter you buy operates at 3.3V. If you buy a 5V model, you will damage the ESP8266.

    Connecting the USB-to-Serial converter

    1. Connect the ground (GND) of the USB-to-Serial converter to the ground of the ESP8266.
    2. Connect the RX-pin of the USB-to-Serial converter to the TXD pin of the ESP8266. (On some boards, it's labelled TX instead of TXD, but it's the same pin.)
    3. Connect the TX-pin of the USB-to-Serial converter to the RXD pin of the ESP8266. (On some boards, it's labelled RX instead of RXD, but it's the same pin.)
    4. If your ESP8266 board has a DTR pin, connect it to the DTR pin of the USB-to-Serial converter. This enables auto-reset when uploading a sketch, more on that later. 

    Enabling the chip

    If you're using a bare-bone ESP-## board by AI Thinker, you have to add some resistors to turn on the ESP8266, and to select the right boot mode. 
    1. Enable the chip by connecting the CH_PD (Chip Power Down, sometimes labeled CH_EN or chip enable) pin to VCC through a 10KΩ resistor.
    2. Disable SD-card boot by connecting GPIO15 to ground through a 10KΩ resistor.
    3. Select normal boot mode by connecting GPIO0 to VCC through a 10KΩ resistor.
    4. Prevent random resets by connecting the RST (reset) pin to VCC through a 10KΩ resistor.
    5. Make sure you don't have anything connected to GPIO2 (more information in the next chapter).

    Adding reset and program buttons

    If your ESP8266 board doesn't have a reset button, you could add one by connecting a push button to between the RST pin and ground.
     
    To put the chip into programming mode, you have to pull GPIO0 low during startup. That's why we also need a program button. Because it's possible to use GPIO0 as an output, we can't directly short it to ground, that could damage the chip. To prevent this, connect 470Ω resistor in series with the switch. It's important that this resistance is low enough, otherwise, it will be pulled high by the 10KΩ resistor we added in the previous paragraph.

    Connecting the power supply

    If the ESP8266 module you have doesn't have a 3.3V voltage regulator on board, you have to add one externally. You could use an LM1117-3.3 for example.
    1. Connect the first pin of the regulator to ground.
    2. Place a 10µF capacitor between pin 2 (Vout) and ground. Watch the polarity!
    3. Place a 10µF capacitor between pin 3 (Vin) and ground.
    4. Connect pin 2 to the 3.3V or VCCof the ESP8266.
    5. Connect pin 3 to a 5V power source, a USB port, for example.
     

    VReg.pngESP8266-2.png

    Before you begin...

    There's a few things you have to look out for when using an ESP8266: The most important thing is that it runs at 3.3V, so if you connect it to a 5V power supply, you'll kill it. Unlike some 3.3V Arduino or Teensy boards, the ESP8266's I/O pins are not 5V tolerant, so if you use a 5V USB-to-Serial converter, or 5V sensors etc. you'll blow it up. 
    A second thing to keep in mind is that the ESP8266 can only source or sink 12mA per output pin, compared to 20-40mA for most Arduinos.
    The ESP8266 has one analog to digital converter, but it has a strange voltage range: 0 - 1V, voltages above 1V might damage the board.
     
    One last thing to keep in mind is that the ESP8266 has to share the system resources and CPU time between your sketch and the Wi-Fi driver. Also, features like PWM, interrupts or I²C are emulated in software, most Arduinos on the other hand, have dedicated hardware parts for these tasks.
    For most applications however, this is not too much of an issue.
  • ESP8266 Multicast Domain Name System

    DNS

    Let's face it, constantly typing IP addresses is really cumbersome, and it would be impossible to remember all your favorite websites' addresses, especially if they use IPv6.
    That's why domain names were introduced: a simple string of text that's easy to remember, for example www.google.com
     
    However, to send a request to a website, your computer still needs to know its IP address. That's where DNS comes in. It stands for Domain Name System, and is a way to translate a website's domain name to its IP address. On the Internet, there are a lot of DNS servers. Each DNS server has a long list of domain names and their corresponding IP addresses. Devices can connect to a DNS server and send a domain name, the DNS server will then respond with the IP address of the requested site.
    You could compare it to a telephone directory: you can look up a name to find the corresponding phone number.
     
    The DNS lookup happens completely in the background: when you go to a website in your browser, it will first send a request to a DNS server (this implies that the computer knows the IP address of the DNS server itself), wait for the response of the lookup, and then send the actual request to the right IP address.

    mDNS

    DNS works great for normal sites on the Internet, but most local networks don't have their own DNS server. This means that you can't reach local devices using a domain name, and you're stuck using IP addresses...
     
    Fortunately, there's another way: multicast DNS, or mDNS. 
    mDNS uses domain names with the .local suffix, for example http://esp8266.local. If your computer needs to send a request to a domain name that ends in .local, it will send a multicast query to all other devices on the LAN that support mDNS, asking the device with that specific domain name to identify itself. The device with the right name will then respond with another multicast and send its IP address. Now that your computer knows the IP address of the device, it can send normal requests.
     
    Luckily for us, the ESP8266 Arduino Core supports mDNS:
    #include <ESP8266WiFi.h>        // Include the Wi-Fi library
    #include <ESP8266WiFiMulti.h>   // Include the Wi-Fi-Multi library
    #include <ESP8266mDNS.h>        // Include the mDNS library
    
    ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    void setup() {
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
    
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting...");
      int i = 0;
      while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
        delay(1000);
        Serial.print(++i); Serial.print(' ');
      }
      Serial.println('\n');
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());              // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer
    
      if (!MDNS.begin("esp8266")) {             // Start the mDNS responder for esp8266.local
        Serial.println("Error setting up MDNS responder!");
      }
      Serial.println("mDNS responder started");
    }
    
    void loop() { }
    
     
    Upload it and open ping again. Try to ping to esp8266.local:
    user@computername:~$ ping esp8266.local
    PING esp8266.local (10.92.237.128) 56(84) bytes of data.
    64 bytes from 10.92.237.128: icmp_seq=1 ttl=128 time=5.68 ms
    64 bytes from 10.92.237.128: icmp_seq=2 ttl=128 time=3.41 ms
    64 bytes from 10.92.237.128: icmp_seq=3 ttl=128 time=2.55 ms
    64 bytes from 10.92.237.128: icmp_seq=4 ttl=128 time=2.19 ms
    64 bytes from 10.92.237.128: icmp_seq=5 ttl=128 time=2.29 ms
    64 bytes from 10.92.237.128: icmp_seq=6 ttl=128 time=2.74 ms
    ^C
    --- esp8266.local ping statistics ---
    6 packets transmitted, 6 received, 0% packet loss, time 5007ms
    rtt min/avg/max/mdev = 2.190/3.148/5.687/1.202 ms
     
    As you can see, ping will automatically find the IP address of the ESP for you.
     
    mDNS is supported on Windows, OSX, Linux and iOS, but not (yet?) on Android.
    It's a real shame that Android doesn't support it, you can help by starring this issue report for the Chromium project to ask for mDNS support in Chrome on Android.
     
    Of course, you can change the domain name of the ESP by changing the parameter of MDNS.begin.
  • ESP8266 Network Time Protocol

    There are many applications where you want to know the time. In a normal Arduino project, you would have to get a RTC module, set the right time, sacrifice some Arduino pins for communication... And when the RTC battery runs out, you have to replace it.

    On the ESP8266, all you need is an Internet connection: you can just ask a time server what time it is. To do this, the Network Time Protocol (NTP) is used.

    In the previous examples (HTTP, WebSockets) we've only used TCP connections, but NTP is based on UDP. There are a couple of differences, but it's really easy to use, thanks to the great libraries that come with the ESP8266 Arduino Core.

    The main difference between TCP and UDP is that TCP needs a connection to send messages: First a handshake is sent by the client, the server responds, and a connection is established, and the client can send its messages. After the client has received the response of the server, the connection is closed (except when using WebSockets). To send a new message, the client has to open a new connection to the server first. This introduces latency and overhead.

    UDP doesn't use a connection, a client can just send a message to the server directly, and the server can just send a response message back to the client when it has finished processing. There is, however, no guarantee that the messages will arrive at their destination, and there's no way to know whether they arrived or not (without sending an acknowledgement, of course). This means that we can't halt the program to wait for a response, because the request or response packet could have been lost on the Internet, and the ESP8266 will enter an infinite loop.

    Instead of waiting for a response, we just send multiple requests, with a fixed interval between two requests, and just regularly check if a response has been received. 

    Getting the time

    Let's take a look at an example that uses UDP to request the time from a NTP server.

    Libraries, constants and globals

    #include <ESP8266WiFi.h>
    #include <ESP8266WiFiMulti.h>
    #include <WiFiUdp.h>
    
    ESP8266WiFiMulti wifiMulti;      // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    WiFiUDP UDP;                     // Create an instance of the WiFiUDP class to send and receive
    
    IPAddress timeServerIP;          // time.nist.gov NTP server address
    const char* NTPServerName = "time.nist.gov";
    
    const int NTP_PACKET_SIZE = 48;  // NTP time stamp is in the first 48 bytes of the message
    
    byte NTPBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
    To use UDP, we have to include the WiFiUdp library, and create a UDP object. We'll also need to allocate memory for a buffer to store the UDP packets. For NTP, we need a buffer of 48 bytes long.
    To know where to send the UDP packets to, we need the hostname of the NTP server, this is time.nist.gov.

    Setup

    void setup() {
      Serial.begin(115200);          // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println("\r\n");
    
      startWiFi();                   // Try to connect to some given access points. Then wait for a connection
    
      startUDP();
    
      if(!WiFi.hostByName(NTPServerName, timeServerIP)) { // Get the IP address of the NTP server
        Serial.println("DNS lookup failed. Rebooting.");
        Serial.flush();
        ESP.reset();
      }
      Serial.print("Time server IP:\t");
      Serial.println(timeServerIP);
      
      Serial.println("\r\nSending NTP request...");
      sendNTPpacket(timeServerIP);  
    }
    In the setup, we just start our Serial and Wi-Fi, as usual, and we start UDP as well. We'll look at the implementation of this function later.
    We need the IP address of the NTP server, so we perform a DNS lookup with the server's hostname. There's not much we can do without the IP address of the time server, so if the lookup fails, reboot the ESP. 
    If we do get an IP, send the first NTP request, and enter the loop.

    Loop

    unsigned long intervalNTP = 60000; // Request NTP time every minute
    unsigned long prevNTP = 0;
    unsigned long lastNTPResponse = millis();
    uint32_t timeUNIX = 0;
    
    unsigned long prevActualTime = 0;
    
    void loop() {
      unsigned long currentMillis = millis();
    
      if (currentMillis - prevNTP > intervalNTP) { // If a minute has passed since last NTP request
        prevNTP = currentMillis;
        Serial.println("\r\nSending NTP request...");
        sendNTPpacket(timeServerIP);               // Send an NTP request
      }
    
      uint32_t time = getTime();                   // Check if an NTP response has arrived and get the (UNIX) time
      if (time) {                                  // If a new timestamp has been received
        timeUNIX = time;
        Serial.print("NTP response:\t");
        Serial.println(timeUNIX);
        lastNTPResponse = currentMillis;
      } else if ((currentMillis - lastNTPResponse) > 3600000) {
        Serial.println("More than 1 hour since last NTP response. Rebooting.");
        Serial.flush();
        ESP.reset();
      }
    
      uint32_t actualTime = timeUNIX + (currentMillis - lastNTPResponse)/1000;
      if (actualTime != prevActualTime && timeUNIX != 0) { // If a second has passed since last print
        prevActualTime = actualTime;
        Serial.printf("\rUTC time:\t%d:%d:%d   ", getHours(actualTime), getMinutes(actualTime), getSeconds(actualTime));
      }  
    }
    The first part of the loop sends a new NTP request to the time server every minute. This is based on Blink Without Delay. 
    Then we call the getTime function to check if we've got a new response from the server. If this is the case, we update the timeUNIX variable with the new timestamp from the server.
    If we don't get any responses for an hour, then there's something wrong, so we reboot the ESP.
    The last part prints the actual time. The actual time is just the last NTP time plus the time since we received that NTP message. 

    Setup functions

    Nothing special here, just a function to connect to Wi-Fi, and a new function to start listening for UDP messages on port 123.
    void startWiFi() { // Try to connect to some given access points. Then wait for a connection
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting");
      while (wifiMulti.run() != WL_CONNECTED) {  // Wait for the Wi-Fi to connect
        delay(250);
        Serial.print('.');
      }
      Serial.println("\r\n");
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());             // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.print(WiFi.localIP());            // Send the IP address of the ESP8266 to the computer
      Serial.println("\r\n");
    }
    
    void startUDP() {
      Serial.println("Starting UDP");
      UDP.begin(123);                          // Start listening for UDP messages on port 123
      Serial.print("Local port:\t");
      Serial.println(UDP.localPort());
      Serial.println();
    }

    Helper functions

    uint32_t getTime() {
      if (UDP.parsePacket() == 0) { // If there's no response (yet)
        return 0;
      }
      UDP.read(NTPBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
      // Combine the 4 timestamp bytes into one 32-bit number
      uint32_t NTPTime = (NTPBuffer[40] << 24) | (NTPBuffer[41] << 16) | (NTPBuffer[42] << 8) | NTPBuffer[43];
      // Convert NTP time to a UNIX timestamp:
      // Unix time starts on Jan 1 1970. That's 2208988800 seconds in NTP time:
      const uint32_t seventyYears = 2208988800UL;
      // subtract seventy years:
      uint32_t UNIXTime = NTPTime - seventyYears;
      return UNIXTime;
    }
    
    void sendNTPpacket(IPAddress& address) {
      memset(NTPBuffer, 0, NTP_PACKET_SIZE);  // set all bytes in the buffer to 0
      // Initialize values needed to form NTP request
      NTPBuffer[0] = 0b11100011;   // LI, Version, Mode
      // send a packet requesting a timestamp:
      UDP.beginPacket(address, 123); // NTP requests are to port 123
      UDP.write(NTPBuffer, NTP_PACKET_SIZE);
      UDP.endPacket();
    }
    
    inline int getSeconds(uint32_t UNIXTime) {
      return UNIXTime % 60;
    }
    
    inline int getMinutes(uint32_t UNIXTime) {
      return UNIXTime / 60 % 60;
    }
    
    inline int getHours(uint32_t UNIXTime) {
      return UNIXTime / 3600 % 24;
    }
    In the getTime function, we first try to parse the UDP packet. If there's no packet available, the function just returns 0. If there is a UDP packet available however, read it into the buffer. The NTP timestamp is 32 bits or 4 bytes wide, so we combine these bytes into one long number. This number is the number of seconds since Jan 1, 1900, 00:00:00, but most applications use UNIX time, the number of seconds since Jan 1, 1970, 00:00:00 (UNIX epoch). To convert from NTP time to UNIX time, we just subtract 70 years worth of seconds.
     
    To request the time from the NTP server, you have to send a certain sequence of 48 bytes. We don't need any fancy features, so just set the first byte to request the time, and leave all other 47 bytes zero.
    To actually send the packet, you have to start the packet, specifying the IP address of the server, and the NTP port number, port 123. Then just write the buffer to the packet, and send it with endPacket.
     
    The last three functions are just some simple math to convert seconds to hours, minutes and seconds.

    Using the example

    Enter your Wi-Fi credentials on lines 79-81, and hit upload. If you have a working Internet connection, you should get an output that looks like this:
    Connecting
    .........
    
    Connected to Wi-Fi SSID
    IP address:	192.168.1.2
    
    Starting UDP
    Local port:	123
    
    Time server IP:	216.229.0.179
    
    Sending NTP request...
    NTP response:	1488378061
    UTC time:	14:21:53   
    Sending NTP request...
    NTP response:	1488378114
    UTC time:	14:22:53   
    Sending NTP request...
    NTP response:	1488378174
    UTC time:	14:23:53   
    Sending NTP request...
    NTP response:	1488378234
    UTC time:	14:24:53   
    Sending NTP request...
    NTP response:	1488378294
    UTC time:	14:25:53
    ...
    You should see the time update every second, and Sending NTP request...  should show up every minute.
    If you don't have an Internet connection, the DNS lookup of the time server will fail:
    Connecting
    .........
    
    Connected to Wi-Fi SSID
    IP address:	192.168.1.2
    
    Starting UDP
    Local port:	123
    
    DNS lookup failed. Rebooting.
    
     ets Jan  8 2013,rst cause:2, boot mode:(3,6)
    If your connection is not reliable, or if there's heavy traffic, you might encounter some dropped packets:
    Sending NTP request...
    NTP response:	1488378780
    UTC time:	14:33:54   
    Sending NTP request...
    UTC time:	14:34:54   
    Sending NTP request...
    NTP response:	1488378895
    UTC time:	14:35:0
    As you can see, the ESP never received a response to the second NTP request. That's not really an issue, as long as at least some packets make it through.

    Local time and daylight savings

    An NTP server returns the UTC time. If you want local time, you have to compensate for your time zone and daylight savings. For example, if you want CET (Central European Time), you have to add 3600 to the UNIX time during winter, (3600 s = 1 h), and 7200 during summer (DST).
  • ESP8266 Over The Air Updates

    Uploading over Serial is fine during development, when you have access to the Serial pins and the USB port. But once your project is finished, and you put it inside an enclosure, it not that easy to upload updates with bug fixes or new features.
    A solution to this problem is Over The Air updating, or OTA for short. As the name implies, this technology allows you to upload new code over Wi-Fi, instead of Serial.
    The only disadvantage is that you have to explicitly add the code for it to every sketch you upload. You also need a flash chip that is twice the size of your sketch, so it won't work for 512kB boards. (It has to download the new sketch while still running the old code.)
    Let's take a look at an example...

    Blink OTA

    The following example is basically Blink Without Delay, but with the necessary OTA and Wi-Fi code added as well.
    #include <ESP8266WiFi.h>
    #include <ESP8266WiFiMulti.h>
    #include <ArduinoOTA.h>
    
    ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
    
    const byte led = 13;
    
    void setup() {
      Serial.begin(115200);         // Start the Serial communication to send messages to the computer
      delay(10);
      Serial.println('\n');
    
      wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");   // add Wi-Fi networks you want to connect to
      wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
      wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
    
      Serial.println("Connecting...");
      int i = 0;
      while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
        delay(250);
        Serial.print('.');
      }
      Serial.println('\n');
      Serial.print("Connected to ");
      Serial.println(WiFi.SSID());              // Tell us what network we're connected to
      Serial.print("IP address:\t");
      Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer
      
      ArduinoOTA.setHostname("ESP8266");
      ArduinoOTA.setPassword("esp8266");
    
      ArduinoOTA.onStart([]() {
        Serial.println("Start");
      });
      ArduinoOTA.onEnd([]() {
        Serial.println("\nEnd");
      });
      ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
        Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
      });
      ArduinoOTA.onError([](ota_error_t error) {
        Serial.printf("Error[%u]: ", error);
        if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
        else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
        else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
        else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
        else if (error == OTA_END_ERROR) Serial.println("End Failed");
      });
      ArduinoOTA.begin();
      Serial.println("OTA ready");
    
      pinMode(led, OUTPUT);
      digitalWrite(led, 1);
    }
    
    unsigned long previousTime = millis();
    
    const unsigned long interval = 1000;
    
    void loop() {
      ArduinoOTA.handle();
      unsigned long diff = millis() - previousTime;
      if(diff > interval) {
        digitalWrite(led, !digitalRead(led));  // Change the state of the LED
        previousTime += diff;
      }
    }
    Add your Wi-Fi credentials, and upload the sketch over Serial. Connect an LED (+ resistor) to pin 13. Then restart the IDE (you have to close all windows). Go to Tools > Port, and you should get a new option: Network Ports: ESP8266 at 192.168.1.x. Select it.
     

    ESP_OTA.png


    Next, change the interval on line 59 from 1000 to 500 milliseconds, and click upload. You should get a password prompt: enter "esp8266". This password is set on line 31, so you can change it if you want to. You can also delete line 31 altogether to use it without a password, but it's not recommended - for obvious security reasons.
     
    The sketch should upload just fine, and once the ESP has reset itself, the LED should blink twice as fast.
     
    Once in a while, you might get an error saying  
    [ERROR]: No Answer
     . If this happens, just enter the password, and try again.

    Serial Monitor OTA

    Using the Serial Monitor over Wi-Fi is not possible (yet?). When you try to open it, you'll be prompted a password, entering the password won't work, because there is no SSH support to access the ESP's console.
     
    You can use a different program to get debug output from the physical Serial port. On Windows, you can try Portmon. On Linux, you can try GTKTerm ( 
    sudo apt-get install gtkterm
    ) or Screen ( 
    sudo apt-get install screen
     to install, and 
    screen /dev/ttyUSB0 115200
     or 
    screen /dev/ttyACM0 115200
     to run; 
    CTRL+A, CTRL+D
     to exit).
  • ESP8266 Software

    Installation of the required software

    The first step is to download and install the Arduino IDE. I explained this in A Beginner's Guide to Arduino. (As of February 7th 2017, the latest stable version of the IDE is 1.8.1.)
     
    To program the ESP8266, you'll need a plugin for the Arduino IDE, it can be downloaded from GitHub manually, but it is easier to just add the URL in the Arduino IDE:
    1. Open the Arduino IDE.
    2. Go to File > Preferences.
    3. Paste the URL http://arduino.esp8266.com/stable/package_esp8266com_index.json into the Additional Board Manager URLs field.
      (You can add multiple URLs, separating them with commas.)
    4. Go to Tools > Board > Board Manager and search for 'esp8266'. Select the newest version, and click install. (As of February 7th 2017, the latest stable version is 2.3.0.)
    You can check out the official install guide here.

    Drivers

    If you are using a board with the CH340(G) USB-to-Serial chip, like the NodeMCU, you'll probably have to install the USB drivers for it.
    They can be found on GitHub
    If you are using a board with the CP2104 USB-to-Serial chip, like the Adafruit Feather HUZZAH board, you'll probably have to install USB drivers as well. You can find them on the Silicon Labs website.
    Boards with an FTDI chip should work right out of the box, without the need of installing any drivers.

    Examples

    You can find all examples used in this article on my GitHub. Just download it as a .ZIP file, unzip it to a convenient location, and you're good to go!