Output Devices
March 26, 2024
Challenge
-
Group assignment:
- Measure the power consumption of an output device.
- Document your work on the group work page and reflect on your individual page what you learned.
-
Individual assignment:
- Add an output device to a microcontroller board you’ve designed and program it to do something.👀
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
- I will Be using the circuit I have fabricated last week as my main controller board.
LCD I2C
- This is the most common display used all around specially at the beginning of any prototype [its so useful for testing].
- As for the connection of The LCD its Quite simple.
- Then I will connect it to the MCU and Upload the code to the MCU.
- Now let’s power it up.
- Now let me use an example code –> I will do small changes to the LED’s of the boards only.
- Now let me change the text on the LCD and try flashing the back light.
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)
- Now to Select the Address I will need to de-solder the resistor and change its location.
-
Now the connection is going to be similar to the LCD.
-
Let me start with one display then I will move to both together.
- I will use Breadboard to connect.
- Now I will power it up and check how it works.
I noticed that the Display without being coded won’t give any evidence of that.
- Now i will upload the code and check how it works.
Nice it work perfectly and we can also choose the font🤓.
- Now I will connect the other display.
- The connection is very simple I will extend the same wires of the first display.
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.
- Now let me change a bit in the code and check how the display will work.
-
I just changed the font and the text on the display.
-
TO change 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.
- The connection is very simple with the MCU.
- Now we will connect it with the MCU.
- Now I’m Ready to code it.
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
-
Now I will connect both together and check how they will work.
-
I would like to observe the amount of storage they will take and if there is any glitch.
-
the connection is going to be as previously done just I’m gonna change a bit in the code.
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.