Skip to content

5. Input & Output device

Throughout the week we experimented with input and output devices paired them with microcontrollers using both Thonny and Arduino IDE to program and code.

The common theme with both languages C++ and Micropython was that we have to let the device know what is the inputs and the outputs in relation to its pins so it knows what information to take and how to react based on the conditions given to it.

RGB lights shifting using Thonny

it is not a perfect smooth color shift but it has a smooth transition partially and it is mostly because of the constant value difference that was added to the green and blue value that you can see in the code

RGB with python results

The code

import machine import time

# Define RGB LED pins and PWM frequencies
RED_PIN = 12
GREEN_PIN = 13
BLUE_PIN = 14
PWM_FREQ = 1000

# Initialize PWM objects for each color
red = machine.PWM(machine.Pin(RED_PIN), freq=PWM_FREQ)
green = machine.PWM(machine.Pin(GREEN_PIN), freq=PWM_FREQ)
blue = machine.PWM(machine.Pin(BLUE_PIN), freq=PWM_FREQ)

# Function to shift colors automatically
def shift_colors():
    for i in range(1024):  # Duty cycle range from 0 to 1023
        red.duty(i)
        green.duty(1023 - i)  # Inverse of red
        blue.duty((i + 512) % 1024)  # Shift blue by 512

        time.sleep(0.01)  # Adjust delay for speed of color shifting

# Call the function to start color shifting
while True:
    shift_colors()

## RGB lights shifting using Arduino IDE

RGB with IDE results

The code

const int redPin = 9;
const int greenPin = 10;
const int bluePin = 11;

void setup() {
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
}

void loop() {
  // Change the color to red
  setColor(255, 0, 0);
  delay(1000); // Delay for 1 second

  // Change the color to green
  setColor(0, 255, 0);
  delay(1000); // Delay for 1 second

  // Change the color to blue
  setColor(0, 0, 255);
  delay(1000); // Delay for 1 second
}

void setColor(int redValue, int greenValue, int blueValue) {
  analogWrite(redPin, redValue);
  analogWrite(greenPin, greenValue);
  analogWrite(bluePin, blueValue);
}

Three speed fan control with a button

I faced an issue with the code of the 3 speed fan control as you see in the video the speed changes twice with one press of the button as the press and me removing my finger is being read as a signal so two speeds change at the same time

3 speed fan with the button error

The code

I did not fully understand the issue of the button input and why is it happening but i solved it in the updated code by repeating each speed twice so when the speed switches twice I can still get my desired speed.

import machine
import time

# Define fan pin for PWM control
FAN_PIN = 26
PWM_FREQ = 1000

# Define button pin
BUTTON_PIN = 27

# Initialize PWM object for the fan
fan_pwm = machine.PWM(machine.Pin(FAN_PIN), freq=PWM_FREQ, duty=0)

# Initialize button object
button = machine.Pin(BUTTON_PIN, machine.Pin.IN, machine.Pin.PULL_UP)

# Fan speed levels (0-1023)
fan_speeds = [0, 0, 512, 512, 768, 768, 1023, 1023]
current_speed = 0

# Function to set fan speed
def set_fan_speed(speed):
    fan_pwm.duty(speed)

# Function to handle button press
def button_press(pin):
    global current_speed
    current_speed = (current_speed + 1 ) % len(fan_speeds)
    set_fan_speed(fan_speeds[current_speed])

# Attach interrupt to the button press
button.irq(trigger=machine.Pin.IRQ_FALLING, handler=button_press)

# Main loop
while True:
    time.sleep(0.1)  # Add a small delay to reduce CPU usage

The accelerometer results

Gyro results

The code

#include "I2Cdev.h"
#include "MPU6050.h"

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // <-- use for AD0 high

int16_t ax, ay, az;
int16_t gx, gy, gz;



// uncomment "OUTPUT_READABLE_ACCELGYRO" if you want to see a tab-separated
// list of the accel X/Y/Z and then gyro X/Y/Z values in decimal. Easy to read,
// not so easy to parse, and slow(er) over UART.
#define OUTPUT_READABLE_ACCELGYRO

// uncomment "OUTPUT_BINARY_ACCELGYRO" to send all 6 axes of data as 16-bit
// binary, one right after the other. This is very fast (as fast as possible
// without compression or data loss), and easy to parse, but impossible to read
// for a human.
//#define OUTPUT_BINARY_ACCELGYRO


#define LED_PIN 13
bool blinkState = false;

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(38400);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    // use the code below to change accel/gyro offset values
    /*
    Serial.println("Updating internal sensor offsets...");
    // -76  -2359   1688    0   0   0
    Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
    Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
    Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
    Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
    Serial.print("\n");
    accelgyro.setXGyroOffset(220);
    accelgyro.setYGyroOffset(76);
    accelgyro.setZGyroOffset(-85);
    Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
    Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
    Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
    Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
    Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
    Serial.print("\n");
    */

    // configure Arduino LED pin for output
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // these methods (and a few others) are also available
    //accelgyro.getAcceleration(&ax, &ay, &az);
    //accelgyro.getRotation(&gx, &gy, &gz);

    #ifdef OUTPUT_READABLE_ACCELGYRO
        // display tab-separated accel/gyro x/y/z values
        Serial.print("a/g:\t");
        Serial.print(ax); Serial.print("\t");
        Serial.print(ay); Serial.print("\t");
        Serial.print(az); Serial.print("\t");
        Serial.print(gx); Serial.print("\t");
        Serial.print(gy); Serial.print("\t");
        Serial.println(gz);
    #endif

    #ifdef OUTPUT_BINARY_ACCELGYRO
        Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));
        Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));
        Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));
        Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));
        Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));
        Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));
    #endif

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

the Buzzer

me and my friend Faisal experimented with the buzzer and using the help of AI tools we were able to have the twinkle twinkle song to play

The code

import machine
import time

# Define speaker pin
SPEAKER_PIN = 26

# Define frequencies for the notes in the melody
# Note: Frequencies are in Hertz
C = 262
D = 294
E = 330
F = 349
G = 392
A = 440
B = 494

# Define the "Twinkle, Twinkle, Little Star" melody with note durations
twinkle_melody = [
    (C, 0.5), (C, 0.5), (G, 0.5), (G, 0.5),
    (A, 0.5), (A, 0.5), (G, 1),
    (F, 0.5), (F, 0.5), (E, 0.5), (E, 0.5),
    (D, 0.5), (D, 0.5), (C, 1),
    (G, 0.5), (G, 0.5), (F, 0.5), (F, 0.5),
    (E, 0.5), (E, 0.5), (D, 1),
    (G, 0.5), (G, 0.5), (F, 0.5), (F, 0.5),
    (E, 0.5), (E, 0.5), (D, 1),
    (C, 0.5), (C, 0.5), (G, 0.5), (G, 0.5),
    (A, 0.5), (A, 0.5), (G, 1)
]

# Initialize PWM object for the speaker
speaker_pwm = machine.PWM(machine.Pin(SPEAKER_PIN), freq=0, duty=512)

# Function to play a note
def play_note(note, duration):
    if note == 0:  # Check for rest
        time.sleep(duration)  # Pause for rest duration
    else:
        speaker_pwm.freq(note)
        time.sleep(duration)

# Function to play the melody
def play_twinkle_twinkle():
    for note, duration in twinkle_melody:
        play_note(note, duration)

# Play the "Twinkle, Twinkle, Little Star" melody
play_twinkle_twinkle()

Last update: September 11, 2024