Preamble


Classical arduino development board (Uno, genuino, ...) do not host a wifi chipset. A wifi "shield" (i.e. an additional board that plugs on the pins of the arduino board) must be used for that. Nevertheless, there are other micro-controllers that are natively capable of communicating over wifi, bluetooth, ... for example esp32 and their "little brother", the esp8266.

A lot of electronics builders propose mini-boards based on these two micro-controllers. The one that is used in this subject is from the firm Wemos and is called D1 mini. This enterprise builds and sells several types of boards, with more or less functionalities, at a very low price. For example, D1 mini costs about 5 euros. Consult https://wiki.wemos.cc/ to see their different products.

Thanks to the arduino development kit for these micro-controllers, it is very easy to setup a wifi connection and to communicate with a web server, or a classical one directly over TCP. The goal of the following exercises is to discover how.

BEWARE ! these boards may be fragile, so do not touch the surface component, at risk to burn the card

 

 

Software setup

  • To write programs for the D1 mini, there are different solutions. We are going to use the arduino development environment, which is used to code in a langage close to the Java & C++
  • Thus, arduino must be firstly installed.
  • The following assumes that your are under a liunx OS, using english language (so you have to translate the menu title of arduino used in this subject).
    • download the last version [ here ]. You obtain a .tgz archive.
    • de-compact the archive in your home directory. You obtain a new directory named arduino-2.XX (where XX depends on the version downloaded)
    • go into this folder and launch the arduino executable
    • This first execution setup the default values for configuration parameters, for example the directory where you pout your codes. (which should be ~/Arduino). Just accept the default values.
  • After that, the esp8266 dev. kit must be installed.
    • In "Fiile" menu, choose "Preferences"
    • Then in "Additional boards manager URL", add https://arduino.esp8266.com/stable/package_esp8266com_index.json. Clic on "Ok" to save
    • In "Tools" menu, go to item "Board", then select "Board manager"
    • In the up-left text field , type "D1" to filter the results. There should be a single choice.
    • Move the mouse cursor on this single choice then an "Install" button should appear. Clic it to start installation.
    • Go back to "Tools" -> "Board" and check that you can select "LOLIN (Wemos) D1 R2 & mini". If it is the case, you are ready to proceed further.

The breadboard setup
 
  • The following exercises are based on a simple electronic setup, using few electronic components and 2 "modules" : a piezo-electric sensor and an infrared receiver.
  • These small boards already integrates various electronic components and are able to communicate with the µC thanks to different protocols.
  • All you need to work with this setup is to find an adequate arduino library for the IR receiver. All is already wired.
  • In order to initialize correctly the setup, here is the connection scheme to the µC : 
    • a led is connected to pin D1,
    • the state of the push button can be read on pin D2,
    • the data pin of the IR receiver is connected to pin D3
    • the positive pin of the piezo-electric sensor is connected to pin A0
    • other pins are connected to Vcc (+3.3V), and ground
 
Exercice #1: a simple sketch with a led and a push button
 

Working principles:

  • pin D2 is connected to the "output" pin of the button, which is itself connected to the ground through a 10Kohm resistor. The other pin of the button is connected to the 3.3V.
  • this scheme is called a pull-down resistor, that leads to set 0V by default on pin D2, and 3.3V when the button is pushed.
  • pin D1 is used to switch on/off the led. The ESP8266 must be told to put a high or low state at this pin. In the present case, the led must be ON as long as D2 is pushed and OFF as soon as D2 is released.

 

 What must be done - part I :

  • Start arduino and create a new sketch.
  • Copy the following code to obtain the described behaviour (NB : some parts are useless for this exercise but will be for the others).
#include <ESP8266WiFi.h>

void setup() {
  Serial.begin(115200);
  delay(10);
 
  // power off Wifi to save energy
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();
  delay(10); 
 
  pinMode(D2,INPUT); // switch
  pinMode(D1,OUTPUT); // LED
  digitalWrite(D1,LOW); // switch off the led at start
  delay(10);  
}
 
void testSwitch() {
  int state = digitalRead(D2);  
  if (state == 0) {
    Serial.println("switch off => light off");
    digitalWrite(D1,LOW);
  }
  else {
    Serial.println("switch on => light on");
    digitalWrite(D1,HIGH);    
  }  
}
 
