Skip to content

4. Embedded Programming

Group assignment

This is my Team Assignment, and I have learned the basic information of two chips. The Atmega328p (AVR architecture) and the Raspberry Pi RP2040 (ARM architecture).

I am a STEAM teacher and have been using Arduino Uno for many years. It was only this week, through my studies, that I truly got to know Arduino.
Arduino is powered by an Atmega328 chip. With this chip, a breadboard, and some basic electronic components, anyone can build an “Arduino Uno”. If you plan to mass-produce some simple hardware products, you can design a new circuit board using the Atmega328 (as a replacement for Arduino Uno), which might save a significant amount of cost. This website can teach you how to Building an Arduino on a Breadboard.
Building an Arduino on a Breadboard

Once you master this skill, you can customize your own Arduino. My teacher Saverio once designed an Arduino shaped like a map of Shanghai. It’s a great activity for learning Arduino.
shanghaino.jpg

Getting to Know the Atmega328

While reading the Atmega328P datasheet , I found that the content is extensive and highly technical, making it difficult to understand. I haven’t finished reading it yet. Instead, I used Kimi AI to get an overview of its content structure. I plan to delve into the specific knowledge as I use it in the future.
Arduino Uno and Arduino Nano both use the ATmega328P as their core microcontroller (even though their shapes are different). They have 14 digital I/O pins (6 of which can be used as PWM outputs) and 6 analog input channels.
arduinouno.jpg
arduinonano.jpg

The Atmega328 features 32 KB of flash memory, 2 KB of SRAM, and 1 KB of EEPROM. - Flash Memory: Used for storing program code and constant data, non-volatile.
- SRAM: Used for storing dynamic variables and temporary data during program execution, volatile.
- EEPROM: Used for storing a small amount of non-volatile data, such as configuration parameters and calibration values, non-volatile.
Reason for Partitioning: To enhance program security, functional separation, and flexibility in resource management. Atmega328 Microcontroller

Individual assignment

Programming with Atmega328p

1. Flashing lights

I have designed a simple program to control the blinking of an LED connected to pin 10.

Circuit Diagram
atmega328light

Code

// Define the pin connected to the LED
int ledPin = 10;

void setup() {
  // Set the pin as an output mode
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // Turn on the LED
  digitalWrite(ledPin, HIGH);
  // Delay for 100 milliseconds
  delay(100);
  // Turn off the LED
  digitalWrite(ledPin, LOW);
  // Delay for 100 milliseconds
  delay(100);
}

2. Adjustable light

Hardware Connections:

Potentiometer (Variable Resistor):
- Connect the two outer pins of the potentiometer to Arduino’s 5V and GND.
- Connect the middle pin to an analog input pin on Arduino (e.g., A0).

LED:
- Connect the positive leg (longer leg) of the LED to a PWM-capable pin on Arduino (e.g., Pin 10) through a suitable resistor (such as 220Ω).
- Connect the negative leg (shorter leg) of the LED to Arduino’s GND.

Adjustablelight

Code

// Define the PWM pin connected to the LED
int ledPin = 10;

// Define the analog pin connected to the potentiometer
int potPin = A0;

void setup() {
  // Set the LED pin as an output
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // Read the value from the potentiometer (range: 0-1023)
  int potValue = analogRead(potPin);

  // Map the potentiometer value to the LED brightness range (0-255)
  int ledBrightness = map(potValue, 0, 1023, 0, 255);

  // Set the LED brightness using PWM
  analogWrite(ledPin, ledBrightness);

  // Simple delay to avoid rapid refresh
  delay(10);
}

Programming with Arduino Atmega328p

I used Wokwi to simulate Arduino programming and observe the real-time effects on the webpage.

1. Serial communication

I wrote a simple code to send text to the serial port.

Code

// Initialize the serial communication with a baud rate of 9600
void setup() {
  Serial.begin(9600);
}

