Skip to content

13. Outputs


Week assignment

  • Measuring the power consumption of an output device (in group)
  • Adding an output device to a my board, and program it to do something (individually)

Measuring power cosumption

We measure different outputs and share the results. I decided to try a laser and an autoflashing LED.

laser and autoflash

For the laser, I used this tutorial Which basically turns the laser on and off with intervals of 100 milliseconds.

int laserPin = 10;

void setup ()
{
  pinMode(laserPin, OUTPUT);
}

void loop () {
  digitalWrite(laserPin, HIGH);
  delay(100);
  digitalWrite(laserPin, LOW);
  delay(100);
}

For the autoflash, I used this tutorial Which basically turns the LED on and off with intervals of 2000 millisecond. The 7 different lights are simultaneously flashed.

void setup () {
  // Initialize the digital pin as an output.
  // Pin 11 has an LED connected on most Arduino boards:
  pinMode (11, OUTPUT);
}

void loop () {
  digitalWrite (11, HIGH); // set the LED on
  delay (2000); // wait for a second
  digitalWrite (11, LOW); // set the LED off
  delay (2000); // wait for a second
}

The group also measured an LCD screen, a Small DC motor and a LED RGB (144 LEDS). I sumarized the data on this table:

Module Working current[mA] Output Datasheet
LCD 20 HD44780U
DC motor 1100 DC motor 6/9V
LED RGB 170-800 SK6812
Laser 50/30 Laser Transmitter
Autoflash LED 80/40 7-Color Auto-flash LED

all outputs

Adding an output device to a my board

For this assignment, I wanted to continue working on my final project so I decided to add to my board an OLED. For the first test, I used the board that I made for the inputs week. Instead of using the one with the accelerometer, I started with the board that had the inverted SLC and SDA. So, I just connected the OLED with wires, and flashed following these instructions.

I used Adafruit’s library for SSD1306. This library is for monochrome displays only. I also used the Adafruit GFX library for the patterns, images, and text.

Then I downloaded the LCD Bitmap Converter from this link but I realized that it was not for iOS. So, I decided to try this using an example from the library.

I followed this tutorial

  • Open the example program from File -> Examples -> Adafruit SSD1306 -> ssd1306_128x64_i2c, because We are using OLED display with I2C interface with the screen size of 128x64.

But my OLED was not working. So, I decided to try using an Adruino UNO first, because I started thinking that maybe the OLED was dead. I repeated the steps and nothing. I changed the pins from SCL and SDA on the Arduino to A4(SLC) and A5(SDA), and nothing. I was about to give up until I found this video about OLED troubleshooting.

Tip

I didn’t check if this was a 64 or a 32 OLED so I decided to change the size from ssd1306_128x64_i2c to ssd1306_128x32_i2c. Uploaded it again to the Arduino and it worked!! So, after checking that my OLED was alive I decided to use the board. But this was the wrong conclusion. The OLED was not 128x32. Josep helped me to figured out that the address was wrong. The address for my board was 0x3C, and I was using 0x3F instead.

When using the code for 128x32 it worked because the address was 0x32 but the image on the screen was distorted.

working oled

Anyway, I still didn’t know why the OLED was not working with my board. I decided to start with something simple. Mainly because I don’t know much about code and I needed to fully understand what I was doing. So, I found this repository https://github.com/datacute/Tiny4kOLED which was simpler and was only using Tiny4KOLED library. I Intalled Tiny4kOLED library and uploaded the example code.

Because the OLED display uses I2C communication protocol, wiring is very simple. Just connected SDA, SCL, VCC and GND. However, the complex part was wiring the FTDI, UPDI and giving my board additional energy. As I’ve done this before for the input’s week, I knew that I needed to wire the board to the oled, then to the UPDI. Then, the UPDI to the FTDI and the FTDI to the computer. But still I needed to power the board and the OLED. So, I used an Arduino UNO and connected VCC from the board to 3.3v and GRD to GRD.

attiny setup

#include <Tiny4kOLED.h>

void setup() {
  // Send the initialization sequence to the oled. This leaves the display turned off
  oled.begin();

  // Two rotations are supported,
  // The begin() method sets the rotation to 1.
  //oled.setRotation(0);

  // Two fonts are supplied with this library, FONT8X16 and FONT6X8
  // Other fonts are available from the TinyOLED-Fonts library
  oled.setFont(FONT8X16);

  // Clear the memory before turning on the display
  oled.clear();

  // Turn on the display
  oled.on();

  // Switch the half of RAM that we are writing to, to be the half that is non currently displayed
  oled.switchRenderFrame();
}

void loop() {
  updateDisplay();
  delay(50);
}

