Week 4: Embedded programming

This week, the task was to program a code using a microcontroller and read the datasheet of at least one microcontroller.

Datasheet

A datasheet in electronics is a technical document provided by manufacturers that details the specifications, functionality, pinout, and physical characteristics of a component. It acts as a guide for engineers to design reliable circuits by defining operating parameters, electrical characteristics, and maximum ratings.

One of the assignments for this week was browse through the data sheet for a microcontroller. A microcontroller unit (MCU) is essentially a small computer on a single chip. It is designed to manage specific tasks within an embedded system without requiring a complex operating system. I chose the ESP32 WROOM 32 by Espressif Systems and a Raspberry Pi Pico by Raspberry Pi.

Classification of Microcontrollers by Number of Bits

Bit: Is the smallest unit of data in electronics and computing, representing a single binary value of either 0 or 1. It acts as the fundamental building block for all digital information, representing logical states like on/off, true/false, or high/low voltage.

  • 8-bit Microcontrollers: Performs operations on 8 bits at a time. Ideal for basic simple tasks, such as timers, sensors, and motor control.
  • 16-bit Microcontrollers: Performs operations on 16 bits at a time. They are ideal for real-time control, precision measurement and industrial applications.
  • 32-bit Microcontrollers: Performs operations on 32 bits at a time. They offer high-performance processing, large memory addressing, and advanced peripherals, making them ideal for complex, power-efficient applications like IoT and industrial control.

Classification of Microcontrollers by Memory

  • Embedded Memory Microcontroller: Is a compact, single-chip computer that integrates all the necesary components. integrating a processor core, program memory (Flash/ROM), data memory (SRAM), and peripherals.
  • External Memory Microcontroller: Is a compact chip without on-chip integrated memory. It requires external program memory (Flash/ROM) and data memory (SRAM).

ESP32 WROOM 32

Feature

ESP32 WROOM 32

ROM

448 KB

SRAM

520 KB

SRAM in RTC

8 KB

Wifi
  • 802.11b/g/n
  • Bit rate: 802.11n up to 150 Mbps
Bluetooth
  • Bluetooth V4.2 BR/EDR
  • Bluetooth LEspecification
Peripherals
  • Up to 32 GPIOs.
  • SD card, UART, SPI, SDIO, I2C, LED PWM, Motor PWM, I2S, IR, pulse counter, GPIO, capacitive touch sensor, ADC, DAC, TWAI® (compatible with ISO 11898-1, i.e. CAN Specification 2.0)
Analog Inputs

18 Analog enabled pins

Operating Conditions
  • Operating voltage/Power supply: 3.0 ~ 3.6 V
  • Operating ambient temperature: –40 ~ 85 °C

Pinout

Pinout
Power: These are the power supply pins, such as 3V3, which provide the necessary voltage for the module to operate.
GND: Ground pins that act as the common reference point for the electrical circuit.
EN: The Enable pin, used to boot, reset, or disable the chip.
GPIO: General Purpose Input/Output pins that can be programmed to act as either digital inputs or outputs.
SPI: Serial Peripheral Interface pins that are high-speed communication protocols for external devices like SD cards or displays.
I2C: Serial Data (SDA) and Serial Clock (SCL). These pins allow microcontrollers to connect to multiple sensors or devices simultaneously using a master-slave architecture.
DAC: Digital-to-Analog Converters used to output an analog voltage signal from the microcontroller.
Touch: Capacitive touch sensors that can detect human touch on conductive surfaces without mechanical buttons.
UART: Universal Asynchronous Receiver-Transmitter pins, typically used for serial communication with a PC or other microcontrollers.
Control: Pins used for specific internal system functions or clock signals.

Programming in C++

What is C++?

C++ is a high-level, general-purpose programming language created by Bjarne Stroustrup in 1979 as an extension of the C programming language. It is often described as "C with Classes," designed to provide the efficiency of low-level coding with the power of modern abstractions.

CPP

What is C++?

C++ is a high-level, general-purpose programming language created by Bjarne Stroustrup in 1979 as an extension of the C programming language. It is often described as "C with Classes," designed to provide the efficiency of low-level coding with the power of modern abstractions.

