← Back to list

Output Devices

March 26, 2024

Output Devices

Challenge


Group Assignment:

This week assignment is very interesting and I felt I’ve never used a testing equipment before [I Usually use DC supply to power up my component do the required testing and I just follow the datasheet], But this time I went a bit over the limit I tested the DC motor which I usually underestimate its abilities but it really shocked me as it can take up to 5 amp to move the stalling the shaft, I also learned that (In Dc Motor : torque is proportional to the current and speed is proportional to the voltage so when there is no load on the motor I discovered the motor can takes more voltage to achieve the required (RPM) and a very small amount of current and vice versa when it stalled and the motor tries to move the shaft it takes more current and the voltage drops to reach 3 volts which is chocking to me.)

For more information please refer to this LINK.

Individual Assignment:

This Was one of the hardest assignment for me (I know its easy to do but it’s hard to choose 😬) Nevertheless I decided to do it using (LCD I2C) as I want to use (I2C) Display in my final project but I know I might not use Normal LCD so I decided to escalate and Use (OLED Display), Then finally I would Like to add Neopixel Ring.

Let’s Begin

LCD I2C

Datasheet

LCD Front

LCD Back

Connection with the MCU

Connection with the MCU back

Connection with the MCU Front

Powered Up

Coded and Work

Great It works perfectly as needed

My main intention of trying it now is to test the needed Library to make it work also to try the MCU working with peripherals uses 5 volts.

(The Needed Library is {LCD_I2C.h})

Code used

/*
    LCD_I2C - Arduino library to control a 16x2 LCD via an I2C adapter based on PCF8574

    Copyright(C) 2020 Blackhack <davidaristi.0504@gmail.com>

    This program is free software : you can redistribute it and /or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.If not, see < https://www.gnu.org/licenses/>.
*/

#include <LCD_I2C.h>

LCD_I2C lcd(0x27, 16, 2); // Default address of most PCF8574 modules, change according

void setup()
{
    lcd.begin(); // If you are using more I2C devices using the Wire library use lcd.begin(false)
                 // this stop the library(LCD_I2C) from calling Wire.begin()
    lcd.backlight();
    pinMode(21,OUTPUT);
    pinMode(20,OUTPUT);
    pinMode(10,OUTPUT);
}

void loop()
{
  digitalWrite(21,LOW);digitalWrite(20,LOW);digitalWrite(10,HIGH);
    lcd.setCursor(2, 0);
    lcd.print("Zaid Abusini"); // You can make spaces using well... spaces
    lcd.setCursor(2, 1); // Or setting the cursor in the desired position.
    lcd.print("Electronics!");
    delay(500);

    // Flashing the backlight
    for (int i = 0; i < 5; ++i)
    {
        lcd.backlight();
        delay(50);
        lcd.noBacklight();
        delay(50);
    }

    lcd.backlight();
    lcd.clear();
    delay(500);
}

OLED Display

This Is a 0.96 inch display with addressable resistor (User can change its location to change the address in case we need to use 2 OLED at the same time without a multiplexer)

Datasheet

Front

0x78

0x7A

Display connection

Display connected with the MCU

Display connected with the MCU and powered up

I noticed that the Display without being coded won’t give any evidence of that.

one display working

Nice it work perfectly and we can also choose the font🤓.

Two display working

Great The two display works perfectly but I have observed that the code toke almost 20% of the available memory which is a bit stressing for me as I was planning to use this MCU as my main microcontroller for the final project but im planning to add more sensors so I have to take in mind this a and plan accordingly.

Code Used

//Original code by 'Mark's Bench' (Mark) <<minor tweaked edits by TechWithRita>>
//LEONARDO - TWO I2C OLEDS
// Using two displays: the 128x64 SH1106 OLED (0x3C/0x78), and the 128x32 SSD1306
// (0x3D/0x7A).
// The 128x64 display will be DISPA, the 128x32 display will be DISPB.
// This program is a bit of a pig, using 60% of the program storage space and 95% of
// the dynamic memory.
// Sometimes when running this program, the Leonardo doesn't respond to serial port
// data/uploads. If that happens, start the compile/upload, immediately ground the
// RESET pin very briefly, and it should work.
// **THIS PROGRAM IS FREE TO USE AND MODIFY AS YOU SEE FIT**