// Continuously send the message through the serial port
void loop() {
  // Send the message
  Serial.println("Arduino is a very powerful programming tool");

  // Wait for 1 second before sending the message again
  delay(1000);
}

Serialcommunication

2. Breathing Light (output)

This program connects an LED to pin 10. The brightness of the LED changes between 0 and 255, increasing or decreasing by 5 each time, which achieves the breathing light effect. To prevent too much current, I added a resistor to the LED.

ledprogram

Code

// Define the PWM pin connected to the LED
int ledPin = 9;

// Define the analog pin connected to the potentiometer
int potPin = A0;

void setup() {
  // Set the LED pin as an output
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // Read the value from the potentiometer (range: 0-1023)
  int potValue = analogRead(potPin);

  // Map the potentiometer value to the LED brightness range (0-255)
  int ledBrightness = map(potValue, 0, 1023, 0, 255);

  // Set the LED brightness using PWM
  analogWrite(ledPin, ledBrightness);

  // Simple delay to avoid rapid refresh
  delay(10);
}

3. Button (input)

Pull-Up Resistor

Circuit Diagram
- Connect one end of the button to digital pin 2.
- Connect the other end of the button to GND.
- No external resistor is needed as the internal pull-up resistor is used.

Pull-Up Resistor Example Code

Code

const int buttonPin = 2;  // Define the button connected to digital pin 2
int buttonState;          // Variable to store the button state

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);  // Set the pin as input mode with internal pull-up resistor
  Serial.begin(9600);                // Initialize serial communication
}

void loop() {
  buttonState = digitalRead(buttonPin);  // Read the button state

  if (buttonState == LOW) {  // If the button is pressed (connected to GND)
    Serial.println("Button is pressed");
    Serial.println(digitalRead(2));
  } else {  // If the button is not pressed (high level)
    Serial.println("Button is not pressed");
    Serial.println(digitalRead(2));
  }

  delay(100);  // A short delay to avoid jitter
}
Pull-Down Resistor

Circuit Diagram
- Connect one end of the button to analog pin A5.
- Connect the other end of the button to +5V.
- Connect a resistor (e.g., 10kΩ) between analog pin A5 and GND.

Pull-down Resistor Example Code

Code

const int buttonPin = A5;  // Define the button connected to analog pin A5
int buttonState;           // Variable to store the button state

void setup() {
  pinMode(buttonPin, INPUT);  // Set the pin as input mode
  Serial.begin(9600);         // Initialize serial communication
}

void loop() {
  buttonState = digitalRead(buttonPin);  // Read the button state

  if (buttonState == HIGH) {  // If the button is pressed (connected to +5V)
    Serial.println("Button is pressed");
    Serial.println(analogRead(A5));
  } else {  // If the button is not pressed (pulled down to GND)
    Serial.println("Button is not pressed");
    Serial.println(analogRead(A5));
  }

  delay(200);  // A short delay to avoid jitter and reduce serial output
}

4. Distance measurement

I don’t know how to write this program, so I referred to the code of AI assistant Kimi. I asked: Write an Arduino program that uses ultrasound to measure distance, and display the detected distance value on the 1602 display. Need hardware connection information and program. Convert the document into md format and translate it into English, and then get the following code.

Hardware Connections
Ultrasonic Sensor (HC-SR04) Connections
VCC: Connect to Arduino’s 5V.
GND: Connect to Arduino’s GND.
Trig: Connect to Arduino’s digital pin 9.
Echo: Connect to Arduino’s digital pin 10.

1602 LCD Display (I2C Interface) Connections
VCC: Connect to Arduino’s 5V.
GND: Connect to Arduino’s GND.
SDA: Connect to Arduino’s A4 (I2C data line).
SCL: Connect to Arduino’s A5 (I2C clock line).

lc1602+ultrasound

Code

#include <Wire.h>  // I2C communication library
#include <LiquidCrystal_I2C.h>  // 1602 LCD I2C library

// Initialize the 1602 LCD with I2C address 0x27, 16 columns, and 2 rows
LiquidCrystal_I2C lcd(0x27, 16, 2);