CPP

Important commands and data types for my code

The Equations menu enables dimension linking and global variables, allowing fast design iterations, scalability, and precise change control.
Fab termi
Global Variables

Global variables are concepts that store numerical values ​​and can be referenced by multiple dimensions and features of the model. They can be defined in the Equation Manager or directly when assigning a dimension, by typing "=" followed by a .

Value/Equations

The Value/ Equations section is where the numerical values and variables operations are assigned.

Evaluates to

In this section is displayed the value that the program will interpretate.

Comments

This space is to place additional information of the Global variable.

My code

My code consists of turning on three LEDs in sequence and starting a timer each time one turns on to measure the time between the LED lighting up and the button being pressed. During the Development of my code I was assisted by ChatGPT to understand the ESP32 internal timer and to be able to register big numbers.

Code

// ---------- Pins ----------
const int ledPins[3] = {16, 17, 18};
const int btnPins[3] = {13, 12, 14};

// ---------- Time ----------
hw_timer_t *timer = NULL;
volatile unsigned long tiempo = 0; // ms

// ---------- Control ----------
int status = 0;
bool waiting = false;

// ---------- Interruption ----------
void IRAM_ATTR onTimer() {
 tiempo++; // 1 ms
}
// ---------- Setup ----------
void setup() {
 Serial.begin(9600);

 // LEDs
 for (int i = 0; i < 3; i++) {
  pinMode(ledPins[i], OUTPUT);
  digitalWrite(ledPins[i], LOW);
 }
 // Buttons
 for (int i = 0; i < 3; i++) {
  pinMode(btnPins[i], INPUT_PULLUP);
 }

// ---------- Timer ----------
timer = timerBegin(1000000);
timerAttachInterrupt(timer, &onTimer);
timerAlarm(timer, 1000, true, 0);
timerStart(timer);

iniciateLED();
}

// ---------- Loop ----------
void loop() {
 if (waiting) {
  if (digitalRead(btnPins[status]) == LOW) {
   waiting = false;
   Serial.print("LED ");
   Serial.print(status + 1);
   Serial.print(" -> Tiempo: ");
   Serial.print(tiempo);
   Serial.println(" ms");
   delay(300);
   nextLED();
  }
 }
}

// ---------- Functions ----------
void iniciateLED() {
 turnOff();
 tiempo = 0;
 digitalWrite(ledPins[status], HIGH);
 waiting = true;
 Serial.print("LED ");
 Serial.print(status + 1);
 Serial.println(" encendido...");
}

void nextLED() {
 status++;
 // If LED number 3 already ended:
 if (status >= 3) {
  waiting = false; // NO MORE BUTTONS LEFT
  turnOff(); // Turn off LEDs
  Serial.println("---- Cicle ended ----");
  return;
 }

 iniciateLED();
}

