Week 4: Embedded Programming
Assignments
Group Assignments:
- Demonstrate and compare the toolchains and development workflows for available embedded architectures
- Document your work to the group work page and reflect on your individual page what you learned
Individual assignments
- Browse through the datasheet for a microcontroller
- Write and test a program for an embedded system using a microcontroller to interact (with local input &/or output devices) and communicate (with remote wired or wireless connections)
Group Assignment
This week, during the group assignment, I reinforced something important: the architecture of a microcontroller really does affect performance, power consumption, and even the way you approach development. It’s not just about picking a board that works. The internal structure actually shapes how the whole system behaves
I also understood that the datasheet isn’t optional. It’s not just extra documentation. It’s the real manual of the device, and if you want to truly understand what you’re doing, you have to read it.
Another key lesson was about programming languages. Choosing a language is similar to choosing a microcontroller. There isn’t a “best” option. The right choice depends on what your project needs, how much performance it requires, and how you plan to develop it.
Group Assignment – Embedded Programming
Individual Assignment
Datasheet
For my project I checked many microcontrollers to see which one would be best suited for my needs. I looked at their specifications, power consumption, and available features to make an informed decision, I decided to use the ESP32 because it has built-in Wi-Fi and Bluetooth
Here is the link for the data sheet: ESP32 Datasheet
Electrical Characteristics
- Operating Voltage: 3.0V - 3.6V
- Logic level: 3.3V
- Active mode current: tens of mA depending on workload
- Deep sleep current: in the microamp range (~5 µA typical)
Sleep Modes
- Active mode: CPU and peripherals running
- Modem sleep: Radio disabled when not in use
- Light sleep: CPU paused, memory retained
- Deep sleep: Ultra-low power consumption (~µA range)
ADC (Analog-to-Digital Converter)
- 1 ADC unit
- Up to 6 ADC channels (depending on the specific module/package)
- 12-bit resolution
PWM (LEDC – Hardware PWM)
- Up to 6 hardware PWM channels
- Adjustable frequency
- Adjustable resolution
Bluetooth Low Energy (BLE)
- Supports Bluetooth 5 LE
- Designed for low-power wireless communication
- Can operate as central or peripheral device
Piano
For one of my classes, I was asked to build a piano using an ATmega328P. By configuring the PWM correctly, I had to generate different frequencies so the buzzer could reproduce the musical notes being played.
The system also needed to adjust both the volume and the octave using different potentiometers, which were read through the ADC.
First, I assembled the hardware connections. I wanted the protoboard to resemble a small piano layout. After completing the circuit, I programmed the microcontroller in C to manage the inputs, ADC readings, and PWM signal generation.
My first attempt at programming the piano failed because I did not configure the PWM settings correctly. As a result, the buzzer was not generating the correct frequency, and the notes sounded distorted and out of tune.
I tested the piano using an oscilloscope to verify that I was generating the correct frequency and duty cycle.
After many attempts, I was finally able to achieve the correct frequency and duty cycle for each note. A friend helped me test the piano while I was recording the final result.
Here is the final code I used for the piano:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
uint8_t Top=0;
uint8_t nota=0;
uint16_t valor=0;
uint16_t octava=1;
uint16_t valor2=0;
float volumen=0.5;
int modo=0;
int matriz[10][1];
int i=0;
void interrupcion(){
PCICR|=(1<<PCIE0);
PCMSK0|=(1<<PCINT3)|(1<<PCINT4);
DDRB&=~((1<<PB3)|(1<<PB4));
sei();
}
ISR(PCINT0_vect){
if(PINB&(1<<PINB3)){
modo++;
_delay_ms(200);
}
if(modo==1){
PORTB&=~(1<<PB7);
TCCR1A&=~(1<<COM1B1);
}
if(modo==2){
PORTB|=(1<<PB7);
TCCR1A&=~(1<<COM1A1);
}
if(modo==3){
modo=0;
PORTB&=~(1<<PB7);
TCCR1A&=~(1<<COM1A1);
TCCR1A&=~(1<<COM1B1);
for(i=0;i<10;i++){
matriz[i][0]=0;
}
}
if(PINB&(1<<PINB4)){
i++;
matriz[i][0]=nota;
_delay_ms(100);
if(i>=10){
i=0;
}
}
}
void PWM1(){
TCCR1A|=(1<<COM1A1)|(1<<COM1B1);
TCCR1B|=(1<<CS11);
TCCR1A|=(1<<WGM11);
TCCR1B|=(1<<WGM12)|(1<<WGM13);
DDRB|=(1<<PB1)|(1<<PB2);
}
void ADC1(){
ADMUX=(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}
uint16_t valor_adc(uint8_t ch){
ch&=0b111;
ADMUX=(ADMUX&0b11111000)|ch;
ADCSRA|=(1<<ADSC);
while(ADCSRA&(1<<ADSC));
return ADC;
}
int main(){
ADC1();
interrupcion();
DDRD=0x00;
DDRB|=(1<<PB7);
while(1){
if(modo==0){
PORTB|=(1<<PB7);
}
valor=valor_adc(0);
valor2=valor_adc(1);
while(modo==1){
if(valor<408){octava=1;}
if((valor>512)&&(valor<717)){octava=2;}
if(valor>921){octava=4;}
if(valor2<408){volumen=0.3;}
if((valor2>409)&&(valor2<614)){volumen=0.5;}
if((valor2>615)&&(valor2<818)){volumen=0.7;}
if((valor2>819)&&(valor2<1023)){volumen=0.9;}
if(PIND&(1<<PIND0)){nota=1;}
if(PIND&(1<<PIND1)){nota=2;}
if(PIND&(1<<PIND2)){nota=3;}
if(PIND&(1<<PIND3)){nota=4;}
if(PIND&(1<<PIND4)){nota=5;}
if(PIND&(1<<PIND5)){nota=6;}
if(PIND&(1<<PIND6)){nota=7;}
if(PIND&(1<<PIND7)){nota=8;}
switch(nota){
case 1: PWM1(); Top=119/octava; OCR1A=Top*volumen; ICR1=Top; break;
case 2: PWM1(); Top=106/octava; OCR1A=Top*volumen; ICR1=Top; break;
case 3: PWM1(); Top=95/octava; OCR1A=Top*volumen; ICR1=Top; break;
case 4: PWM1(); Top=90/octava; OCR1A=Top*volumen; ICR1=Top; break;
case 5: PWM1(); Top=80/octava; OCR1A=Top*volumen; ICR1=Top; break;
case 6: PWM1(); Top=71/octava; OCR1A=Top*volumen; ICR1=Top; break;
case 7: PWM1(); Top=63/octava; OCR1A=Top*volumen; ICR1=Top; break;
case 8: PWM1(); Top=60/octava; OCR1A=Top*volumen; ICR1=Top; break;
default: break;
}
_delay_ms(400);
nota=0;
}
}
}
}
Connection Between This Week and My Final Project
This week’s work will directly support the development of my final project. Building the piano helped me understand how important it is to properly configure the PWM and ADC. That experience gave me a better understanding of how timers and signal generation work at the hardware level.
While reviewing the ESP32 datasheet, I focused on specifications that relate directly to my wearable. I analyzed the operating voltage and sleep modes to understand power consumption and battery life. I also reviewed the ADC for sensor readings and the PWM features to control the vibration motor.
Overall, this week helped me move from just programming to making informed technical decisions for my final project.