// Need this to use the I2C bus. I2C pins on Leonardo are broken
// out but are also 2 (SDA) and 3 (SCL).
#include <Wire.h> 

// Need this to make displays do things and stuff.
#include <U8g2lib.h> 

// Select proper constructor (driver) for this particular 128x64 OLED display and
// call it DISPA. See https://github.com/olikraus/u8g2/wiki/u8g2setupcpp for other
// drivers. There are lots of different OLED board configurations out there!
U8G2_SSD1306_128X64_NONAME_F_HW_I2C DISPA(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C DISPB(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);


// Select constructor for this particular 128x32 OLED display, call it DISPB.                                                                               
//U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C DISPB(U8G2_R0, U8X8_PIN_NONE);

// Set aliases for the I2C pins. They're broken out on the Leonardo but I'm using
// the numbered pins so it's seamless with other boards like the Pro Micro.


#define SDA 4  
#define SCL 5


void setup() {
  // put your setup code here, to run once:

  // Setting the pins that control the displays to all outputs. There are no inputs
  // on these two OLED displays to worry about - others may be different!
  pinMode(SDA, OUTPUT);  
  pinMode(SCL, OUTPUT);


  // Set I2C bus speed on Arduino and both displays. This may not be necessary
  // but I put it in anyway - one less thing to troubleshoot if things don't work.
  Wire.setClock(100000);
  DISPA.setBusClock(100000);
  DISPB.setBusClock(100000);

  // Some devices say they're 0x78/0x7A, but others may say they're 0x3C/0x3D. It's
  // like that because the address is 7 bits but some places (u8g2 included) pad it
  // out to 8 bits. Adding a 0 on the end multiplies the value by 2.
  // Most of the small OLED displays out there seem to be set to 0x3C(0x78). Some
  // can be changed, but not all of them.
  // See https://www.arduino.cc/en/Reference/Wire for details.
  DISPA.setI2CAddress(0x7A); //or 0x3C OR 0x3D
  DISPB.setI2CAddress(0x78);
  
  // Fire up the displays and get them ready to accept data.
  // Remember, DISPA is the 128x64px OLED, DISPB is the 128x32px OLED.                           
  DISPA.begin();
  DISPB.begin();

  // Select a font to use on DISPA and DISPB. They don't have to be the same, and
  // you can change them throughout the program, too. 
  // Check https://github.com/olikraus/u8g2/wiki for others, there are LOTS.
  DISPA.setFont(u8g2_font_logisoso30_tf );
  //DISPA.setFont(u8g2_font_t0_13_tf);

  DISPB.setFont(u8g2_font_logisoso16_tf ); //smaller font to show difference

  // Let's put some writing on DISPA. Make sure the display buffer is clear before
  // writing or drawing anything.
  DISPA.clearBuffer();

  // Move the starting position of what will be written/drawn next to x=0, y=32.
  // As shown in the above picture, coordinates start at 0,0 at the top left.
  // If you want to properly display text, make sure you set the y-value to at least
  // as large as how many pixels tall your font is.
  // If your display shows nothing, make sure you have set the y-value or everything
  // will end up being drawn beyond the edges of the display...
  
  // This just puts Howdy! in the selected font in the buffer. Nothing gets written
  // to the screen yet. You could move the cursor position again and write more text
  // to the buffer or draw some shapes if you wanted. At this point you're just
  // setting bits that will turn on the associated pixels.
  // See https://github.com/olikraus/u8g2/wiki/u8g2reference to find out how to
  // draw shapes and lines or even set individual pixels.

  // Now, do the same thing for DISPB.
  DISPB.clearBuffer(); 

}

void loop() {
    DISPA.clearBuffer();
    DISPA.setCursor(0, 31);
    DISPA.print("Display");
    DISPA.setCursor(40, 63);
    DISPA.print("A");
    DISPA.sendBuffer();
    
    //Display #2 or B (DISPB)
    DISPB.clearBuffer();
    DISPB.setCursor(0, 31);
    DISPB.print("Display");
    DISPB.setCursor(40, 63);
    DISPB.print("B");
    DISPB.sendBuffer();
}

Very useful video to Watch Link.

Two display working after changing the font

Two display working after changing the font

//Original code by 'Mark's Bench' (Mark) <<minor tweaked edits by TechWithRita>>
//LEONARDO - TWO I2C OLEDS
// Using two displays: the 128x64 SH1106 OLED (0x3C/0x78), and the 128x32 SSD1306
// (0x3D/0x7A).
// The 128x64 display will be DISPA, the 128x32 display will be DISPB.
// This program is a bit of a pig, using 60% of the program storage space and 95% of
// the dynamic memory.
// Sometimes when running this program, the Leonardo doesn't respond to serial port
// data/uploads. If that happens, start the compile/upload, immediately ground the
// RESET pin very briefly, and it should work.
// **THIS PROGRAM IS FREE TO USE AND MODIFY AS YOU SEE FIT**

// Need this to use the I2C bus. I2C pins on Leonardo are broken
// out but are also 2 (SDA) and 3 (SCL).
#include <Wire.h> 

// Need this to make displays do things and stuff.
#include <U8g2lib.h> 

// Select proper constructor (driver) for this particular 128x64 OLED display and
// call it DISPA. See https://github.com/olikraus/u8g2/wiki/u8g2setupcpp for other
// drivers. There are lots of different OLED board configurations out there!
U8G2_SSD1306_128X64_NONAME_F_HW_I2C DISPA(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C DISPB(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);


// Select constructor for this particular 128x32 OLED display, call it DISPB.                                                                               
//U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C DISPB(U8G2_R0, U8X8_PIN_NONE);

// Set aliases for the I2C pins. They're broken out on the Leonardo but I'm using
// the numbered pins so it's seamless with other boards like the Pro Micro.


#define SDA 4  
#define SCL 5


void setup() {
  // put your setup code here, to run once:

  // Setting the pins that control the displays to all outputs. There are no inputs
  // on these two OLED displays to worry about - others may be different!
  pinMode(SDA, OUTPUT);  
  pinMode(SCL, OUTPUT);


  // Set I2C bus speed on Arduino and both displays. This may not be necessary
  // but I put it in anyway - one less thing to troubleshoot if things don't work.
  Wire.setClock(100000);
  DISPA.setBusClock(100000);
  DISPB.setBusClock(100000);

  // Some devices say they're 0x78/0x7A, but others may say they're 0x3C/0x3D. It's
  // like that because the address is 7 bits but some places (u8g2 included) pad it
  // out to 8 bits. Adding a 0 on the end multiplies the value by 2.
  // Most of the small OLED displays out there seem to be set to 0x3C(0x78). Some
  // can be changed, but not all of them.
  // See https://www.arduino.cc/en/Reference/Wire for details.
  DISPA.setI2CAddress(0x7A); //or 0x3C OR 0x3D
  DISPB.setI2CAddress(0x78);
  
  // Fire up the displays and get them ready to accept data.
  // Remember, DISPA is the 128x64px OLED, DISPB is the 128x32px OLED.                           
  DISPA.begin();
  DISPB.begin();

  // Select a font to use on DISPA and DISPB. They don't have to be the same, and
  // you can change them throughout the program, too. 
  // Check https://github.com/olikraus/u8g2/wiki for others, there are LOTS.
  //DISPA.setFont(u8g2_font_logisoso30_tf );
  //DISPA.setFont(u8g2_font_t0_13_tf);
  DISPA.setFont(u8g2_font_6x13_t_cyrillic );
  DISPB.setFont(u8g2_font_logisoso16_tf ); //smaller font to show difference

  // Let's put some writing on DISPA. Make sure the display buffer is clear before
  // writing or drawing anything.
  DISPA.clearBuffer();

  // Move the starting position of what will be written/drawn next to x=0, y=32.
  // As shown in the above picture, coordinates start at 0,0 at the top left.
  // If you want to properly display text, make sure you set the y-value to at least
  // as large as how many pixels tall your font is.
  // If your display shows nothing, make sure you have set the y-value or everything
  // will end up being drawn beyond the edges of the display...
  
  // This just puts Howdy! in the selected font in the buffer. Nothing gets written
  // to the screen yet. You could move the cursor position again and write more text
  // to the buffer or draw some shapes if you wanted. At this point you're just
  // setting bits that will turn on the associated pixels.
  // See https://github.com/olikraus/u8g2/wiki/u8g2reference to find out how to
  // draw shapes and lines or even set individual pixels.

  // Now, do the same thing for DISPB.
  DISPB.clearBuffer(); 

}

void loop() {
    DISPA.clearBuffer();
    DISPA.setCursor(0, 31);
    DISPA.print("Zaid");
    DISPA.setCursor(40, 63);
    DISPA.print("Abusini");
    DISPA.sendBuffer();
    
    //Display #2 or B (DISPB)
    DISPB.clearBuffer();
    DISPB.setCursor(0, 31);
    DISPB.print("Electronics");
    DISPB.setCursor(40, 63);
    DISPB.print("Engineer");
    DISPB.sendBuffer();
}

Neopixel ring

This Is a Neopixel Ring that contain 16 RGB LED that are addressable and can be controlled.

Ring Datasheet
RGB Datasheet

NeoPixel Ring

Connection pin

Connection with MCU

I’ll be using an example code to check how it works.

Code USED

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 2

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {
  // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  // End of trinket special code

  strip.begin();
  strip.setBrightness(50);
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  // Some example procedures showing how to display to the pixels:
  colorWipe(strip.Color(255, 0, 0), 50); // Red
  colorWipe(strip.Color(0, 255, 0), 50); // Green
  colorWipe(strip.Color(0, 0, 255), 50); // Blue
//colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW
  // Send a theater pixel chase in...
  theaterChase(strip.Color(127, 127, 127), 50); // White
  theaterChase(strip.Color(127, 0, 0), 50); // Red
  theaterChase(strip.Color(0, 0, 127), 50); // Blue

  rainbow(20);
  rainbowCycle(20);
  theaterChaseRainbow(50);
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

OLED and Neopixel

I have noticed that both will occupy 20% of the storage which is a good sign, but I have to check more when we come to the input devices.

I noticed a bit of glitch when the Neopixel change the color, I hope its not the current (I have read that i can draw 700 mAmp from the power pin of the XIAO and I dont think I have reached this Already (16X18mA = 288 mA) this is according to the Manufacture house LINK)

I have to keep this in mind as my limit is going to be the current in this case 1 Neopixel ring will take almost 35% of the current.

Code USED

#include <Wire.h> 
#include <U8g2lib.h> 

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C DISPA(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C DISPB(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 

#define button 9
#define SDA 4  
#define SCL 5

#define PIN 2

Adafruit_NeoPixel zaid = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);


void setup() {

pinMode(SDA, OUTPUT);  
pinMode(SCL, OUTPUT);
pinMode(button,INPUT);
Wire.setClock(100000);
DISPA.setBusClock(100000);
DISPB.setBusClock(100000);
DISPA.setI2CAddress(0x7A); //or 0x3C OR 0x3D
DISPB.setI2CAddress(0x78);
DISPA.begin();
DISPB.begin();
DISPA.setFont(u8g2_font_t0_13_tf);
DISPB.setFont(u8g2_font_logisoso16_tf ); //smaller font to show difference
DISPA.clearBuffer();
DISPB.clearBuffer(); 
zaid.begin();
  zaid.setBrightness(100);
  zaid.show(); // Initialize all pixels to 'off'
}

void loop(){
int state = digitalRead(button);
int red = zaid.Color(255,0,0);//red color 
int green = zaid.Color(0,255,0);//green color
int blue = zaid.Color(0,0,255);//blue color 

if (state == 1){
  test(green);
}else{test(blue);
}

    DISPA.clearBuffer();
    DISPA.setCursor(0, 31);
    DISPA.print("Zaid");
    DISPA.setCursor(40, 63);
    DISPA.print("Abusini");
    DISPA.sendBuffer();

    DISPB.clearBuffer();
    DISPB.setCursor(0, 31);
    DISPB.print("Electronics");
    DISPB.setCursor(40, 63);
    DISPB.print("Engineer");
    DISPB.sendBuffer();

}
void test(uint32_t c){
  for (int i =0 ;i<zaid.numPixels();i++){
    zaid.setPixelColor(i,c);
    zaid.show();
    delay(100);
  }
}

Note : AS for the I2C connection its not advisable to connect different power specification modules to the MCU so in my case I have powered my module with 5V and connected them with my 3.3V MCU (They have worked perfectly) but this might cause a damage on the long term of operation so its not wise but it might solve a short term problem.