void loop() {
  testSwitch();
  delay(10); // attendre 10ms
}
 
  • Save this sketch in the Arduino directory, giving a simple name, e.g.  simpletest.
  • Connect the esp8266 to a USB port of the computer
  • In menu "Tools", select "Board" : Wemos D1 R2 & mini.
  • Check that :
    • upload speed is at 921600
    • port is /dev/ttyUSB0 (NB : if you have other connected boards, it may be ttyUSB1, ttyUSB2, ...)
  • In menu "Tools", choose "Monitor". A new window appears (called the monitor in the following), that displays what is sent to the computer by the D1, thanks to the instructions  Serial.print(...). Unfortunately, it is the only way to debug a program. CAUTION ! In the bottom-right of this window, you have to set the speed to 115200 bauds. Otherwise, the computer will receive jammed data and display random characters.
  • In menu "Sketch",  choose "Upload". The code is compiled then transfered in the flash memory of the D1. It compilation fails, there is a mistake in the code. If the transfer fails, the speed transfer may be invalid, or not adapted to the board. Try a lower speed (e.g. 460800 bauds, or even less)
 

Remarks :

  • it is better to wait few milliseconds between calls to testSwitch(), hence the instruction delay(10). Otherwise, the D1 may crash.
  • This sketch is not really well written because it sets D1 to HIGH or LOW even if it is already HIGH or LOW (see part II to correct that) and thus, it prints a huge number of message on Serial.
  • Pushing or releasing the button is not detected immediately since there is a wait of 10ms. To correct that, it is to use the interrupts principle to call testSwitch(). For example, we can tell the µC to interrupt what it is currently doing to call a particular function (i.e. a callback) as soon as the state of pin D2 changes. This is the subject of exercise #2.

 

What must be done - part II :

  • Modify the sketch so that the LED is ON or OFF only when the button state changes, i.e. if its state is different over two consecutive executions of loop().

Exercise #2: interrupts
 
Working principles:
  • At boot, the LED is off.
  • As soon as the button is pressed and released, the LED changes of state, i.e. turns on if it was off, and the opposite. Note that the LED keeps its state during the time between the push and the release.
  • The change of state must be driven by an interrupt handler.
What must be done :
  • Create a new sketch, by copying the code of the first exercise.
  • Modify the sketch so that :
    • testSwitch() is called as soon as the state of pin D2 changes => must use interrupts.
    • testSwitch() must change the state of the LED if button has been pressed then released.

Remarks:

  • because of using interrupts, there is no need to remember the previous state: we are sure that testSwitch() is called only when the state changes.
  • interrupt handler must execute as fast as possible. Thus, it is not a good idea to put Serial.println() calls within.

 

Exercise #3: testing reflexes - part I
 
Working principles:
  • At boot, LED is off.
  • After 5 seconds, the LED must blink between 2 and 5 times (at random). The gap between blinks is 500ms. The last blink lasts for 1sec and the others 500ms, so that the user knows when the sequence ends.
  • Then the user must press the button as many times as the LED blinked, and as fast as possible.
  • The time between the first and the last push is measured and printed on Serial,  and the LED is lighted for 200ms to warn the user he must stop pushing the button.
  • Then, after 5 seconds, the LED blinks again, etc.
What must be done :
  • Create a new sketch, by copying the code of the second exercise.
  • Modify the sketch to reproduce the behavior exposed above

Advice :

  • time (in milli seconds) elapsed from boot can be retrieved using : long t = millis(); Thus, calling this method twice allows to measure a gap in time.
  • to draw a random number, use : random(min,max) (min included, max excluded)
  • the behavior consists in two applications states : LED blink, push button. This can be directly translated within the sketch using a state variable.

For example :

int state = 0; // 0=blink, 1= button
int nbBlinks;
volatile int countPush; // incremented by testSwitch()
...
setup() {
  ...
  // set interrupt to call testSwitch()
  ...
}
loop() {
  if (state == 0) {
    // wait 5 secs
    // assign nbBlinks
    // do the blinks
    // t1 = current time;
    state = 1; countPush = 0;
  }
  else if (state == 1) {
    if (countPush >= nbBlinks) { // see Rk below for the >=
      // t2 =  current time
      // print t2-t1
      state == 0;
    }
  }
}

 

Remark : if the button is pushed sufficiently rapidly, the testSwitch() function may be called more than nbBlinks times before the loop() function resumes. Thus, it is perfectly possible that countPush becomes greater than nbBlinks before the test is done in loop(). This is why a >= must be used instead of a simple ==.

 

Exercise #4: testing reflexes - part II
 
