Skip to content

Week 09 - Output Devices

Goals

  • individual assignment:
    • add an output device to a microcontroller board you've designed, and program it to do something
  • group assignment:
    • measure the power consumption of an output device

Week's explorations and achievments

  • Group assignment: measure the power consumption of a small DC motor
  • Test several output devices (breadbord connections):
    • RGBW led strips
    • Servomotor
    • DC motor
    • LCD screen
  • Test electrical circuits and gesture workflows for the final project
  • Sketch new ideas for the final project
  • Design, produce and test small boards for the final project
    • Led element: data input part
    • Led element: contact pads for data input and ground
    • Led element: battery part
    • Microcontroller side: contact pads for trigger and data GPIOs and ground

Group assignment

We measured the power consumption of a small DC motor.

See the group assignment page

I'll keep in mind that the current must always be measured in series. Measuring the power consumption can help you dimension the power supply for a project, or in the case of a battery powered project to anticipate how long it can work without replacing or changing the batteries.

Output devices tests

Since there are strikes ongoing in France, it affects my ability to come and work in the lab (closed campus, public transportation issues), so I worked with components I could find at home.

RGB Leds

Built-in WS2812B leds

I used the last board designed and produced during the electronic production week. It provides an ATtiny3216, SPI and I2C, a bunch of GPIOs and WS2812B RGB leds. I thus attempted to program them at first, but they didn't light up. At first I thought maybe there was a problem of compatibility with the libraries and invested this question. But since nothing happened at all I realised it is probably a hardware problem, most likely bad soldering. Indeed, their pads are under the element and it's then quite complicated to solder them manually. My instructor had adviced me the week before to solder them with solder paste and a refusion oven, but since he's not there this week I just carried on with external led strips.

Neopixel strips recommmandations

I used leds strips I had at home that I used in a previous small personal project. I don't have the exact reference but they are Neopixel alike led strips.

Here are the best practices provided by Adafruit's in their [Neopixel Uberguide] (https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices) that I follow when I do a project with led strips:

Before connecting NeoPixels to any large power source (DC “wall wart” or even a large battery), add a capacitor (500–1000 µF at 6.3V or higher) across the + and – terminals as shown above. The capacitor buffers sudden changes in the current drawn by the strip.

[Comment: in fact I tend to add a capacitor even when I don't have a particularly large battery, since I observed it could improve the stability of the led's light]

Place a 300 to 500 Ohm resistor between the Arduino data output pin and the input to the first NeoPixel. The resistor should be at the end of the wire closest to the NeoPixel(s), not the microcontroller. Some products already incorporate this resistor…if you’re not sure, add one…there’s no harm in doubling up! Also, newer NeoPixels are less picky about this. Nothing’s needed at the “out” end of a strip…you can leave the data out “floating.”

[Comment: I systematically added a 300 Ohm resistor between the microcontroller data output and the input to the first led of the strip]

Try to minimize the distance between the Arduino and first pixel, so the signal is clear. A meter or two is usually no problem. Much longer and things can become unreliable. Individual NeoPixels can act as repeaters for long runs.

[Comment: I will not be concerned by this issue in this project]

Avoid connecting NeoPixels to a live circuit. If you simply must, always connect ground first, then +5V, then data. Disconnect in the reverse order.

[Comment: I don't think my project respects that point, but I'm not sure what are the risks here]

If powering the pixels with a separate supply, apply power to the pixels before applying power to the microcontroller. Otherwise they’ll try to power “parasitically” through the data line, which could spell trouble for the microcontroller.

Observe the same precautions as you would for any static-sensitive part; ground yourself before handling, etc.

NeoPixels powered by 5v ideally need a 5V data signal. If using a 3.3V microcontroller you must use a logic level shifter such as a 74AHCT125 or 74HCT245. See the “Logic Level Shifting” page for more details. If you are powering your NeoPixels with 3.7v directly from a LiPoly cell, a 3.3v data signal is OK.

[Comment: The ATtiny3216 provides 5V so I believe I don't have to worry about that? Also not sure if all my strips will be powered the same way, some might be by 5V, others with 3.7V LiPoly cell, not sure if it's a problem?]