void turnOff() {
 for (int i = 0; i < 3; i++) {
  digitalWrite(ledPins[i], LOW);
 }
}
// ---------- Pins ----------
const int ledPins[3] = {16, 17, 18};
const int btnPins[3] = {13, 12, 14};
1. First, this part declares the pins where my LEDs and my buttons will be. It also relates each LED with each button.
const defines my variable as a constant. int defines my variable a an integer value. [3] defines that may array has 3 spaces, and {} assignates each one of them to one of the spaces my array has.
// ---------- Time ----------
hw_timer_t *timer = NULL;
volatile unsigned long tiempo = 0; // ms
2. Then i declared the timer and my starting time variable.
hw_timer_t is one of the internal watches of the ESP32. *timer is a pointer where I am declaring that a timer will go. That timer will be declared in the setup() NULL indicates that there isn't anything for now.
volatile indicates that a variable is prolly to change.unsigned long is for big numbers. tiempo = 0 is my registered time variable that for begining is 0.
// ---------- Control ----------
int status = 0;
bool waiting = false;
3. Then i declared the control variables to knwo in which LED would I be and if there's more LEDS after.
int status = 0 is to know in which of the 3 states (LEDs) I am, it starts at 0 because at the beginig it isn't in any state. bool indicates that a variable is one state or other, true or false. bool waiting = false starts at false because it isn't waiting for any LED yet.
// ---------- Interruption ----------
void IRAM_ATTR onTimer() {
 tiempo++; // 1 ms
}
// ---------- Setup ----------
void setup() {
 Serial.begin(9600);

 // LEDs
 for (int i = 0; i < 3; i++) {
  pinMode(ledPins[i], OUTPUT);
  digitalWrite(ledPins[i], LOW);
 }
 // Buttons
 for (int i = 0; i < 3; i++) {
  pinMode(btnPins[i], INPUT_PULLUP);
 }
4. Then I setted an interruption, started de Serial and declared the Output of my LEDS as LOW and my buttons
IRAM_ATTR onTimer() Sets the ESP32 in "fast" memory so it doesn't stop doing that task. tiempo++ Every time the timer is working, my time variable will increment its value 1 by 1. Serial.begin(9600) activates the Serial, the communication with the PC.  // LEDs
 for (int i = 0; i < 3; i++) {
  pinMode(ledPins[i], OUTPUT);
  digitalWrite(ledPins[i], LOW);
 }
Declares each LED, while i value is less than 3, a led will be declared. Instead of declaring them indivually, the "for" does it all at the same time.  // Buttons
 for (int i = 0; i < 3; i++) {
  pinMode(btnPins[i], INPUT_PULLUP);
 }
The same happends with the buttons.
// ---------- Timer ----------
timer = timerBegin(1000000);
timerAttachInterrupt(timer, &onTimer);
timerAlarm(timer, 1000, true, 0);
timerStart(timer);
iniciateLED();
}
5. After, I created the timer, the iterruptor and the alarm.
timerAttachInterrupt(timer, &onTimer) when the timer starts it calls &onTimer. timerAlarm(timer, 1000, true, 0) defines the timer in microseconds and establis it as a repetitive task. timerStart(timer) starts the timer.
// ---------- Loop ----------
void loop() {
 if (waiting) {
  if (digitalRead(btnPins[status]) == LOW) {
   waiting = false;
   Serial.print("LED ");
   Serial.print(status + 1);
   Serial.print(" -> Tiempo: ");
   Serial.print(tiempo);
   Serial.println(" ms");
   delay(300);
   nextLED();
  }
 }
}
6. If it is in the waiting variable, the status will go to the next state until there is no more states.
// ---------- Functions ----------
void iniciateLED() {
 turnOff();
 tiempo = 0;
 digitalWrite(ledPins[status], HIGH);
 waiting = true;
 Serial.print("LED ");
 Serial.print(status + 1);
 Serial.println(" encendido...");
}

7. This void is the responsable of turning on the LEDs.

Programming in Python

What is Python?

Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together. Python's simple, easy to learn syntax emphasizes readability and therefore reduces the cost of program maintenance..

py

My Code

My code consists of turning on three LEDs in sequence and starting a timer each time one turns on to measure the time between the LED lighting up and the button being pressed.

Code

from machine import Pin
import time


# ---------- Pines ----------
led_pins = [2, 4, 5]
btn_pins = [26, 27, 28]


# ---------- LEDs ----------
leds = [Pin(p, Pin.OUT) for p in led_pins]
# ---------- Botones (Pull-up) ----------
buttons = [Pin(p, Pin.IN, Pin.PULL_UP) for p in btn_pins]

# ---------- Control ----------
estado = 0
terminado = False


# ---------- Funciones ----------

def apagar_todo():
for led in leds:
led.value(0)


def iniciar_led(i):
apagar_todo()
leds[i].value(1)
inicio = time.ticks_ms()
print(f"LED {i+1} encendido...")
return inicio
# ---------- Programa principal ----------
while not terminado:
inicio = iniciar_led(estado)
esperando = True
while esperando:
# Botón presionado = LOW (0)
if buttons[estado].value() == 0:
tiempo = time.ticks_diff(time.ticks_ms(), inicio)
print(f"LED {estado+1} -> Tiempo: {tiempo} ms")
time.sleep(0.3) # Antirebote
esperando = False
estado += 1
# Si terminó el ciclo
if estado >= 3:
apagar_todo()
print("---- Ciclo terminado ----")
terminado = True

Files