Working principles:
  • At boot, LED is off.
  • After 5 seconds, the LED must blink between 2 and 9 times. The gap between blinks is 500ms. The last blink lasts for 1sec and the others 500ms, so that the user knows when the sequence ends.
  • Then the user must press a button of an IR remote controller as fast as possible. The button must be the one that corresponds to the number of blinks. If the wrong button is pressed, time keeps running and the user must try another button, etc. until the good one is pressed.
  • The time between the last blink and the push on the good button is measured and printed on Serial,  and the LED is lighted for 200ms to warn the user he must stop using the controller.
  • Then, after 5 seconds, the LED blinks again, etc.
What must be done :
  • Install the IRremote library that allows to easily manage an IR Receiver. For that, :
  • Create a new sketch, starting by just reading which button of the controller is pressed.
  • Then, modify the sketch according to the behavior exposed above.

Advice :

  • before fulfilling the whole sketch, you have to identify the code of each button 2, 3, 4, ..., 9 of the IR remote controller.
  • as in the previous exercise, it is useful to rely on an application state variable.

Exercise #5: testing reflexes - part III
 
Working principles:
  • At boot, LED is off.
  • After 5 seconds, the LED must blink between 3 and 6 times. The gap between blinks is 500ms. The last blink lasts for 1sec and the others 500ms, so that the user knows when the sequence ends.
  • Then the user must gently hit on a piezo-electric sensor as many times as the LED blinked, and as fast as possible.
  • The time between the last blink and the last hit is measured and printed on Serial, and the LED is lighted for 200ms to warn the user he must stop hitting the piezo.
  • Then, after 5 seconds, the LED blinks again, etc.

NB : a piezo-electric sensor is able to deliver a variable current and voltage under pressure, vibrations, ... This voltage can be read on a analog input of a µC.

What must be done :
  • Create a new sketch by copying the code of the previous exercise.
  • Then, modify the sketch according to the behavior exposed above.

Advice :

  • as in the previous exercise, it is useful to rely on an application state variable.
  • when state = 1, the sketch must read an analog value on pin A0, ranging from 0 to 1023. The stronger the hit on the piezo, the higher the value, but reading value above 200 is sufficient to detect a hit.
  • BEWARE : consecutive readings on A0 must be separated by at least 3ms or the µC will crash.
  • Problem : if reading every 3ms, it gives a sequence of values above 200 for a single hit. Thus, after reading value above 200, the µC should wait a bit so that the piezo stops delivering current. You have to test different values to be sure to differentiate the hits on the piezo, without missing one. 

Exercise #6: testing coordination & memory - part IV
 
Working principles:
  • At boot, LED is off.
  • After 5 seconds, the LED must blink between 3 and 6 times (at random). The blinks AND the duration between is 300ms. After this first sequence, the µC waits for 1 second.
  • Then, the LED must blink again between 3 and 6 times (at random). The blinks AND the duration between is 300ms. After this second sequence, the µC waits for 1 second.
  • Then the LED blinks between 1 and 3 times (at random). The gap between blinks is 500ms. The last blink lasts for 1sec and the others 500ms, so that the user knows when the sequence ends.
  • According to the number of blinks in the last sequence, the user must work in a different "mode" :
    • 1 blink -> push the button and hit the piezo alternatively, starting by the button. The button must be pressed as many time as the number of blinks in the first sequence, and the piezo hit as in the second sequence.
    • 2 blinks -> hit the piezo and push the button alternatively, starting by the piezo. The piezo must be hit as many time as the number of blinks in the first sequence, and the button pushed as in the second sequence.
    • 3 blinks  -> just use the IR remote controller. The total number of blinks, this ranging from 6 to 12 must be typed with the IR remote controller (using two buttons if total >= 10).
  • NB: if user make a mistake, like pushing several times the button before hitting the piezo, it must not cause an error and mistakes are just ignored.
  • The reaction time is measured and print, as in the previous parts.
What must be done :
  • Create a new sketch by copying parts of the previous exercises.
  • Then, modify the sketch according to the behavior exposed above.

Advice :

  • as in the previous exercises, it is useful to rely on an application state variable. But this time, there are more than 2 states to define: there should be a state for each source of acquisition (button, piezo, IR) that can be used.
  • it is also useful to define boolean variables to represent the fact that :
    • user pushed and release the button just once,
    • user hit the piezo just once,
    • user  pushed/released the button the good number of times,
    • user hit the button the good number of times,