In this curse we are going to learn programming in C (C++) language while having great fun with a physical hardware. We learn to use industry standard programming tool Visual Studio Code, and get involved to physical programming with Adafruit Circuit Playground Express developer board (by utilizing PlaformIO and Arduino).
Requirements
- Knowledge
- Ability to use computer: open/save a file
- Basic typing skills
- Basic mathematics with multiply and divide
- Hardware
- Computer (Linux, Windows or Mac)
- Visual Studio code installed on the computer (Windows also requires drivers to be installed)
- Adafruit Circuit Playground Express developer board.
- Flashlight (phone with flashlight can be also good)
Season 1
Lesson 0
Scope: Set up Visual Studio Code
- In VSCode open Preferences/Extensions, install extension “PlatformIO IDE”.
- Installation + Quick start guide: https://docs.platformio.org/en/latest/integration/ide/vscode.html
- Go to PlatformIO Home (House icon on the toolbar), select New Project
- Name: “01_blink”,
- Board: “Adafruit Circuit Playground Express” (“Circuit Playground Bluefruit” for blue board)
- Location: Use default location
- What is “default location”? ($HOME/Documents/PlatformIO/Projects/ )
- Explore project
- File: src/main.cpp
- File: platformio.ini
- Build project with check-mark icon on the toolbar!
Lesson 1
Scope: Start using VSCode with PlatformIO, Blink example, and creating methods
“Every great project is starting up by blinking of an LED”
- What is Arduino? Infrastructure based on:
- (compatible) Hardware
- (IDE – We don’t use it)
- “Possibility” of easy upload (boot loader)
- PlatformIO makes Arduino professional (platformio.ini)
- Open VSCode – What is an IDE? Text program -> compile -> upload to device. (Syntax highlight, code format, shows errors, refactoring, debugging, etc.)
- Open project created last time “01_Blink”.
- Type into main.cpp:
#include <Arduino.h> // This part will be launched on startup. void setup() { pinMode(LED_BUILTIN, OUTPUT); } // This part will be repeated again and again. void loop() { digitalWrite(LED_BUILTIN, HIGH); delay(1000); digitalWrite(LED_BUILTIN, LOW); delay(1000); }
- Build (with check-mark on the toolbar)
- Connect hardware, press Reset 2 times on the device
- Upload (with the right pointing arrow on the toolbar)
- Inspect the code
- #include
- Remarks:
// /* ignored blocks */
- code blocks
- setup / loop methods
- { } blocks
- Sequence processing
- 3 method calls: pinMode(), digitalWrite(), delay()
- Pre-defined values: HIGH, LOW
- Delay waits for milliseconds. 1 second is 1000 milliseconds.
- How to get help:
- Reference: https://www.arduino.cc/reference/en/
- Examples: (Not available in PlatformIO 🙁 )
- Modify code to have different timings. And add patterns. (Use Copy/Paste.) E.g.:
void loop() { digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); delay(100); digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); delay(3000); }
- Press Reset 2 times on the board and Upload from the toolbar.
- Introduce a new method (aka. function). Type it above “loop()”! Note, that the body of the loop method can be reused here. (Cut-Paste)
void blinkOne() { digitalWrite(13, HIGH); delay(100); digitalWrite(13, LOW); delay(100); }
- Modify loop:
void loop() { blinkOne(); blinkOne(); blinkOne(); delay(2000); }
- Press Reset 2 times on the board and Upload from the toolbar.
- Understand how we reused our existing code, to be called multiple times.
- Understand the workflow of our program.
- Modify blinkOne:
void blinkOne(int onFor) { digitalWrite(13, HIGH); delay(onFor); digitalWrite(13, LOW); delay(300); }
- Modify loop:
void loop() { blinkOne(200); blinkOne(200); blinkOne(1000); delay(2000); }
- Upload (Don’t forget the double-reset!)
- Understand the method arguments used to customize our program. (aka. signature)
Home work: play around with other blink patterns.
Keywords learned
- setup, loop, pinMode, digitalWrite, delay, HIGH, LOW, LED_BUILTIN
Lesson 2
Scope: Get know our Adafruit Circuit Playground hardware
- What is on the board: buttons, pads, LEDs, etc.
- https://learn.adafruit.com/adafruit-circuit-playground-express/guided-tour
- Also check the schematics: https://cdn-learn.adafruit.com/assets/assets/000/049/671/original/makecode_schem.png?1514316401
- Adafruit also provided us a helper “library”. Library is a collection of pre-implemented methods, defines, etc.
- This library is “open source”, meaning you are free to check the source code of it and learn from it. (Or maybe modify, fix errors, etc.) The source code is available on GitHub: https://github.com/adafruit/Adafruit_CircuitPlayground
- Open “01_blink” from previous lesson in VSCode.
- Use File/Save workspace as…
- Use name “learn_programming”
- Question from Lession 0:
- What is “default location”? ($HOME/Documents/PlatformIO/Projects/ )
- Find this location with a file browser. In Visual Studio Code right click on “01_blink” click on menu item Reveal in Finder (MacOS) / Open in Explorer (Windows) / Open in File browser? (Linix)
- Duplicate project “01_blink”, so we have a new project “02_neopixel”
- How to duplicate with file browser? (OS specific)
- Go back to Visual Studio Code
- Use File/Add Folder to Workspace
- Choose “02_neopixel”, one just have created with duplication
- Inspect Explorer window of VSCode screen: now we have two projects
- Close project “01_blink” and open project “02_neopixel” in the Explorer tree. So, not to be confused further on.
- Open src/main.cpp in 02_neopixel project
- Inspect Toolbar containing option “Default (02_neopixel)”
- To use Adafruit helper library we must modify our platformio.ini . Open platformio.ini, and perform highlighted modifications.
[env:adafruit_circuitplayground_m0] platform = atmelsam board = adafruit_circuitplayground_m0 framework = arduino lib_deps = adafruit/Adafruit Circuit Playground@^1.11.3 SPI
- Modify src/main.cpp as follows. Add new header entry, modify setup(), modify blinkOne()
#include <Arduino.h> #include <Adafruit_CircuitPlayground.h> void setup() { CircuitPlayground.begin(); } void blinkOne(int onFor) { CircuitPlayground.setPixelColor(0, 20, 60, 10); delay(onFor); CircuitPlayground.clearPixels(); delay(1000); } void loop() { blinkOne(200); blinkOne(200); blinkOne(1000); delay(2000); }
- Upload code.
- Get help on method setPixelColor() by moving the mouse cursor over it.
- RGB Color – 3 arguments light level of Red, Green, Blue colors. Light intensity levels can be set between 0 and 255.
- Set color to 20, 20, 20
- Upload code. Note the separate colors within one LED.
- Modify code as follows. Method arguments (signature) of blinkOne is changed:
#include <Arduino.h> #include <Adafruit_CircuitPlayground.h> void setup() { CircuitPlayground.begin(); } void blinkOne(int pixel, int red, int green, int blue) { CircuitPlayground.setPixelColor(pixel, red, green, blue); delay(200); CircuitPlayground.clearPixels(); } void loop() { blinkOne(0, 255, 0, 0); blinkOne(1, 0, 255, 0); blinkOne(2, 0, 0, 255); blinkOne(3, 200, 100, 50); blinkOne(4, 20, 20, 20); blinkOne(5, 100, 100, 100); blinkOne(6, 100, 255, 100); blinkOne(7, 255, 255, 0); blinkOne(8, 0, 255, 255); blinkOne(9, 255, 0, 255); }
- Upload!
- Homework: Try different colors, mix up pixel order.
Learned today:
- Navigating within explorer, basic file manipulation.
- RGB
Lession 3
Scope: Variables, defines, serial communication, Data types, Voltages (HIGH, LOW)
- On which pin is “Light Sensor” connected? (See schematic: https://cdn-learn.adafruit.com/assets/assets/000/031/914/original/circuit_playground_schem.png?1461348465)
- Create new project PlatformIO “03_analog”. (PlatformIO home, New Project, Board: Adafruite Playground Express)
- Note that new project is added to the workspace after “02_neopixel”.
- Type in:
#include <Arduino.h> #define SENSOR_PIN A8 int sensorValue = 0; void setup() { Serial.begin(9600); } void loop() { sensorValue = analogRead(SENSOR_PIN); Serial.println(sensorValue); delay(1000); }
- Build/Upload (Double reset and upload)
- Place the circuit in a darker spot, and spot the flashlight onto the sensor.
- Open serial monitor (Check quick start guide of PlatformIO at Lesson 0)!
- Inspect text arrives from Arduino while moving the flashlight. Write down minimum and maximum values observed!
- Close terminal with key combination: “CTRL-C” (Choose terminal window content by clicking into the window before CTRL-C)
- Inspect “int sensorValue”
- Storing value in this variable. “variable” means storage, where stored value might change over the life-cycle of the program.
- “int” – type
- Global and local variables: sensorValue can be moved inside the “loop”.
- Initialization value
- What data types does Arduino (C programming language) provide? (See reference!)
- void, boolean
- char, unsigned char, byte (one byte) (actually boolean is a byte)
- int, unsigned int, short
- long, unsigned long
- float, double
- word
- Let’s do some maths and use float numbers. Modify code as shown:
void loop() { sensorValue = analogRead(SENSOR_PIN); float valPercent = (float)sensorValue / 1024 * 100; Serial.println(valPercent); delay(500); }
- Upload and check serial monitor.
- What is analog value?
- Electric potential (volts) measured on the pin
- What is electric potential?
- Digital values (HIGH, LOW)
- ADC, reference voltage
- Voltage level is here returned in a value between 0 and 1023
Keywords learned
- analogRead, variable declaration, (data types), Serial.println
Lesson 4
Scope: Music instrument [conditions, control structures, physics of voices]
- Create new project named “04_on_off”
- Type in (might want to reuse previous code):
#include <Arduino.h> #define SENSOR_PIN A8 int sensorValue = 0; void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { sensorValue = analogRead(SENSOR_PIN); if (sensorValue < 500) { digitalWrite(LED_BUILTIN, HIGH); } else { digitalWrite(LED_BUILTIN, LOW); } }
- What does this code about to do?
- Upload and test it!
- Inspect “if”, after the if word we have a “condition”. Condition in an expression that results true or false.
- In the conditions we usualy use “Comparison Operators” combined by “Boolean Operators” with brackets. What is this means?
- Comparison Operators: <, >, <=, >=, ==, != (== and = are not the same!)
- Boolean Operators: && (means and), || (means or)
- E.g. if ((sensorValue < 500) || (sensorValue > 800))
- Complicated logic can be built
- Open file browser and duplicate (copy-paste) project “04_on_off” so we have a new directory called “05_instrument”.
- Add this new project to our workspace.
- Modify src/main.cpp according to this:
#include <Arduino.h> #define SENSOR_PIN A8 #define OUT_PIN LED_BUILTIN int sensorValue = 0; void setup() { pinMode(OUT_PIN, OUTPUT); } void loop() { sensorValue = analogRead(SENSOR_PIN); digitalWrite(OUT_PIN, HIGH); delay(sensorValue); digitalWrite(OUT_PIN, LOW); delay(sensorValue); }
- What does this code about to do? Upload and inspect!
- Turns LED on/off with different delays.
- Note, that rapid blinking we do not recognize. LED seams to have the same dim level (after we cannot see it blinking).
- Check board schematic for “Speaker”!
- Change the OUT_PIN from LED_BUILTIN to A0
- We can observe the sound changing
- Double reset to mute speaker!
- Let’s do some math! What minimum and maximum analog values did we wrote down?
- Minimum value = 10
- so a full on-off cycle is 2 x delay(10) in the code,
- it takes 20 milliseconds (what is 0.02 seconds).
- audio voice tone (frequency) is measured in Hertz, what says “how many cycles are in 1 second”.
- 1 second is 1000 millisecond, the 20ms cycle occurs 50 times in one seconds, that is 50Hz. (or 1/0.02s = 50Hz)
- We need an instrument with tones between 200-500Hz
- TODO: make it more clear!
- Minimum delay per cycle should be 1sec/500 = 0.002 second, that is 2 milliseconds, what is 2000 microseconds. We have two delays per cycle, so we need to divide this into to, so 2×1000.
- The maximum should be 1sec/200=0.005 that is 500 milliseconds, what is 2×2500 microseconds.
- Minimum value = 10
- We need to delay microseconds instead of milliseconds,
- We need to map our sensed values to this 1000-2500 range.
- So let’s modify our code like this:
#include <Arduino.h> #define SENSOR_PIN A8 #define OUT_PIN A0 int sensorValue = 0; void setup() { pinMode(OUT_PIN, OUTPUT); } void loop() { sensorValue = analogRead(SENSOR_PIN); int mappedValue = map(sensorValue, 10, 1000, 1000, 2500); digitalWrite(OUT_PIN, HIGH); delayMicroseconds(mappedValue); digitalWrite(OUT_PIN, LOW); delayMicroseconds(mappedValue); }
- Upload!
- Use flashlight to play on the instrument.
- Double reset to mute!
Home work: make a way to mute speakers, when instrument is not in use. Use the learned if + condition statement!
References:
- https://en.wikipedia.org/wiki/Hertz
- https://en.wikipedia.org/wiki/Piano_key_frequencies
Keywords learned
- if, operators, delayMicroseconds
Lession 5
Scope: loops, arithmetic operators, pwm
- Check homework: Previous code modifies with something like this.
#include <Arduino.h> #define SENSOR_PIN A8 #define OUT_PIN A0 int sensorValue = 0; void setup() { pinMode(OUT_PIN, OUTPUT); } void loop() { sensorValue = analogRead(SENSOR_PIN); if (sensorValue > 20) { int mappedValue = map(sensorValue, 10, 1000, 1000, 2500); digitalWrite(OUT_PIN, HIGH); delayMicoseconds(mappedValue); digitalWrite(OUT_PIN, LOW); delayMicoseconds(mappedValue); } }
- The condition is “sensorValue > 20”
- Create a new project with name “06_loops”
- Copy platformio.ini changes from project “02_neopixel”
- Type into src/main.cpp:
#include <Arduino.h> #include <Adafruit_CircuitPlayground.h> void setup() { CircuitPlayground.begin(); } void loop() { int i = 0; while (i < 10) { CircuitPlayground.setPixelColor(i, 20, 10, 25); delay(1000); i = i + 1; } delay(3000); CircuitPlayground.clearPixels(); }
- Upload.
- In variable
i
we store a value that is calculated by the previous value ofi
. - Instead
i = i + 1
, typei += 1
- Instead
i += 1
typei++
- These are all the same.
- Of course can do any kind of arithmetic operations: +, -, *, /, and use ()
- We can use +=, -=, *=, /= if the previous value of the variable is involved.
- We have the i++, i–, ++i, –i special forms.
while(
is the loop. It repeats the block inside while the given condition is true. In this case the i < 20 was true until i reached the value 20, and than the inside block was not executed any more.) { } - Modify the code as follows:
#include <Arduino.h> #include <Adafruit_CircuitPlayground.h> void setup() { CircuitPlayground.begin(); } void loop() { for (int i = 0; i < 10; i++) { CircuitPlayground.setPixelColor(i, 20, 10, 25); delay(1000); } delay(3000); CircuitPlayground.clearPixels(); }
- This does the same. for is a very common way to do iteration on, when we know the limits.
- for used when we know the limits, while is used when we are unsure how many times to repeat.
- Loop control keywords:
continure
– continues the loop with the next item (if there is any)break
– exit from the loop
- Open file browser and duplicate (copy-paste) project “04_on_off” so we have a new directory called “07_pwm”.
- Modify the code as follows:
#include <Arduino.h> #define SENSOR_PIN A8 int sensorValue = 0; void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { sensorValue = analogRead(SENSOR_PIN); digitalWrite(LED_BUILTIN, LOW); for (int i = 0; i < 1024; i++) { if (i == sensorValue) { digitalWrite(LED_BUILTIN, HIGH); Serial.println(i); } delayMicroseconds(10); } }
- Analyze the code! What do we expect to happen?
- Upload and test
- The LED blinks so rapidly, that we see a smooth dim instead.
- We are playing with the on and off state times withing a cycle.
- We call this PWM (Pulse Width Modulation)
- On/Off = Duty cycle
- Generally used for dimming and motor speed control (DC motor)
- Replace loop as follows:
void loop() { sensorValue = analogRead(SENSOR_PIN); int mappedValue = map(sensorValue, 0, 1024, 255, 0); analogWrite(LED_BUILTIN, mappedValue); }
- Arduino has a built in function called analogWrite(), but
- it is not available for any output pins
- know how fast a cycle is?
TODO: would be nice to demonstrate it on a DC motor
References:
- https://www.arduino.cc/en/Tutorial/PWM
Home work: in 06_loops modify loop to have different patterns. E.g. count down, lit up every second LEDs.
Keywords learned
- while, for, analogWrite, arithmetic operators (+, -, etc.)
- PWM
Lesson 6
Scope: Arrays, Tone player,
- Create a new project called 08_tone_player
- Type the following code:
#include <Arduino.h> #define BUZZER A0 #define ONE_SECOND_IN_MICROS 1000000.0 float toneC4 = 261; // Frequency of tone C4 in Hz (Hz is 1/sec) void playTone(float freq, int length) { } void setup() { pinMode(BUZZER, OUTPUT); } void loop() { float waveTimeMicros = ONE_SECOND_IN_MICROS / toneC4; int count = toneC4; for(int i=0; i < count; i++) { digitalWrite(BUZZER, HIGH); delayMicroseconds(waveTimeMicros / 2); digitalWrite(BUZZER, LOW); delayMicroseconds(waveTimeMicros / 2); } delay(4000); }
- Inspect the code
- We want to play the tone “middle C”, the frequency of that is 261.63 (https://en.wikipedia.org/wiki/Piano_key_frequencies)
- 261 Hz means turns on/off 261 times within a second.
- The wave time is 1/261 second
- 1 second is 1.000.000 microsecond
- The wave time is 1.000.000 / 261 microsecond
- The ON and one OFF periods adds up to the wave time
- To have it played for one second we have to repeat this wave segment for 261 times. This is the
for
cycle about. - Now introduce a method called playTone
- This method will have a parameter: the tone frequency to be played.
- Modify the code as follows:
#include <Arduino.h> #define BUZZER A0 #define ONE_SECOND_IN_MICROS 1000000.0 float toneC4 = 261.63; // Frequency of tone C4 in Hz (Hz is 1/sec) float toneE4 = 329.62; float toneA4 = 391.00; void setup() { pinMode(BUZZER, OUTPUT); } void playTone(float freq) { float waveTimeMicros = ONE_SECOND_IN_MICROS / freq; int count = freq; for(int i=0; i < count; i++) { digitalWrite(BUZZER, HIGH); delayMicroseconds(waveTimeMicros / 2); digitalWrite(BUZZER, LOW); delayMicroseconds(waveTimeMicros / 2); } } void loop() { playTone(toneC4); playTone(toneE4); playTone(toneA4); delay(4000); }
- Note, that Arduino actually have a tone player method just like that built in:
tone(BUZZER, toneC4);
- It would be great to have some list to store more notes…
- Now let’s learn arrays. Modify code as follows:
#include <Arduino.h> #define BUZZER A0 #define ONE_SECOND_IN_MICROS 1000000.0 float tones[] = { 261.63, 329.62, 261.63, 329.62, 391.00, 391.00 }; void setup() { pinMode(BUZZER, OUTPUT); } void playTone(float freq) { float waveTimeMicros = ONE_SECOND_IN_MICROS / freq; int count = freq; for(int i=0; i < count; i++) { digitalWrite(BUZZER, HIGH); delayMicroseconds(waveTimeMicros / 2); digitalWrite(BUZZER, LOW); delayMicroseconds(waveTimeMicros / 2); } } void loop() { for (int i = 0; i < 6; i++) { playTone(tones[i]); } delay(4000); }
- Array is always a list containing items of the same type. In the example above the type is
float
. The array is marked with brackets[]
. - Items of the array can be pre-defined within brackets { } followed by the declaration.
- (There can be fixed size of arrays where items are filled later on.)
- Note that the first item of the array is referenced as item0 (zero)
- The length of the array in the case above is 6, and the index of the items are from 0 (zero) up to 5.
- Add length for notes, and place some small gap between tones.
- We can also determine the length of an array with
sizeof()
#include <Arduino.h> #define BUZZER A0 #define ONE_SECOND_IN_MICROS 1000000.0 float tones[] = { 261.63, 329.62, 261.63, 329.62, 391.00, 391.00 }; int lengths[] = { 1, 1, 1, 1, 2, 2 }; void setup() { pinMode(BUZZER, OUTPUT); } void playTone(float freq, int length) { float waveTimeMicros = ONE_SECOND_IN_MICROS / freq; int count = length * freq / 2; for(int i=0; i < count; i++) { digitalWrite(BUZZER, HIGH); delayMicroseconds(waveTimeMicros / 2); digitalWrite(BUZZER, LOW); delayMicroseconds(waveTimeMicros / 2); } delay(4); } void loop() { for (int i = 0; i < (sizeof(tones) / sizeof(float)); i++) { playTone(tones[i], lengths[i]); } delay(4000); }
Keywords learned
- arrays
Lesson 7
Scope: Strings
- Text in the code is called a string. Special notation. E.g. “fly”
- String is an array consists of characters. E.g. The string “fly” is an array like this [‘f’, ‘l’, ‘y’, ‘\0’]
- There is also a terminal character noted with ‘\0’
- This way, the string “fly” has a length = 3, but the space required for it with the terminator is 4 bytes.
- Char is an unsigned integer type from -128 to 127, we usually cast it to byte, that is the unsigned from of that.
- There are some handful string helper method for provided by the C language:
- strlen()
- strcmp()
- strcpy(), strncpy()
- etc.
- Type in the following code:
#include <Arduino.h> char line[] = "fly"; void setup() { Serial.begin(9800); } void loop() { for (int i = 0; i < strlen(line); i++) { Serial.print(line[i]); Serial.print(" - "); Serial.println((byte)line[i]); } delay(5000); }
- Upload an open terminal
- Characters of the string are displayed both in character and integer (ASCII) codes.
- https://www.asciitable.com/
- e.g. character code of space is 32, this is the first visible character in the ASCII table.
- Note the capital and lower case letters.
- Modify the code to read input from the console:
#include <Arduino.h> #define LINE_LENGTH 128 char line[LINE_LENGTH]; void setup() { Serial.begin(9800); Serial.setTimeout(10); } void readLine() { while (!Serial.available()) { delay(1); } Serial.readBytes(line, LINE_LENGTH); for (int i=0; i < strlen(line); i++) { if (line[i] < 32) { line[i] = '\0'; break; } } } void loop() { Serial.print("> "); readLine(); for (int i = 0; i < strlen(line); i++) { Serial.print(line[i]); Serial.print(" = "); Serial.println((byte)line[i]); } }
- Method readLine() appears and loop is modified accordingly.
- Also need to modify platformio.ini as follows:
[env:adafruit_circuitplayground_m0] platform = atmelsam board = adafruit_circuitplayground_m0 framework = arduino monitor_filters = send_on_enter printable monitor_flags = --echo
- Upload and open monitor. Press enter and type some words, send it with Enter key
- The text is sent to the microcontroller that processed it
- We can also find some helper methods to read from serial: https://www.arduino.cc/reference/en/language/functions/communication/stream/
Lesson 8
Scope: Infra red light, communication
Prepare for this lesson with:
- At least one remote control unit (TV remote)
- Two APC boards
- A comb
- What is infrared light?
- Inspect TV remote control light with phone camera.
- Duplicate project “02_neopixel” so we have a new project called “10_infra_receive”
- Infrared input port is D12, but it is not defined, we have to use CPLAY_IR_RECEIVER definition instead.
- Type in the following code:
#include <Arduino.h> #include <Adafruit_CircuitPlayground.h> #define IR_IN CPLAY_IR_RECEIVER void setup() { CircuitPlayground.begin(); pinMode(IR_IN, INPUT); } void loop() { int level = digitalRead(IR_IN); digitalWrite(CPLAY_BUZZER, level); }
- Upload
- Point a remote controller to the board, you hear buzzing. We have converted the light signal to audio.
- Try pointing the remote to some walls and experiment the voice.
- Modify IR_IN the code as follows:
//#define IR_IN CPLAY_IR_RECEIVER #define IR_IN A10
- Upload
- This is the “non-amplified” IR signal.
- Duplicate project, so we have a new project with name “11_infra_sender”
- Modify buzzer definition as follows:
#define BUZZER 25
- Upload
- With a phone camera you can see, that board is playing the tones “on the” infra LED.
- We need boards. On one you should upload the project 10_infra_receive on the other the 11_infra_sender
- Now music is transferred via IR. The first unit plays back what the second sends to it.
- Try to block the path of the light
- Try using movements that distorts the light. E.g. move a comb between the two boards.