This project aims to help individuals begin a long term smoking habit. If you ever wished someone should pass on sooner or quit vaping or both this can help. The cigarette box will hold up to 12-18 cigarettes depending on the brand and will feature rewards upon smoking 12 cigarettes. The reward pending a smoked pack is a simple congratulations with a procedural explosion of stars on the screen.
The backside of the soldered boards. The board on the right is the button board, and the left board is the one that hosts the Arduino Pro Micro and power.
Close-up to the soldered board that hosts the Arduino Pro Micro board and the power supply.
Close-up of the soldered board that hosts the tactile button switches.
A 3/4 top-down view of the soldered boards together. The 9V battery is also next to the boards.
In this video, I show operation of the prototype of the machine adding and removing cigarettes using the buttons and it displays a congratulations as a result.
Powering the Arduino Pro Micro board with a 9v battery. Testing the 9v to 5v connection on the bread board. This was done to ensure soldering of the micro board was working as well as the other components were working.
Soldering of the first button board. The issue was the pin connector was placed on the wrong side. Later on I would discover the pin connector I use next would have a broken screw.
A Free-Cad 3D model of cigarette box. The file was successfully exported as an SVG with the holes giving 2mm of leeway in size for the intended components, i.e., the screen and the buttons.
Closeup of initial breadboard. Showcasing wiring of the buttons.
The process initially began with creating a simple breadboard setup, as shown by the video and some of the photos. This setup was then adapted to a soldered version that unfortunately experienced a plethora of issues. After coming to these issues I began trying to assemble a cardboard version of my original; however, I realized that this was not going to work as intended due to a lack of supplies and time needed to make this last minute attempt. That being said the 3D digital model as well as the coding portions went smoothly due to my prior experiences.
Overall, I am unhappy with my project as it turned out unfinished. This came due to a variety of issues in production stemming from soldering. Some issues that occurred include soldered components breaking: wires and a pin connector. These may have been avoided had I tested certain components more rigorously, and others needed to be accomplished in entirely different means. When it came to the wires, I believe that had I soldered solid wires directly to components like the OLED display this would have led to less issues of wires breaking from the soldered connection. The pin connector breaking could have been dealt with simple testing had I considered it to fail in that one of the screws was not working. In terms of what this means I do struggle as a builder as it stems from a natural ineptitude or lack of talent at it compared to other aspects. This building portion was something I should have considered more carefully and focused on designing a larger box that could support non-soldered components: to alleviate the majority of the work time to allow for a functional product. Although, the product may have had its purpose redesigned or be somewhat comically large. Comparatively, the coding portion had gone extremely smoothly from prior knowledge and practice of coding. Although I would prefer to reattempt this project I realistically need to focus on others, as such I do not expect for this project to be further iterated on. That being said, if I were trying to reach my original goal properly I believe 3D printing may be a more advantageous avenue. Due to my familiarity with Blender I believe 3D printing would be more successful. Prior to developing and employing the strategies mentioned before, i.e., ensuring and testing all components thoroughly prior to soldering and using wires that are solid. Afterwards, measuring closely and leaving room for mistakes on the holes of buttons I could create a 3D model that would allow for the insertion of the soldered components have visibility and be able to be used properly. These steps I think would allow for a much smoother second iteration by comparison.
Comment block at top is as specified in project assignment • Code has clean, clear formatting • Code as posted will compile and run properly • Variables have descriptive names, e.g. potVal rather than x • Comments explain what different blocks of code are doing, and/or explain any unusual or potentially difficult-to-understand
/*
Cigar Box (Code)
Reads input of two buttons and outputs information to an OLED (128x64, WxH) display.
This information is related to showcasing the number of cigarettes smoked/stored.
Notably this code is written for the Arduino Pro Micro board, hence why the SDA &
SCL channels are mapped to digital pins. Note that SCREEN_ADDRESS may vary between
different displays and may require a scanner to obtain the proper value.
pin mapping:
Arduino pin | role | description
___________________________________________________________________
16 input Adding a cigarette to the counter
10 input Removing a cigarette from the counter
2 output Used for SDA display information
3 output Used for SCL display information
Code released to the public domain by the author, 11/12/25
*/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Pins for buttons that add and subtract counts
const static uint8_t BUTTON_ADD_PIN = 16;
const static uint8_t BUTTON_SUB_PIN = 10;
const static uint8_t SCREEN_WIDTH = 128; // OLED display width, in pixels
const static uint8_t SCREEN_HEIGHT = 64; // OLED display height, in pixels
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C // May differ from display to display
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
static uint8_t activeCigaretteCount = 0;
static uint32_t cigaretteSmokedCount = 0;
const static uint8_t CIGARETTE_MAX = 18;
static uint32_t timeSinceSmoked = 0;
const static uint32_t SUB_TIME = 250;
const static uint8_t NUM_ICONS = 20;
// 'Star', 16x16px
const static uint8_t STAR_BITMAP_WIDTH = 16;
const static uint8_t STAR_BITMAP_HEIGHT = 16;
static const unsigned char PROGMEM STAR_BITMAP[]= {
0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe,
0x3f, 0xfc, 0x0f, 0xf0, 0x1f, 0xf8, 0x1f, 0xf8, 0x3e, 0x7c, 0x3c, 0x3c, 0x78, 0x1e, 0x60, 0x06
};
void setup() {
Serial.begin(9600);
pinMode (BUTTON_ADD_PIN, INPUT);
pinMode (BUTTON_SUB_PIN, INPUT);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
display.display();
}
void loop() {
readInputs();
}
void readInputs (){
if (digitalRead (BUTTON_ADD_PIN)){
addCigarette();
drawAddedCigarette();
delay(100);
}
uint32_t time = millis();
if (digitalRead (BUTTON_SUB_PIN) && time - timeSinceSmoked >= SUB_TIME){
subCigarette();
drawSmokedCigarette();
delay(100);
}
}
void readInputsNoDraw () {
if (digitalRead (BUTTON_ADD_PIN)){
addCigarette();
delay(100);
}
uint32_t time = millis();
if (digitalRead (BUTTON_SUB_PIN) && time - timeSinceSmoked >= SUB_TIME){
subCigarette();
delay(100);
}
}
void addCigarette (){
activeCigaretteCount += activeCigaretteCount < CIGARETTE_MAX ? 1 : 0;
}
void subCigarette (){
activeCigaretteCount -= activeCigaretteCount > 0 ? 1 : 0;
cigaretteSmokedCount += 1;
}
void drawAddedCigarette () {
display.setTextSize (2);
display.setTextColor (SSD1306_WHITE);
display.setTextWrap (true);
for (int i = 0; i < 100; i++){
display.clearDisplay();
display.setCursor (0, 0);
display.print ("Number of Cigarettes: ");
display.print (activeCigaretteCount);
display.display();
readInputsNoDraw ();
if (cigaretteSmokedCount % 12 == 0 && cigaretteSmokedCount > 0){
drawSmokedCigarettePack();
display.setTextWrap(true);
}
delay (5);
}
display.clearDisplay();
display.display();
}
void drawSmokedCigarette () {
bool drawSpecial = false;
display.setTextSize (2);
display.setTextColor (SSD1306_WHITE);
display.setTextWrap (true);
for (int i = 0; i < 100; i++){
display.clearDisplay();
display.setCursor (0, 0);
display.print ("Number of Cigarettes: ");
display.print (activeCigaretteCount);
display.display();
readInputsNoDraw ();
if (cigaretteSmokedCount % 12 == 0){
drawSmokedCigarettePack();
display.setTextWrap(true);
}
delay (3);
}
display.clearDisplay();
display.display();
}
void drawSmokedCigarettePack (void) {
const uint32_t UPDATE_TIME = 200;
const uint8_t XPOS = 0;
const uint8_t YPOS = 1;
const uint8_t DELTA_Y = 2;
const uint8_t DELTA_X = 3;
uint8_t i, icons[NUM_ICONS][4];
// Initialize Icons
for (i = 0; i < NUM_ICONS; i++){
icons[i][XPOS] = SCREEN_WIDTH / 2;
icons[i][YPOS] = SCREEN_HEIGHT / 2;
icons[i][DELTA_Y] = random (-6,6);
icons[i][DELTA_Y] += icons[i][DELTA_Y] == 0 ? 1 : 0;
icons[i][DELTA_X] = random (-6,6);
icons[i][DELTA_X] += icons[i][DELTA_X] == 0 ? 1 : 0;
}
unsigned long timeStarted = millis();
uint32_t updatedTime = 0;
while (millis() - timeStarted <= 7000){
readInputsNoDraw ();
if (millis () - updatedTime >= UPDATE_TIME){
display.clearDisplay();
for (i = 0; i < NUM_ICONS; i++){
display.drawBitmap (icons[i][XPOS], icons[i][YPOS], STAR_BITMAP, STAR_BITMAP_WIDTH, STAR_BITMAP_HEIGHT, SSD1306_WHITE);
icons[i][XPOS] += icons[i][DELTA_X];
icons[i][YPOS] += icons[i][DELTA_Y];
}
display.display();
updatedTime = millis();
}
}
display.setTextSize (2);
display.setTextColor (SSD1306_WHITE);
int16_t x = 120;
while (x > -630){
display.clearDisplay();
display.setTextWrap (false);
display.setCursor (x, SCREEN_HEIGHT/2);
display.println (F("Congratulations! You smoked a whole Cigarette Pack!"));
display.display();
x -= 3;
delay (3);
readInputsNoDraw ();
}
display.clearDisplay();
}