#define TrigPin 9  // Ultrasonic Trig pin connected to digital pin 9
#define EchoPin 10 // Ultrasonic Echo pin connected to digital pin 10

void setup() {
  pinMode(TrigPin, OUTPUT);  // Set Trig pin as output
  pinMode(EchoPin, INPUT);   // Set Echo pin as input
  lcd.init();                // Initialize the LCD
  lcd.backlight();           // Turn on the LCD backlight
  lcd.setCursor(0, 0);       // Set cursor position
  lcd.print("Distance: ");   // Display title
}

void loop() {
  // Send ultrasonic pulse
  digitalWrite(TrigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(TrigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(TrigPin, LOW);

  // Measure the duration of the echo pulse (in microseconds)
  long duration = pulseIn(EchoPin, HIGH);

  // Calculate distance (in centimeters)
  float distance = duration * 0.034 / 2;

  // Display distance on the LCD
  lcd.setCursor(0, 1);       // Set cursor to the second row
  lcd.print(distance);       // Display distance
  lcd.print(" cm");          // Display unit

  delay(500);                // Update every 500 milliseconds
}

5. Rhythm Music Light

I asked the AI (Deepseek),Write an Arduino code for this:
* When the program starts, all 16 LEDs on the NeoPixel Ring connected to P11 light up in yellow.

  • After pressing the button on D3, the lights turn off one by one within 2 seconds, while the buzzer on D5 plays a segment of music.
  • One second after the buzzer stops playing, the lights turn back on in yellow.
  • If the button is pressed again, the above actions are repeated.
    Note: The music can be a segment from a popular song.

Hardware Connections

*NeoPixel Ring: - Connect the IN pin of the NeoPixel Ring to digital pin D11 on the Arduino. - Connect VCC to 5V and GND to GND.

*Button: - Connect one end of the button to digital pin D3 and the other end to GND.

*Buzzer: - Connect the positive terminal of the buzzer to digital pin D5 and the negative terminal to GND.

Rhythm Music Light

#include <Adafruit_NeoPixel.h>

#define LED_PIN     11
#define BUZZER_PIN  5
#define BUTTON_PIN  3
#define LED_COUNT   16

// Initialize NeoPixel ring
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// Music parameters (a fragment from the "Super Mario" theme)
int melody[] = { 660, 660, 660, 510, 660, 770, 380 };
int noteDurations[] = { 100, 100, 100, 100, 100, 100, 100 };

volatile bool buttonPressed = false;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;

void setup() {
    strip.begin();
    strip.show(); // Initialize all LEDs off
    pinMode(BUTTON_PIN, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);
    resetLights();
}

void loop() {
    if (buttonPressed && (millis() - lastDebounceTime) > debounceDelay) {
        buttonPressed = false;
        startAnimation();
    }
}

void buttonISR() {
    if (!buttonPressed && (millis() - lastDebounceTime) > debounceDelay) {
        buttonPressed = true;
        lastDebounceTime = millis();
    }
}

void resetLights() {
    for (int i = 0; i < LED_COUNT; i++) {
        strip.setPixelColor(i, strip.Color(255, 255, 0)); // Yellow color
    }
    strip.show();
}

void startAnimation() {
    // Turn off all lights (one by one)
    for (int i = 0; i < LED_COUNT; i++) {
        strip.setPixelColor(i, 0);
        strip.show();
        playMusicSegment(i);
        delay(125); // 2 seconds to complete 16 LEDs (2000/16 = 125ms)
    }

    noTone(BUZZER_PIN);
    delay(1000);
    resetLights();
}

void playMusicSegment(int noteIndex) {
    if (noteIndex < 7) { // Play only the first 7 notes
        int duration = 1000 / noteDurations[noteIndex];
        tone(BUZZER_PIN, melody[noteIndex], duration);
        delay(duration * 1.3); // Wait for the note to play
        noTone(BUZZER_PIN);
    }
}