If your microcontroller and NeoPixels are powered from two different sources (e.g. separate batteries for each), there must be a ground connection between the two.

[Comment: This is important to take in account in my circuits design]

Make sure that your connections are secure. Alligator clips do not make reliable connections to the tiny solder pads on NeoPixel rings. Better to solder a small pigtail wire to the ring and attach the alligator clips to that.

Tests with led strips

Following the recommandations I added a 470 uF capacitor between the VCC and GND pin of the neopixel strip and a 300 Ohm resistor on the data line. For these tests I used the same power source for the led strip than for the microcontroller (5V USB). I connected the data line to the PIN 5 (my GPIO6).

I used to work with the Adafruit Neopixel library and also used it during the Embedded Programming week with the ATtiny1614 and other commercial boards, so I used it for mmy first tests. But what worried me after the very first test was that the colors were completely inconsistent. For example I asked for green in the programm and obtained different leds color.

picture week 09

I thought that maybe the library was not compatible with the ATtiny3216 which has a slightly different architecture than the ATtiny1614 (it's a megaavr architecture) and looked for other libraries. I read that some other person struggled also with led libraries issues with this microcontroller so I went for the tinyNeopixel.h library. It provides both a static and a non static version. I first tried the static version with the simple example

Here's how to define a strip object using the tinyNeopixel library. NUMPIXELS is the number of pixels, PIN the data pin, and the third parameter NEO_GRB is the pixel type flags : // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

So I first declared my strip that way.

tinyNeoPixel strip = tinyNeoPixel(NUMPIXELS, PIN, NEO_GRB, pixels);

Then thought it might be a problem of color bitstream

tinyNeoPixel strip = tinyNeoPixel(NUMPIXELS, PIN, NEO_RGB, pixels);

It wasn't any better. Than I remembered that a long time ago I faced such issue and it was a problem of white led or white color encoding. I thus switched my declaration for:

tinyNeoPixel strip = tinyNeoPixel(NUMPIXELS, PIN, NEO_RGBW, pixels);

Almost there! The correct declaration was indeed:

tinyNeoPixel strip = tinyNeoPixel(NUMPIXELS, PIN, NEO_GRBW, pixels);

picture week 09

But obviously there was still a small issues to fix, as some pixels were incorrect.

picture week 09 picture week 09

I switched for the non-static version of tinyNeopixel.h, and everything went as expected. Not sure why though! I also tested the strandtest example and everything went smoothly.

picture week 09

Two strips tests

I added a second strip on PIN 4 (my GPIO5). I added a resistor but no other capacitor since all were connected together and very physically close.

Here's the code, adapted from the simple test example.

// NeoPixel Ring simple sketch (c) 2013 Shae Erisson
// released under the GPLv3 license to match the rest of the AdaFruit NeoPixel library

#include <tinyNeoPixel.h>

// Which STRIP_A on the Arduino is connected to the NeoPixels?
#define STRIP_A           5
#define STRIP_B 4

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS_A      16
#define NUMPIXELS_B      16

// When we setup the NeoPixel library, we tell it how many pixels, and which PIN to use to send signals.
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
// example for more information on possible values.
tinyNeoPixel pixels_a = tinyNeoPixel(NUMPIXELS_A, STRIP_A, NEO_GRBW + NEO_KHZ800);
tinyNeoPixel pixels_b = tinyNeoPixel(NUMPIXELS_B, STRIP_B, NEO_GRBW + NEO_KHZ800);
int delayval = 50;
int r= 200;
int g=20;
int b = 10;

int r2= 0;
int g2= 60;
int b2= 200;

void setup() {

  pixels_a.begin(); // This initializes the NeoPixel library.
  pixels_b.begin(); // This initializes the NeoPixel library.
}

void loop() {

  // For a set of NeoPixels the first NeoPixel is 0, second is 1, all the way up to the count of pixels minus one.

  for (int i = 0; i < NUMPIXELS_A; i++) {
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    pixels_a.setPixelColor(i, pixels_a.Color(r, g, b)); // Moderately bright green color.
    pixels_a.show(); // This sends the updated pixel color to the hardware.
    delay(delayval); // Delay for a period of time (in milliseconds).
  }

  for (int i = 0; i < NUMPIXELS_B; i++) {
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    pixels_b.setPixelColor(i, pixels_b.Color(r2, g2, b2)); // Moderately bright green color.
    pixels_b.show(); // This sends the updated pixel color to the hardware.
    delay(delayval); // Delay for a period of time (in milliseconds).
  }

}

I wanted to test how I could play with led lighting for my final project. I was enchanted by the results of these very first tests, even in daylight the light is strongh enough to make beautiful effects. I used a white ceramic vase with nice creases to see the variations in the lighting and the color of shadows and I am willing to experiment more with such "obstacles" (as described in my first final project sketches). Also I enjoyed how the roughness of the wall interacts with the light, as it was something I initially wanted to experiment too (see "textures" in my first sketches). I think that the shadows are great and the way the colored lights blends towards a yellowish light is really nice.

picture week 09 picture week 09 picture week 09 picture week 09

Servomotor

Such simple servomotors are controlled with one GPIO output (thanks to Pulse Width Modulation). I powered with the same power supply as the microcontroller (USB 5V). Note that you need to include the library Servo.h

I used the simple example provided by the website arduino-france.

The example sketch sends three angles values, I changed it for a loop with smaller delays to have a more continuous movement.

#include "Servo.h"

Servo servo; // création de l'objet "servo"

void setup() {
   servo.attach(0); // attache le servo au pin spécifié
}

void loop() {

  for (int a=0; a<180; a++){
   servo.write(a); // demande au servo de se déplacer à cette position
   delay(4); // attend 1000 ms entre changement de position
  }

  for (int a=0; a<180; a++){
   servo.write(180-a); // demande au servo de se déplacer à cette position
   delay(4); // attend 1000 ms entre changement de position
  }

}

LCD screen

I used a 16x2 LCD screen with a I2C backpack that I had at my home. I remembered that the first time I used I struggled because the intensity was not properly adjusted. You have a small screw in the back to adjust it if you cannot read anything.

I used the I2C header pins I added to my development board (SDA, SCL, + GND) and powered it with the same supply as my board (VCC +5V). You need to add two libraries: * Wire.h for I2C communication * LiquidCrystal_I2C.h by Frank Brabander

In order to communicate with the device, you need its adress. It's often Ox27 but just to be sured I ran a test allowing me to retrieve its adress with serial commmunication I found on the website makerguides.com.

/*I2C_scanner
  This sketch tests standard 7-bit addresses.
  Devices with higher bit address might not be seen properly.*/

#include <Wire.h>

void setup() {
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);
  Serial.println("\nI2C Scanner");
}