void updateDisplay() {
  // Clear the half of memory not currently being displayed.
  oled.clear();

  // Position the text cursor
  // In order to keep the library size small, text can only be positioned
  // with the top of the font aligned with one of the four 8 bit high RAM pages.
  // The Y value therefore can only have the value 0, 1, 2, or 3.
  // usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
  oled.setCursor(0, 1);

  // Write text to oled RAM (which is not currently being displayed).
  oled.print(F("ms: "));

  // Write the number of milliseconds since power on.
  oled.print(millis());

  // Swap which half of RAM is being written to, and which half is being displayed.
  // This is equivalent to calling both switchRenderFrame and switchDisplayFrame.
  oled.switchFrame();
}

working oled with attiny

This code worked. So, I tought maybe there’s somethign wrong with the other code and the ATtiny1614 that I was using. I Still didn’t know what it was. The error I was getting when trying to upload the code from Adafruit was:

Error compiling for board ATtiny1614/1604/814/804/414/404/214/204.

error attiny

After a lot of time and frustration trying to find out what was wrong. I saw that when compiling successfully it showed the % of memory that the code was using.

memory space

So, I checked the size of the memory of the ATtiny1614, which is 16k. I remembered that, when discussing about the final project, Edu told me I could have memory issues if trying to upload complex graphics, but I was expecting something like ‘not enough space’. This error was telling me nothing.

I decided to comment stuff on the Adafruit code. I commented the loop, and error. I commented the setup too, and error. It was then I realized that the problem were the libraries. So, Adafruit libraries for the OLED were too heavy and I was never going to make it using the ATTiny1614.

This was definitely the most frustrating week so far. As my goal for this week was to be able to run my MPU6050 with the OLED, I decided to stick with the Tiny4kOLED library, and add the gyroscope code to it so that it shows the gyroscope data on the screen.

MPU6050 & OLED I2C

I used an 128x64 I2C based OLED module. I2C is a serial communication protocol, so data is transferred bit by bit along a single wire (the SDA line) SCL and SDA: These are the serial clock and serial data pins for I2C communication. The MPU6050 uses the same protocol.

I used this tutorial to check the address for both modules.

modules address

Using the Gyroscope on the MPU6050

A Gyroscope can detect the orientations. So, for my final project I wanted to use it to interact with the game. The accelerometer can detect acceleration, that’s why I will use it to track my user movement while not playing the game. This sensor can detect 3-directions:

  • X-axis = Pitch
  • Y-axis = Roll
  • Z-axis = Yaw

For this test, I wanted to understand how the gyro works and represent that on my OLED screen. Both the OLED and the MPU6050 are I2C Modules. This means (for me) that I will only need 4 wires to interface it with board: GND, VCC, SCL and SDA.

The gyroscope is complex, at least for me. So, my idea was to try to simplify it as much as possbile. It works using a vibrating structure to determine the rate of rotation. This is called MEMS (Micro Electro Mechanical Systems) angular rate sensor and it measures angular rotation. To understand this I read this friendly explanation

Then, I found this library: MPU6050_light which simplifies the calculation needed to understand the sensor’s input. So, I followed this tutorial and used the following code:

/* Get tilt angles on X and Y, and rotation angle on Z
    Angles are given in degrees
 License: MIT
 */
 #include "Wire.h"
 #include <MPU6050_light.h>
 MPU6050 mpu(Wire);
 unsigned long timer = 0;
 void setup() {
   Serial.begin(9600);
   Wire.begin();
 byte status = mpu.begin();
   Serial.print(F("MPU6050 status: "));
   Serial.println(status);
   while (status != 0) { } // stop everything if could not connect to MPU6050
 Serial.println(F("Calculating offsets, do not move MPU6050"));
   delay(1000);
   mpu.calcOffsets(); // gyro and accelero
   Serial.println("Done!\n");
 }
 void loop() {
   mpu.update();
 if ((millis() - timer) > 10) { // print data every 10ms
     Serial.print("X : ");
     Serial.print(mpu.getAngleX());
     Serial.print("\tY : ");
     Serial.print(mpu.getAngleY());
     Serial.print("\tZ : ");
     Serial.println(mpu.getAngleZ());
     timer = millis();
   }
 }

gyroscope input

Note

I found out that there was some sort of auto-calibration feature going on when flashing the board. I have to do more research on this for the final project because it may affect the performance of my device.

If I turned the senor to the left numbers will decrese and if I turn it to the right they will increase. So, now I just neded to add some parts of the gyro code to the code for the OLED.

For the first test I just copy the code I used to run the gyroscope into the OLED code and got this:

The gyroscope data was being printed on the serial monitor and the OLED was just counting non related stuff. For my final project I wanted to use the position of the gyro in Y to move a digital character. So, I wanted to experiment on how should I merge both codes in a way that the gyroscope could communicate with the OLED.

After my struggle to get the attiny to work with the OLED this seemed relatively simple. I started to copy and paste code from one sketch to the other until I got this patchwork:

// Choose your I2C implementation before including Tiny4kOLED.h

#include <Tiny4kOLED.h>
#include <Wire.h>
#include <MPU6050_light.h>

MPU6050 mpu(Wire);

