OverEngineered Pen Holder 2.0
Greetings.
So here's something OverEngineered and different: a Pen Stand or Holder made completely from PCBs and 3D-printed parts.
The goal was to create a pen stand that was entirely different from the typical pen stand. It would have a number of features, such as a room temperature and humidity meter, an onboard light for aesthetics and illumination, and a USB port that could supply 5V to power various devices, including smartphones.
Version 1 of the PenStand I constructed last year was large and heavy; Version 2 is more compact and has an additional ESP8266 Setup that is connected to an SSD1306 OLED and an AHT10 Sensor.
https://www.hackster.io/Arnov_Sharma_makes/overengineered-pen-holder-6a251e#toc-end-result-11
This New Setup is a pen holder that measures the temperature and humidity in the room and shows the data on the SSD1306 display to keep us informed about the current room climate.
This article is about how this device was created, so let's get started with the build.
Material Required
The following were the materials used in this build.
- Custom PCBs Provided by PCBWAY
- ESP12F Module
- SSD1306 OLED
- AHT10 Sensor
- RED LEDs 5mm
- IP5306 Power Management IC
- 1uF 0805 Package Capacitors
- Li-ion 18650 Cell Holder
- Li-ion 3.7V 2900mAh Cell
- 3D-printed parts
- 10K Resistor
- 5.6 Ohms 1206 Package Resistor
- USB Type C Port
Concept
First, the 3D model was created in Fusion360, and it consists of four identically sized rectangular Boards arranged in a cuboid shape. To hold these PCBs together, we designed two inside holders with screw mounting holes. We will add screws to keep the PCB connected to the internal holder.
Internal holders are located on both the top and bottom of the penstand; the bottom holder acts as the lid.
The display, ESP configuration, and AHT10 sensor will be located on the front PCB, while the lithium cell and power management IC arrangement will be located on the bottom PCB.
PCBCAD software was used to generate the outline after exporting the PCB shape DWG file.
PCB Design
The first step in PCB design is to create a total of three different boards: the power management board, which houses an IP5306 IC with a lithium cell, the side PCB, which only acts as a connection board to connect the front PCB's VCC-GND to the power management board, and the front board, which includes an ESP12F setup with an SSD1306 display and an AHT10 sensor.
The Power Management Board consists of an IP5306 IC with all necessary parts, such as input and output capacitors, an inductor, etc.
The battery has an 18650 SMD holder footprint added, and we used a Type C connector for Power IN. Moreover, 10 red LEDs were added in parallel using four 1206 resistors with the IP5306's 5V, and there is a push switch between the 5V and the positive of the LEDs.
After the power board schematic is complete, we use the DWG file exported from Fusion360 to create the PCB outline and add all the components to the board. We placed LEDs on the bottom side of the PCB, and IP5306 IC components, including the battery holder, were all added on the top side of the PCB as the top side will face outwards. LEDs will be placed inside the pen holder to illuminate the entire assembly from the inside.
As the ESP12F is a 3.3V device and 5V will damage the MCU, we added an AMS1117 Voltage Regulator setup to step down 5V from the input side to 3.3V for ESP to function. Next, we prepare the front PCB, which is the ESP12F setup connected with an SSD1306 OLED and AHT10 sensor. The entire board is powered from 5V we get from the power module board.
Both the display and AHT10 sensor are powered by 5 volts.
The same DWG file is used to create the outline for this board as well. AHT is added on one side, and ESP12F is added below the display in the middle.
The third board, which is the side PCB, will be empty and without any ports or connecting pads, but we have added two CON1 ports with PCB traces linked to them that extend 5V and GND from one side of the board to the other.
In addition to serving this purpose, the side PCB has patterns and a solder mask aperture on both sides that allows light from the LEDs to pass through.
PCBWAY
After completing all three PCB Designs, we export their gerber data and send them to PCBWAY for samples.
Three Orders were placed, all for RED Solder mask and white silkscreen.
After placing the order, I received the PCBs within a week, and the PCB quality was pretty great. The silkscreen I used is completely random and asymmetrical, so it's pretty hard to make, but they did an awesome job of making this PCB with no errors whatsoever.
You guys can check out PCBWAY if you want great PCB service at an affordable rate.
Front Temp/Humidity PCB Assembly
- We begin with the Front TEMP/Humidity PCB Assembly process, which required the use of two soldering techniques because it involved both SMD and THT components.
- We first apply solder paste to each SMD component pad using a solder paste dispenser.
- Next, we pick and place all the SMD components in their proper places using an ESD Tweezer.
- Following the pick-and-place procedure, the PCB is carefully lifted and placed on the SMT Reflow hotplate, which heats the PCB from below to the solder paste melting temperature, permanently soldering all of the components to their pads.
- We gather all the THT components, including the OLED display and AHT10 sensor module, position them on their pads, and then solder the pads with a standard soldering iron.
Power Management Board Assembly
Next, we begin the Power Management Board assembly, which followed a process that was identical to the one used to create the front PCB.
- We first add solder paste to each SMD component's pads, and then, using an ESD Tweezer, we pick up and arrange each SMD component into position.
- The PCB is then placed on the SMT Hotplate, where it is reflowed and all of the SMD components are soldered to their pads.
- The remaining THT parts, including the 5mm THT LED, Push Button, USB Port, and push-on-off switch, are then added.
The Board is now complete.
Power Source
The entire system is powered by a 3.7V, 2900mAh 18650 lithium-ion battery, and the ESP12F OLED and LEDs are powered by a reliable 5V output from the IP5306 power management IC.
We insert an 18650 cell into its holder by confirming the polarity, and we then use a multimeter to measure the output voltage, which should be 5 volts; this confirms that the setup is functioning.
Temp/Humidity Board Programming with NODEMCU
You might not be aware that any ESP board can be programmed using the NODEMCU Board.
By taking a NODEMCU board and connecting a jumper with its GND Pin and EN Pin, which puts the onboard ESP8266 of the NODEMCU into sleep mode, we may utilize the NODEMCU to program the external ESP12F module.
This enables us to connect an external ESP Board to NODEMCU; so essentially, we are turning off the ESP board on the NODEMCU and connecting a second ESP Board to a few of its pins.
You can read the article below for additional information about this process.
https://www.hackster.io/Arnov_Sharma_makes/program-esp8266-with-nodemcu-7ea1bb
CODE
#include <Wire.h> #include <AHTxx.h> #include <Adafruit_SSD1306.h> #include <Adafruit_GFX.h> #define OLED_WIDTH 128 #define OLED_HEIGHT 64 #define OLED_ADDR 0x3C Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT); float ahtValue; //to store T/RH result AHTxx aht10(AHTXX_ADDRESS_X38, AHT1x_SENSOR); //sensor address, sensor type void setup() { #if defined(ESP8266) WiFi.persistent(false); //disable saving wifi config into SDK flash area WiFi.forceSleepBegin(); //disable AP & station by calling "WiFi.mode(WIFI_OFF)" & put modem to sleep#endif display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR); display.clearDisplay(); Serial.begin(115200); Serial.println(); while (aht10.begin() != true) //for ESP-01 use aht10.begin(0, 2); { Serial.println(F("AHT1x not connected or fail to load calibration coefficient")); //(F()) save string to flash & keeps dynamic memory free delay(5000); } Serial.println(F("AHT10 OK")); //Wire.setClock(400000); //experimental I2C speed! 400KHz, default 100KHz } void loop() { /* DEMO - 1, every temperature or humidity call will read 6-bytes over I2C, total 12-bytes */ Serial.println(); Serial.println(F("DEMO 1: read 12-bytes")); ahtValue = aht10.readTemperature(); //read 6-bytes via I2C, takes 80 milliseconds display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(30, 0); display.println(F("Temp-")); // Serial.print(F("Temperature...: ")); if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs { display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(35, 25); display.println(ahtValue); display.display(); // Serial.print(ahtValue); } else { printStatus(); //print temperature command status if (aht10.softReset() == true) Serial.println(F("reset success")); //as the last chance to make it aliveelse Serial.println(F("reset failed")); } delay(2000); //measurement with high frequency leads to heating of the sensor, see NOTE ahtValue = aht10.readHumidity(); //read another 6-bytes via I2C, takes 80 milliseconds display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(30, 0); display.println(F("Humd-")); // Serial.print(F("Humd-")); if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs { display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(35, 25); display.println(ahtValue); display.display(); // Serial.println(F(" +-2%")); } else { printStatus(); //print humidity command status } delay(2000); //measurement with high frequency leads to heating of the sensor, see NOTE /* DEMO - 2, temperature call will read 6-bytes via I2C, humidity will use same 6-bytes */ Serial.println(); Serial.println(F("DEMO 2: read 6-byte")); ahtValue = aht10.readTemperature(); //read 6-bytes via I2C, takes 80 milliseconds Serial.print(F("Temperature: ")); if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs { Serial.print(ahtValue); Serial.println(F(" +-0.3C")); } else { printStatus(); //print temperature command status } ahtValue = aht10.readHumidity(AHTXX_USE_READ_DATA); //use 6-bytes from temperature reading, takes zero milliseconds!!! Serial.print(F("Humidity...: ")); if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs { Serial.print(ahtValue); Serial.println(F(" +-2%")); } else { printStatus(); //print temperature command status not humidity!!! RH measurement use same 6-bytes from T measurement } delay(10000); //recomended polling frequency 8sec..30sec } void printStatus() { switch (aht10.getStatus()) { case AHTXX_NO_ERROR: Serial.println(F("no error")); break; case AHTXX_BUSY_ERROR: Serial.println(F("sensor busy, increase polling time")); break; case AHTXX_ACK_ERROR: Serial.println(F("sensor didn't return ACK, not connected, broken, long wires (reduce speed), bus locked by slave (increase stretch limit)")); break; case AHTXX_DATA_ERROR: Serial.println(F("received data smaller than expected, not connected, broken, long wires (reduce speed), bus locked by slave (increase stretch limit)")); break; case AHTXX_CRC8_ERROR: Serial.println(F("computed CRC8 not match received CRC8, this feature supported only by AHT2x sensors")); break; default: Serial.println(F("unknown status")); break; } }
This code uses the AHT10 library to read temperature and humidity values from an AHT10 sensor and display them on an SSD1306 OLED display.
Let's go through the code step by step:
The code includes the necessary libraries for the AHTxx sensor (AHTxx.h), the OLED display (Adafruit_SSD1306.h and Adafruit_GFX.h), and the Wire library for I2C communication.
The code defines constants for the OLED display width, height, and I2C address.
The code defines constants for the OLED display width, height, and I2C address.
An instance of the Adafruit_SSD1306 class is created, named "display, " with the specified width and height.
A floating-point variable "ahtValue" is declared to store the temperature and humidity values.
An instance of the AHTxx class is created, named "aht10, " with the specified I2C address and sensor type.
In the setup() function:
WiFi-related configuration (for the ESP8266) is disabled.
The OLED display is initialized.
Serial communication is started.
The AHT10 sensor is initialized using the begin() function. It waits until the sensor is connected and the calibration coefficients are loaded.
In the loop() function:
DEMO 1: Temperature measurement is performed by calling the readTemperature() function, which returns the temperature value in Celsius. The result is stored in "ahtValue."
The OLED display is cleared, and the temperature value is printed on the display using the display library functions.
If the temperature value is valid (not equal to AHTXX_ERROR), it is displayed on the OLED display. Otherwise, the printStatus() function is called to print the status of the temperature command and perform a soft reset if necessary.
A delay of 2000 milliseconds is added between temperature and humidity measurements.
Humidity measurement is performed by calling the readHumidity() function, which returns the relative humidity value in percentage. The result is stored in "ahtValue."
The OLED display is cleared, and the humidity value is printed on the display using the display library functions.
If the humidity value is valid, it is displayed on the OLED display. Otherwise, the printStatus() function is called to print the status of the humidity command.
A delay of 2000 milliseconds is added before moving on to DEMO 2.
DEMO 2: Temperature measurement is performed again using the readTemperature() function, and the result is stored in "ahtValue.
If the temperature value is valid, it is printed on the serial monitor along with an accuracy range.
Humidity measurement is performed using the readHumidity() function, specifying AHTXX_USE_READ_DATA. This reuses the 6-byte data previously read during the temperature measurement, resulting in faster execution.
If the humidity value is valid, it is printed on the serial monitor along with an accuracy range.
A delay of 10000 milliseconds is added before repeating the loop.
In the loop() function:
DEMO 1: Temperature measurement is performed by calling the readTemperature() function, which returns the temperature value in Celsius. The result is stored in "ahtValue."
The OLED display is cleared, and the temperature value is printed on the display using the display library functions.
If the temperature value is valid (not equal to AHTXX_ERROR), it is displayed on the OLED display. Otherwise, the printStatus() function is called to print the status of the temperature command and perform a soft reset if necessary.
A delay of 2000 milliseconds is added between temperature and humidity measurements.
Humidity measurement is performed by calling the readHumidity() function, which returns the relative humidity value in percentage. The result is stored in "ahtValue."
The OLED display is cleared, and the humidity value is printed on the display using the display library functions.
If the humidity value is valid, it is displayed on the OLED display. Otherwise, the printStatus() function is called to print the status of the humidity command.
A delay of 2000 milliseconds is added before moving on to DEMO 2.
DEMO 2: Temperature measurement is performed again using the readTemperature() function, and the result is stored in "ahtValue."
If the temperature value is valid, it is printed on the serial monitor along with an accuracy range.
Humidity measurement is performed using the readHumidity() function, specifying AHTXX_USE_READ_DATA. This reuses the 6-byte data previously read during the temperature measurement, resulting in faster execution.
If the humidity value is valid, it is printed on the serial monitor along with an accuracy range
A delay of 10000 milliseconds is added before repeating the loop.
The printStatus() function is defined to print the status of the AHT10 sensor. It checks the status returned by the getStatus() function and prints an appropriate message based on the status code.
Overall, this code sets up the OLED display, initializes the AHT10 sensor, reads temperature and humidity values using the AHTxx library, and displays the values on the OLED display and serial monitor.
Final Assembly
- The final assembly method begins by first gathering the four Boards, the bottom lid, and the 3D-printed holder together.
- We begin by using M2 screws to attach the front PCB to the 3D-printed lid before adding the back PCB and the 3D Holder on the top side.
- We then install side panels using the same M2 screws.
- After completing the mechanical assembly, we link the power management board's positive and negative terminals to the side PCB using jumper leads. Then, the positive and negative terminals of the side PCB are connected to the front PCB using the same jumper leads.
The Project is now complete.
RESULT
This project's final result is an overengineered pen stand holder with an ESP12F setup at the front, an OLED screen, an AHT10 sensor for monitoring room temperature and humidity, along with RED light that lights up the entire thing.
This project was a follow-up to my earlier PEN HOLDER project, which was also made entirely of PCBs.
Ultimately, this project demonstrates that FR4 may be used to create body parts in addition to electronics.
Thanks for getting this far; please leave a comment if you need any help with this project.
Special thanks to PCBWAY for supporting this project; do check them out for great PCB service at a lower cost.
Thanks again, and I will be back with a new project soon.
#include <Wire.h>
#include <AHTxx.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT);
float ahtValue; //to store T/RH result
AHTxx aht10(AHTXX_ADDRESS_X38, AHT1x_SENSOR); //sensor address, sensor type
void setup()
{
#if defined(ESP8266)
WiFi.persistent(false); //disable saving wifi config into SDK flash area
WiFi.forceSleepBegin(); //disable AP & station by calling "WiFi.mode(WIFI_OFF)" & put modem to sleep
#endif
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.clearDisplay();
Serial.begin(115200);
Serial.println();
while (aht10.begin() != true) //for ESP-01 use aht10.begin(0, 2);
{
Serial.println(F("AHT1x not connected or fail to load calibration coefficient")); //(F()) save string to flash & keeps dynamic memory free
delay(5000);
}
Serial.println(F("AHT10 OK"));
//Wire.setClock(400000); //experimental I2C speed! 400KHz, default 100KHz
}
void loop()
{
/* DEMO - 1, every temperature or humidity call will read 6-bytes over I2C, total 12-bytes */
Serial.println();
Serial.println(F("DEMO 1: read 12-bytes"));
ahtValue = aht10.readTemperature(); //read 6-bytes via I2C, takes 80 milliseconds
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(30, 0);
display.println(F("Temp-"));
// Serial.print(F("Temperature...: "));
if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
{
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(35, 25);
display.println(ahtValue);
display.display();
// Serial.print(ahtValue);
}
else
{
printStatus(); //print temperature command status
if (aht10.softReset() == true) Serial.println(F("reset success")); //as the last chance to make it alive
else Serial.println(F("reset failed"));
}
delay(2000); //measurement with high frequency leads to heating of the sensor, see NOTE
ahtValue = aht10.readHumidity(); //read another 6-bytes via I2C, takes 80 milliseconds
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(30, 0);
display.println(F("Humd-"));
// Serial.print(F("Humd-"));
if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
{
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(35, 25);
display.println(ahtValue);
display.display();
// Serial.println(F(" +-2%"));
}
else
{
printStatus(); //print humidity command status
}
delay(2000); //measurement with high frequency leads to heating of the sensor, see NOTE
/* DEMO - 2, temperature call will read 6-bytes via I2C, humidity will use same 6-bytes */
Serial.println();
Serial.println(F("DEMO 2: read 6-byte"));
ahtValue = aht10.readTemperature(); //read 6-bytes via I2C, takes 80 milliseconds
Serial.print(F("Temperature: "));
if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
{
Serial.print(ahtValue);
Serial.println(F(" +-0.3C"));
}
else
{
printStatus(); //print temperature command status
}
ahtValue = aht10.readHumidity(AHTXX_USE_READ_DATA); //use 6-bytes from temperature reading, takes zero milliseconds!!!
Serial.print(F("Humidity...: "));
if (ahtValue != AHTXX_ERROR) //AHTXX_ERROR = 255, library returns 255 if error occurs
{
Serial.print(ahtValue);
Serial.println(F(" +-2%"));
}
else
{
printStatus(); //print temperature command status not humidity!!! RH measurement use same 6-bytes from T measurement
}
delay(10000); //recomended polling frequency 8sec..30sec
}
void printStatus()
{
switch (aht10.getStatus())
{
case AHTXX_NO_ERROR:
Serial.println(F("no error"));
break;
case AHTXX_BUSY_ERROR:
Serial.println(F("sensor busy, increase polling time"));
break;
case AHTXX_ACK_ERROR:
Serial.println(F("sensor didn't return ACK, not connected, broken, long wires (reduce speed), bus locked by slave (increase stretch limit)"));
break;
case AHTXX_DATA_ERROR:
Serial.println(F("received data smaller than expected, not connected, broken, long wires (reduce speed), bus locked by slave (increase stretch limit)"));
break;
case AHTXX_CRC8_ERROR:
Serial.println(F("computed CRC8 not match received CRC8, this feature supported only by AHT2x sensors"));
break;
default:
Serial.println(F("unknown status"));
break;
}
}
OverEngineered Pen Holder 2.0
*PCBWay community is a sharing platform. We are not responsible for any design issues and parameter issues (board thickness, surface finish, etc.) you choose.
- Comments(0)
- Likes(2)
- Engineer Sep 18,2024
- Kathryn Fortunato Sep 04,2023
- 0 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
More by Arnov Arnov sharma
- WALKPi PCB Version Greetings everyone and welcome back, This is the WalkPi, a homebrew audio player that plays music fr...
- Delete Button XL Greetings everyone and welcome back, and here's something fun and useful.In essence, the Delete Butt...
- Arduino Retro Game Controller Greetings everyone and welcome back. Here's something fun.The Arduino Retro Game Controller was buil...
- Super Power Buck Converter Greetings everyone and welcome back!Here's something powerful, The SUPER POWER BUCK CONVERTER BOARD ...
- Pocket Temp Meter Greetings and welcome back.So here's something portable and useful: the Pocket TEMP Meter project.As...
- Pico Powered DC Fan Driver Hello everyone and welcome back.So here's something cool: a 5V to 12V DC motor driver based around a...
- Mini Solar Light Project with a Twist Greetings.This is the Cube Light, a Small and compact cube-shaped emergency solar light that boasts ...
- PALPi V5 Handheld Retro Game Console Hey, Guys what's up?So this is PALPi which is a Raspberry Pi Zero W Based Handheld Retro Game Consol...
- DIY Thermometer with TTGO T Display and DS18B20 Greetings.So this is the DIY Thermometer made entirely from scratch using a TTGO T display board and...
- Motion Trigger Circuit with and without Microcontroller GreetingsHere's a tutorial on how to use an HC-SR505 PIR Module with and without a microcontroller t...
- Motor Driver Board Atmega328PU and HC01 Hey, what's up folks here's something super cool and useful if you're making a basic Robot Setup, A ...
- Power Block Hey Everyone what's up!So this is Power block, a DIY UPS that can be used to power a bunch of 5V Ope...
- Goku PCB Badge V2 Hey everyone what's up!So here's something SUPER cool, A PCB Board themed after Goku from Dragon Bal...
- RGB Mixinator V2 Hey Everyone how you doin!So here's a fun little project that utilizes an Arduino Nano, THE MIXINATO...
- Gengar PCB Art Hey guys and how you doing!So this is the GENGAR PCB Badge or a Blinky Board which is based around 5...
- R2D2 Mini Edition So here's something special, A Mini R2D2 PCB that speaks ASTROMECH.Astromech is a fictional language...
- C-3PO Blinky Board Hey guys and how you doing!So this is the C3P0 PCB Badge or a Blinky Board which is based around 555...
- WALKPi Breadboard Version Greetings everyone and welcome back, Here's something loud and musical.Similar to a traditional walk...
-
-
kmMiniSchield MIDI I/O - IN/OUT/THROUGH MIDI extension for kmMidiMini
72 0 0 -
DIY Laser Power Meter with Arduino
84 0 2 -
-
-
Box & Bolt, 3D Printed Cardboard Crafting Tools
120 0 2 -
-
A DIY Soldering Station Perfect for Learning (Floppy Soldering Station 3.0)
415 0 1 -
Custom Mechanic Keyboard - STM32
241 0 3