void loop() {
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);
}

After switching my UPDI/FTDI programmer to the FTDI mode, I can retrieve the following message in the Serial monitor:

Scanning...
I2C devide found at 0x27 ! 
done

I could now confirm that the I2C LCD screen is at the adress 0x27. I ran the example sketch also provided in makersguide, only I adapted it by adding the three last lines to make the text blink. It worked as expected.

/* I2C LCD with Arduino example code. More info: https://www.makerguides.com */

// Include the libraries:
// LiquidCrystal_I2C.h: https://github.com/johnrickman/LiquidCrystal_I2C
#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD

// Wiring: SDA pin is connected to A4 and SCL pin to A5.
// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered)
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Change to (0x27,20,4) for 20x4 LCD.

void setup() {
  // Initiate the LCD:
  lcd.init();
  lcd.backlight();
}

void loop() {
  // Print 'Hello World!' on the first line of the LCD:
  lcd.setCursor(0, 0); // First number for the column, second for the row
  lcd.print("OUTPUT DEVICES"); // Print the string "Hello World!"
  lcd.setCursor(0, 1); //
  lcd.print("ON STRIKE");

    delay (1000);
  lcd.init();
  delay (1000);
}

picture week 09

DC motor

For the DC motor I waited until I could go to the lab because I didn't have any MOSFETs at home. Controlled with Pulse Width Modulation. I used a N-MOSFET and a diode to drive the DC motor. I wasn't sure what was the dedicated voltage, I tried with the same power supply as the development board (5V USB) and it worked fine.