void setup() {
  // Send the initialization sequence to the oled. This leaves the display turned off
  oled.begin();

  // Two fonts are supplied with this library, FONT8X16 and FONT6X8
  // Other fonts are available from the TinyOLED-Fonts library
  oled.setFont(FONT8X16);

  // Clear the memory before turning on the display
  oled.clear();

  // Turn on the display
  oled.on();

  // Switch the half of RAM that we are writing to, to be the half that is non currently displayed
  oled.switchRenderFrame();

  Serial.begin(9600);
   Wire.begin();
 byte status = mpu.begin();
   Serial.print(F("MPU6050 status: "));
   Serial.println(status);
   while (status != 0) { } // stop everything if could not connect to MPU6050
 Serial.println(F("Calculating offsets, do not move MPU6050"));
   delay(1000);
   mpu.calcOffsets(); // gyro and accelero
   Serial.println("Done!\n");
}

void loop() {

  mpu.update();

     Serial.print("X : ");
     Serial.print(mpu.getAngleX());
     Serial.print("\tY : ");
//   Serial.print();
     Serial.print("\tZ : ");
     Serial.println(mpu.getAngleZ());

  delay(50);
  updateDisplay(mpu.getAngleY());
}

void updateDisplay(float angleY) {
  // Clear the half of memory not currently being displayed.
  oled.clear();

  // Position the text cursor
  // In order to keep the library size small, text can only be positioned
  // with the top of the font aligned with one of the four 8 bit high RAM pages.
  // The Y value therefore can only have the value 0, 1, 2, or 3.
  // usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
  oled.setCursor(0, 1);

  // Write text to oled RAM (which is not currently being displayed).
  oled.print(F("ms: "));

  // Write the number of milliseconds since power on.
  oled.print(mpu.getAngleY());

  // Swap which half of RAM is being written to, and which half is being displayed.
  // This is equivalent to calling both switchRenderFrame and switchDisplayFrame.
  oled.switchFrame();
}

Explanation of the code

I used the following libraries. To Tiny4kOLED I added Wire, MPU6050_light

#include <Tiny4kOLED.h>
#include <Wire.h>
#include <MPU6050_light.h>

As both modules uses Wire.h I had to declare that it was only for the accelerometer (this is probably not the technical way to say this). I added this:

MPU6050 mpu(Wire);
I found that I needed to inicialize first the OLED and then the MPU6050. Not sure why, but this is what I read and also the only way I was able to make it work. Probably it’s related to the libraries.

This runs all for the OLED first. The OLED is inicialliced with oled.begin.

  // Send the initialization sequence to the oled. This leaves the display turned off
  oled.begin();

  // Two fonts are supplied with this library, FONT8X16 and FONT6X8
  // Other fonts are available from the TinyOLED-Fonts library
  oled.setFont(FONT8X16);

  // Clear the memory before turning on the display
  oled.clear();

  // Turn on the display
  oled.on();

  // Switch the half of RAM that we are writing to, to be the half that is non currently displayed
  oled.switchRenderFrame();

  ```

Only then, the MPU6050 is iniciallized. The MPU6050 is inicialliced with Wire.begin.
Wire.begin(); byte status = mpu.begin(); Serial.print(F(“MPU6050 status: “)); Serial.println(status); while (status != 0) { } // stop everything if could not connect to MPU6050 Serial.println(F(“Calculating offsets, do not move MPU6050”)); delay(1000); mpu.calcOffsets(); // gyro and accelero Serial.println(“Done!\n”);
Then, I defined the data that I wanted from the MPU6050. I just wanted to show the data in Y. 
mpu.update(); // Refreshes the values from the gyro //print the data on the serial port Serial.print(“X : “); Serial.print(mpu.getAngleX()); Serial.print(“\tY : “); Serial.print(“\tZ : “); Serial.println(mpu.getAngleZ());

// measures the gyro data with a dealy of 50 milliseconds delay(50); // This is the only mesure that will be shown in the OLED updateDisplay(mpu.getAngleY()); ```

So, by using the function updateDisplay(mpu.getAngleY()) and the parameter float angleY saying that the number is a decimal.

// Create a function that recieves the value to display
  void updateDisplay(float angleY) {
  // Clear the half of memory not currently being displayed.
  oled.clear();

  // Position the text cursor
  // In order to keep the library size small, text can only be positioned
  // with the top of the font aligned with one of the four 8 bit high RAM pages.
  // The Y value therefore can only have the value 0, 1, 2, or 3.
  // usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
  oled.setCursor(0, 1);

  // Write text to oled RAM (which is not currently being displayed).
  oled.print(F("ms: "));

  // Write the number of milliseconds since power on.
  oled.print(mpu.getAngleY());

  // Swap which half of RAM is being written to, and which half is being displayed.
  // This is equivalent to calling both switchRenderFrame and switchDisplayFrame.
  oled.switchFrame();
}

Download file here:


Last update: May 2, 2021