Networking & Communications¶
Back to electronics đ
For this week we have to communicate via wired connections, and wireless connections.
Wired Communication¶
Wired connections, (including but not limited to USB, HDMI, and GPIO pins), provide a reliable communication method between a board and external devices or networks. By making tasks like programming, debugging, and interfacing with peripherals much easier, wired connections can help a lot when you’re working on a project.
I2C Communication¶
For this week, I decided to explore I2C communication, especially because my microcontroller has limited pins, and because all of my components have the I2C option.
What is I2C?
I2C (Inter-Integrated Circuit) is a serial communication protocol commonly used to connect microcontrollers, sensors, and other integrated circuits. It allows multiple devices to communicate with each other using just two wires, a clock line (SCL) for synchronization and a data line (SDA) for transmitting information.
- Google.com
But before I could do anything with my board or components, I needed to understand addresses.
Addresses
In I2C communication, each component on the bus is assigned a unique address, typically 7 bits long, allowing for up to 128 different addresses. Devices may have fixed addresses or configurable ones, usually set through address pins, enabling multiple devices to coexist on the same bus without conflict. To find out the addresses of the components Iâm using this week, hereâs what I did.
I started off by connecting an SSD1306 OLED Display and an I2C Standard LCD 20x4 to an Arduino board as shown.
!
Then I went online for a code to run, and I came across this really useful website. From there, I found a code that can scan your I2C devices, their addresses, and it doesnât need any libraries đ. This is the code that I ran:
// SPDX-FileCopyrightText: 2023 Carter Nelson for Adafruit Industries
//
// SPDX-License-Identifier: MIT
// --------------------------------------
// i2c_scanner
//
// Modified from https://playground.arduino.cc/Main/I2cScanner/
// --------------------------------------
#include <Wire.h>
// Set I2C bus to use: Wire, Wire1, etc.
#define WIRE Wire
void setup() {
WIRE.begin();
Serial.begin(9600);
while (!Serial)
delay(10);
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
WIRE.beginTransmission(address);
error = WIRE.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}
After running that code, this is the output that I got on my serial monitor:
Now we know that my OLED address is 0x3C, and that my LCD address is 0x27.
Wired Display Using I2C¶
So now that I had my addresses, I could finally start coding!
ChatGPT helped me come up with a basic code to run both devices at once! However, I decided to download some libraries first:
Adafruit_SSD1306.h
To program an SSD1306 OLED Display, download the following libraries on your Arduino IDE.
LiquidCrystal_I2C.h To download the LiquidCrystal_I2C.h library, check out this page, and then follow along.
Once the ZIP file has downloaded, open up your Arduino IDE, and then go to Sketch>Include Library> Add .ZIP LibraryâŚ
Then, open your .ZIP file location and then select it!
Now weâre done with installing all the libraries we need !!! After giving ChatGPT the following prompt:
Please provide a detailed example illustrating the integration of both an LCD display and an OLED display with an Arduino board. Specify the necessary libraries ('Wire.h', 'LiquidCrystal_I2C.h', 'Adafruit_GFX.h', 'Adafruit_SSD1306.h'), define constants for the displays' addresses, sizes, and reset pins. Additionally, explain the usage of functions such as 'lcd.backlight()', 'display.begin()', 'display.clearDisplay()', 'display.setTextSize()', 'display.setTextColor()', 'display.setCursor()', 'display.println()', 'display.display()', 'lcd.clear()', and 'lcd.print()'. The goal is to create a comprehensive guide for utilizing both LCD and OLED displays in an Arduino project.
Hereâs the output I got:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// LCD settings
#define LCD_ADDRESS 0x27
#define LCD_COLS 20
#define LCD_ROWS 4
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLS, LCD_ROWS);
// OLED settings
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define OLED_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
// Initialize the LCD
lcd.backlight();
// Initialize the OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
for (;;); // Don't proceed, loop forever
}
}
void loop() {
// Display "TWD" on OLED and "wow" on LCD
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("TWD");
display.display();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("wow");
delay(2000);
// Display "wow" on OLED and "TWD" on LCD
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("wow");
display.display();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("TWD");
delay(2000);
}
I just wanted to see if the LCD was functional or not, so this code just displays random characters on the screen.
Hereâs the result:
Once it worked, I decided to replace the Arduino Uno board with my development board, so I connected the GPIO pins accordingly, and it worked !!!
Wireless Communication¶
Wireless communication refers to the transmission of data between devices without the need for physical cables or wires. It uses electromagnetic waves, such as radio frequencies, infrared, or microwaves, to transmit information over the air, allowing mobility and flexibility in applications such as Wi-Fi, Bluetooth, and cellular networks.
For this week, I decided to use the board I made in week 9 to host a webserver, access that webserver on my computer, and communicate with the development board itself (specifically the LEDâs)
XIAO ESP32 C3 Webserver¶
Before we start off anything, youâre going to need a Bluetooth/WiFi antenna.
They usually come with your XIAO ESP32 C3, but you can find tonnes of them online incase you donât have one. Just search up âBluetooth antenna for XIAO ESP32 C3â.
Once you have your antenna connected, youâre good to go.
I didnât really know where to start, so I went to the official page for my microcontroller, and they had exactly what I needed for this week!
Scanning for WiFi (Station Mode)
For some practice, I decided to follow along with whatever the website had, and so, I started by connecting my board to a WiFi network.
#include "WiFi.h"
void setup()
{
Serial.begin(115200);
// Set WiFi to station mode and disconnect from an AP if it was previously connected
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.println("Setup done");
}
void loop()
{
Serial.println("scan start");
// WiFi.scanNetworks will return the number of networks found
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
delay(10);
}
}
Serial.println("");
// Wait a bit before scanning again
delay(5000);
}
Once youâve uploaded this code, open your serial monitor to see what connections are nearby!
Connecting to WiFi
Now, itâs time to connect to a WiFi network! Remember, you need to know the name and password in order to do this !!!
#include <WiFi.h>
const char* ssid = "your-ssid";
const char* password = "your-password";
void setup()
{
Serial.begin(115200);
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop()
{
}
If youâve connected successfully, the serial monitor should look something like this:
Webserver
Finally, itâs time to host a webserver. I did some research online and then I consulted ChatGPT for the code. After asking ChatGPT the following:
Could you write acode to create a web server using the Xiao ESP32-C3 microcontroller board. The web server should serve a web page accessible over Wi-Fi, allowing users to control two LEDs connected to the board.
Set up the necessary connections:
1. Connect two LEDs to GPIO pins on the Xiao ESP32-C3 board. Use pin 2 for LED 1 and pin 5 for LED 2.
Connect the Xiao ESP32-C3 board to a Wi-Fi network using the provided SSID and password.
Implement the web server functionality:
Initialize the web server on port 80.
2. Create an HTML page with two sections: one for controlling LED 1 and another for controlling LED 2.
Each section should contain two buttons: one to turn the corresponding LED on and another to turn it off.
Use inline JavaScript (fetch API) to send requests to the server when buttons are clicked.
3. Define routes for handling HTTP requests:
Define a route for the root path ('/') to serve the HTML page.
Implement separate routes for turning each LED on and off ("/on1", "/off1", "/on2", "/off2").
4. When a request is received to turn an LED on, set the corresponding GPIO pin high. When turning it off, set the pin low.
Respond to the client with a success message indicating the state change.
Ensure proper error handling and feedback:
5. Print status messages to the Serial monitor for debugging purposes.
Handle cases where the Wi-Fi connection fails or the server encounters errors gracefully.
Test the functionality:
Upload the code to the Xiao ESP32-C3 board.
6. Verify that the board successfully connects to the Wi-Fi network.
Open a web browser on a device connected to the same network and navigate to the IP address of the Xiao ESP32-C3 board.
Test each button on the web page to ensure that it correctly toggles the corresponding LED on and off.
Note: Make sure to include any necessary library dependencies and ensure compatibility with the Xiao ESP32-C3 board, thanks.
After that, I got the following code:
#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "your-ssid";
const char* password = "your-password";
WebServer server(80);
const int ledPin1 = 2; // GPIO pin for LED 1
const int ledPin2 = 5; // GPIO pin for LED 2
void setup() {
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
// Initialize Serial port
Serial.begin(115200);
// Connect to Wi-Fi network
Serial.println();
Serial.println("Connecting to Wi-Fi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// HTML for the web page
String html = "<html><head><style>";
html += "body { font-family: Arial, sans-serif; background-color: #957dad; color: #ffffff; margin: 0; padding: 0; }";
html += "h1 { text-align: center; margin-top: 50px; }";
html += "h2 { text-align: center; }";
html += "button { display: block; margin: 20px auto; padding: 10px 20px; font-size: 18px; background-color: #5e5874; border: none; border-radius: 5px; color: #ffffff; cursor: pointer; }";
html += "button:hover { background-color: #7d75a2; }";
html += "</style></head><body>";
html += "<h1>ESP32 Web Server</h1>";
html += "<h2>HELLO LED</h2>";
html += "<button onclick=\"fetch('/on1')\">Turn On</button>";
html += "<button onclick=\"fetch('/off1')\">Turn Off</button>";
html += "<h2>LED 2</h2>";
html += "<button onclick=\"fetch('/on2')\">Turn On</button>";
html += "<button onclick=\"fetch('/off2')\">Turn Off</button>";
html += "</body></html>";
// Route for root / web page
server.on("/", HTTP_GET, [html](){
server.send(200, "text/html", html);
});
// Route to handle turning LED 1 on
server.on("/on1", HTTP_GET, [](){
digitalWrite(ledPin1, HIGH);
server.send(200, "text/plain", "LED 1 turned on");
});
// Route to handle turning LED 1 off
server.on("/off1", HTTP_GET, [](){
digitalWrite(ledPin1, LOW);
server.send(200, "text/plain", "LED 1 turned off");
});
// Route to handle turning LED 2 on
server.on("/on2", HTTP_GET, [](){
digitalWrite(ledPin2, HIGH);
server.send(200, "text/plain", "LED 2 turned on");
});
// Route to handle turning LED 2 off
server.on("/off2", HTTP_GET, [](){
digitalWrite(ledPin2, LOW);
server.send(200, "text/plain", "LED 2 turned off");
});
// Start server
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
}
Explanation¶
Hereâs a brief explanation of how the code works:
Wi-Fi Connection
The setup
function initializes the serial communication for debugging and connects to a Wi-Fi network using the SSID and passwordbthat you give it. It then prints the IP address on your serial monitor once connected.
Web Server Setup
A web server object (server
) is created to listen for HTTP requests on port 80. HTML and CSS code is used to create a web page with buttons to control the LEDs.
Routes Definition
There’s a lot of routes that are defined for handling HTTP GET requests:
- The root route (
/
) serves the HTML page. - Routes
/on1
and/off1
control the first LED, turning it on and off respectively. - Routes
/on2
and/off2
control the second LED in a similar manner.
Handling Requests
In the loop
function, server.handleClient()
processes incoming HTTP requests and executes the corresponding route handlers, which turn the LEDs on or off and send a plain text response.
Once I uploaded and ran this code, I opened the serial monitor, and pasted the IP in there into google. The webserver worked !!!
Hereâs a basic UI of the server, as well as a video that shows how it works:
Problem #1¶
This week, I had ONE really major issue. No matter what code I had, it wouldn’t upload. Arduino IDE kept returining “error status 2”. I spent about a day being unable to upload anything, and so I decided to troubleshoot this (heh).
After a lot of trial and error, I don’t really know what the physical problem with my board was, but I found a fix. All I had to do was reboot my MC as SOON as I started uploading the code, and then restarting the MC once the code was uploaded.
To reboot, long click on the B button on the MC, and then click the R button. Then, to restart, just click on R.
note: you can find the design files and design process on my week 9 documentation page.
This website was created using a template provided by Mr. Anith Ghalley and was used with his permission.*