I used a mosfet I could find in the lab, which is the following: TRANSISTOR MOSFET CANAL N - IRL2703

I got help from the following resource and followed the wiring to make my circuit: control-a-motor-speed-with-arduino

Here's the code I tested, allowing me to set the motor's speed to three different values:

const int motorpin = 5;
const int divider = 3;
int motor_speed = 0;

void setup()
{
  Serial.begin(57600);
  pinMode(motorpin, OUTPUT); 
}

void loop()
{
  for(motor_speed = 0; motor_speed <= 255; motor_speed += (int)(255/divider))
  {
    printSpeed(motor_speed);
    analogWrite(motorpin, motor_speed);
    delay(5000);
  }
}

void printSpeed(int motor_speed)
{
  Serial.print("Current Speed: ");
  Serial.println(motor_speed);
}

circuit control dc motor with n mosfet

Circuit by Enrico Simonetti

picture week 09

Explanations of the circuit

Here's what I understood about the circuit and the choice of these components: in order to drive a DC motor, an important current is needed, which cannot directly be provided by my ATtiny3216 development board. That's why it's necessary to add an amplification circuit, for example based on a NPN transistor. But such transistors are limited when used to drive a DC motor: a voltage drop occurs accross the transistor, and thus less voltage is available for the DC motor. That's why it's a better solution to use a MOSFET instead of a NPN transistor. While the regular transistor is a current amplifier, the MOSFET is a voltage amplifier, allowing better voltage stability accross the motor. Also, it is much easier to use as it can be controlled by monitoring the voltage, which is easy to do with the Pulse Width Modulation principle on my dedicated output pins.

As for the diode, it is very important to avoid that the parasite currents produced when the motor stops propagate in the inverse direction, as they get block by the asymetrical diode.

Apparently I cannot invert the direction of the DC motor with this MOSFET circuit but anyway I just wanted to give it a try.

Sketches and useflow exploration for the final project

A small reminder of the initial idea of my final project:

sketch final project

I gave it more thought, adding the possibility to have a type of element powered by the same supply as the microcontroller, or at least less independent power supplies.

picture week 09

In this sketch I close the data line which sends the color instruction to the neopixel, as in the following video:

It works but I also wanted to detect the contact to be able to increment a time delay from the moment the contact is made. I got inspired by this resource on electronicwings.com to do a simple input pullup on one of the GPIO.

picture week 09

Thus the following code allows me to turn on a led when I close the circuit connected to the GPIO 4 (PIN 3 in arduino). Note that there when the circuit is opened the input pin is connected through a pull up resistor to 5V, and when you close the circuit it's connected to the ground. For this reason the condition you'll use in your code is (trigState==0) to detect the moment when the circuit is closed.

#define TRIG 3
#define LED 4

void setup() {
pinMode(TRIG, INPUT_PULLUP);
pinMode(LED, OUTPUT);
}

void loop() {

  int trigState = digitalRead(TRIG);

 if (trigState==0){
  digitalWrite(LED, HIGH); //turn len on when switch pressed
 }

 else {
  digitalWrite(LED, LOW); //turn len on when switch pressed
 }

  delay(1);    

}

After I suceeded with a simple LED (and a 300 Ohm resistor to protect it), I used this input to trigger the progressvie lighting of the neopixels.

picture week 09

I also did test powering the led strip with a 3.7V LiPo Cell battery. Always be careful to still connect the grounds of the two circuits together!

picture week 09

Small test boards for the final project

Design

I used the trigger tests I did earlier to design small contact pads and minimal boards to ensure connections, add the small components (pull up resistor, resistor on the data line for the neopixel strip, capacitor between Vcc and ground for the neopixel strip) and header pins. Here is a sort of general principle of what I need on the two sides of my opened circuit, that are the microcontroller side and the movable led element side:

picture week 09

The led element can be powered independetly with a battery (I did tests wit a 3.7V LipoCell battery) or with the same Vcc and GND line if it makes contact in the enclosure (see sketch in the previous section).

I thus designed four very small boards:

  • Led element: data input part
  • Led element: contact pads for data input and ground
  • Led element: battery part
  • Microcontroller side: contact pads for trigger and data GPIOs and ground

Led element unit - data input

This is the last version. In the first version I draw both this board and the battery part on the same schematic and PCB. They are now divided in two seperate files.

screen kicad week 09

screen kicad week 09

Led element - Battery

This is the second version, the first one provided a 3 header pin which was not convenient for connecting the LiPo cell battery.

screen kicad week 09

screen kicad week 09

Led element - Contact pads for data input and ground

This PCB will be connected to the first one with angled header pins.

screen kicad week 09

screen kicad week 09

Microcontroller side - Contact pads and GPIOs

![screen kicad week 09](../images/week09/elec-schem-microcontroller-gpio.png

screen kicad week 09

Mill

Here are the tools and settings I used:

  • 0.4mm cylindric mill for the tracks, 2 passes with 40% overlap, -0.05mm depth, 90mm/s X/Y speed and 80mm/s Z speed, 8000rpm spindle
  • 0.4mm cylindric mill for NCC copper clearing, 2 passes with 40% overlap, -0.05mm depth, 90mm/s X/Y speed and 80mm/s Z speed, 8000rpm spindle [Note: I know that a larger mill would have been more adequate and sturdier, but didn't know where the 0.8mm mill was stored. Maybe I should have used a V-shaped mill]
  • 2mm cylindric mill for the edge cuts, cut Z -1.9mm depth, multipasser 0.95mm 180mm/s X/Y speed, 100mm/s Z speed, 8000rpm spindle.

Well I didn't tape perfectly the board to the sacrificial board and some Z differences were too important for proper milling. I broke a 0.4mm mill but it can still do the NCC copper clearing. I chosed to copper clear only the boards with the contact pads. Also I had to recut some boards with a massicot.

picture week 09 picture week 09 picture week 09 picture week 09

Solder

led element contact pads

picture week 09 picture week 09 picture week 09 picture week 09 picture week 09 picture week 09

microcontroller contact pads

picture week 09

led element battery

picture week 09 picture week 09 picture week 09

Test

picture week 09

#include <tinyNeoPixel.h>

#define TRIG 3
#define STRIP_A 5

#define NUMPIXELS_A      16

tinyNeoPixel pixels_a = tinyNeoPixel(NUMPIXELS_A, STRIP_A, NEO_GRBW + NEO_KHZ800);

int delayval = 100;
int r= 200;
int g=20;
int b = 10;

int i=0;

void setup() {
  pinMode(TRIG, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  pixels_a.begin(); // This initializes the NeoPixel library.
  pixels_a.clear(); // This initializes the NeoPixel library.
}

void loop() {

  int trigState = digitalRead(TRIG);

  if (trigState==0){
    pixels_a.setPixelColor(i, pixels_a.Color(r, g, b)); // Moderately bright green color.
    pixels_a.show(); // This sends the updated pixel color to the hardware.
    delay(delayval); // Delay for a period of time (in milliseconds).
    i=i+1;
  }

  else {
  digitalWrite(LED, LOW);
  }

  delay(1);    

}

picture week 09

Final overview

Once I was done testing and uploading sketches to the microcontroller I powered the circuit with a USB sector power supply, 5V. I used the USB power port designed on my board and an USB extension cable.

picture week 09

The led element is powered with a 3.7V LiPo Cell battery.

Here are pictures of the global setup and more detailed pictures of the little PCBs made this week.

picture week 09

picture week 09

picture week 09

picture week 09

picture week 09

picture week 09

picture week 09

Files

All the following folders contains the KiCad file with the electric schematic and the PCB design, as well as the plotted gerber files for F.Cu and the Edge Cuts. Note that the Edge Cuts should be redesigned in any case, according to the structure design evolution.