Professional Documents
Culture Documents
(1)
The SainSmart 12864 Graphic LCD display module is a 128 by 64 pixel resolution LCD
screen that supports Chinese characters, English characters, and graphics [11]. It has blue
backlighting and comes with the ST7920 controller used to communicate with the Arduino
through SPI connections. A 5 mm LED that operates in the 2-3 voltage range is used in the
device with a 200 Ohm resistor that limits the voltage across the LED [16]. A speaker that
operates at 5 volts is used as a buzzer, and its volume is controlled by limiting the voltage
16
delivered to the speaker [17]. Lastly, a standard, solder-less 400-point breadboard with 22-gauge
hookup wires is used for making the interconnections of the prototype.
iii. Hardware Configuration
Figure 6: Prototype Wire Diagram
Certain components in the wire diagram in Figure 6 are not identical to the physical
hardware, but are easily recognizable. For instance, the speaker image in the diagram does not
physically look the same as that of the actual prototype. As seen in the figure, a 9-volt battery is
connected to the breadboard through a battery connector. A push-and-lock switch is used to
control the connection from the battery to the Arduino board to act as a power button. The
Arduino draws voltage from the battery through the Vin pin, which is also directed into the A0
17
analog input pin on the board to measure the battery life status. The other components on the
breadboard are powered with 5 volts from the Arduino. The LCD is interfaced with the Arduino
board using digital pins D11, D12, and D13. These pins assign a device reference number to the
LCD, specify the clock rate of the communication between the Arduino and the LCD, and allow
data exchange between the two.
The ultrasonic sensor has two pins for input and output communications with the Arduino
board. When Stud-E warns the user of improper posture, the Arduino sends a signal on pin D9 to
blink the LED, and if needed, a signal on D10 to sound the buzzer. The user is able to interact
with the device using the three available push buttons. The Menu button is connected to D3 and
allows the user to access the user-friendly menu to change device settings. The Next button is
connected to D4 and allows the user to scroll through the available menu options. The OK button
is connected to D5 and allows the user to make a selection. The three push buttons are connected
to ground with 10 kilo-ohm pull-down resistors, and will only activate when pressed.
Stud-E has the ability to measure the battery level and presents a notification on the LCD
if it detects low battery life. Since the voltage supply is 9 volts, the Arduino implements a
resistive voltage divider composed of two 10 kilo-ohms resistors, thereby decreasing the voltage
read by the Arduino down to 4.5 volts. This voltage delivered to the analog pin A0 is read
continuously so that the analog-to-digital converter on the Arduino will output a 10-bit integer
for read values ranging from 0 to 1023. The output value is then mapped to 9 volts in order to
determine the current voltage. Since the Arduino operates best with an input voltage of 7 to 12
volts, the battery is considered low when it falls below the threshold of 65% of the input voltage.
If the battery fails to stay above the threshold, the LCD will display a warning. The electronics
for the Stud-E are seen in Figure 7.
Figure 7: Electrical Setup of Prototype
18
iv. Software Configuration
The algorithms for the device, seen in Appendix C, have two main sections, the program
code and the user interface menu. The Arduino Integrated Development Environment (IDE) was
used in the software development for the Arduino microcontroller. The IDE uses the Arduino
programming language, similar to another language called Processing. It also uses the avr-gcc
compiler and other open source software.
The Stud-E program includes two libraries called U8glib and EEPROM. The U8glib
library is an open source library that contains useful functions that interface with the LCD. The
EEPROM library is a native Arduino library that contains functions to use the EEPROM on the
microcontroller. In order for Arduino programs to work, they require the implementation of two
functions named setup() and loop(). Global variables for the various components and menu
interface are declared before the setup() function is implemented.
In the setup() function, the pins that the program will use are assigned as either inputs
or outputs. When a rising signal is received on pin D3, the code is written such that the interrupt
will halt the program until the menu() function fully executes and exits. The rest of the
setup() function involves algorithms that detect the users posture, set a threshold on the
measured distance, and load in device settings from the EEPROM. Additional code ensures that
the sensor does not return large outlier distances due to missing the object; if the proper posture
threshold value does not fall within a reasonable range, the calibration process will fail and the
device will need to be restarted.
The loop() function of the program the Arduino microcontroller repeatedly execute the
contents of the loop() function. This function first tests if the timer feature is activated or not. If
it is not activated, the loop() function will continue to evaluate the users posture until the timer
is set. If the measured distance is less than the threshold, meaning the user is slouching, the
program will blink the LED and flash a warning on the LCD. If the user does not correct their
posture within five seconds, the program will continue flashing the LCD and LED, and will also
sound the buzzer at the same time.
However, if the timer feature is activated, the program will start the study session and
display a countdown on the LCD of the time remaining for the current session, while testing the
users posture at approximately the same time. Arduino programs are executed sequentially, so
there is no method to run the study session and test the users posture at exactly the same
instance. Once the study session ends, the program will initiate a break session, which features a
countdown of the time remaining and will not evaluate the users posture. After the break, the
user is prompted to re-calibrate the sensor to readjust the distance threshold.
v. Posture Detecting Algorithm
A specific algorithm must be developed to evaluate the users posture and set a threshold
on the minimum distance the user will be allowed to lean towards the desk. This algorithm relies
19
heavily on common trigonometric properties and functions. Figure 8 below depicts the setup of
the functioning device.
Figure 8: Device and User Setup
During the devices initial setup and calibration, the horizontal distance between the
device and user is measured and assigned to variable i. The LCD then displays a message to
prompt the user to point the device at his face; a distance measurement is then taken and
assigned to variable j. Using Equation 2, the angle that the user sets the device at, , is
recorded.
(2)
The minimum ideal sitting posture angle between a persons lap and torso, , is set to
equal 90 degrees based on previous research. In order for the trigonometric rules applied in the
algorithm to work, the user is initially prompted to sit up straight during the devices initial setup
to mimic a 90-degree right triangle between the user, the desk, and the device sensor. Using the
rule of angle summation in a triangle, the slouching posture angle between the sensors line of
sight and the users torso, a, can be calculated as seen in Equation 3.
(3)
The distance from the sensor to the users head at a slouching position, X, can be
calculated by manipulating the law of sines in Equation 4.
(4)
This X value is set as the distance threshold, which determines whether the users
posture is within optimal range or not. Setting the ideal posture to 90 degrees will simplify the
trigonometric calculations, and the threshold will default to the earlier measured distance stored
20
in the variable j. With this simplification in mind, it is possible for the program to readjust the
threshold just by assigning the threshold to a new measured distance value, and such
recalibration is required when the user returns to the device after the break session of the timer
feature. As the device operates, whenever the user starts to slouch past the threshold, warnings
are delivered via blinking lights and a buzzing noise.
vi. Mechanical Design
A housing for the electronics was designed in order to create a stable and portable device.
The housing consists mainly of three designed base plates made of 6061 aluminum, generic
standoffs, and an adjustable friction hinge. The base plates were designed in Solidworks, and all
of the components were imported from companies websites. This setup can be seen in Figure 9
below.
Figure 9: Stud-E Prototype Model
Two of the plates create a space for the main components, such as the Arduino board,
breadboard, speaker, buttons and LEDs. The last plate is used to mount the LCD screen and
ultrasonic sensor. This is attached to the parallel plates with a frictional hinge, so that the sensor
may rotate about an axis and point at the users face. After the Solidworks model was complete,
finished technical drawings were made and given to the machine shop on Northeastern
Universitys campus, seen in Appendix D. The final prototype is seen in Figure 10.
21
Figure 10: Final Stud-E Prototype
vii. User Interface
The four available buttons and the LCD are the main aspects that govern the users
interactions with the device. The LCD provides information to the user and displays the settings
menu. Once the user presses the Menu button, the program will automatically bring up the Main
Menu. The Main Menu contains submenus, such as Timer, Sound, Reset, and Exit. By selecting
Exit, the program will close the Main Menu and bring the user back to the previous menu. When
the reset option is selected, the user will be prompted to confirm the choice before the variables
reset and stored values return to the defaults. The program defaults have the timer feature turned
off, the study session set at 40 minutes, the break session set at 20 minutes, and the sound set to
mute. In the Timer submenu, the user may change the status of the timer feature and the time
durations for the study and break sessions. In the sound submenu, the user can control the buzzer
volume, as well as to mute or un-mute it.
The menu interface is made possible by the functions incorporated from the U8glib
library. Each page of the menu is displayed by the LCD controller, which requires the text font,
horizontal and vertical pixel location, and the desired text to be defined. The name of each menu
page is displayed at the top row of the menu, and the available options are listed below it. A
cursor of a different color from the background highlights the current item, and makes it clear to
the user which option is currently selected. To be efficient, the program refreshes and redraws
the menu only when it detects that the user has made a scrolling change by pressing the Next
button. Any setting changes that the user makes with the menu interface is automatically
reflected in the program and stored to the EEPROM for later use.
viii. Prototyping Process
The prototyping process started with the electrical wiring of the Arduino microcontroller
to other components through breadboard connections. Algorithms were first developed for the
22
Arduino to interface with the ultrasonic sensor. Once the sensor was working and could detect
posture changes, the LED and buzzer were added to the configuration to warn the user of poor
posture. The LCD was later added to display information about posture changes and other
system information. With the addition of the LCD, algorithms were explored for the menu user
interface. Switch buttons were then added to complement and access the menu, which can be
seen in Figure 11. With the main components in place, a 9-volt battery was acquired to power the
device, and a hardware-software configuration was developed to incorporate a power feature and
a low battery life indicator.
Figure 11: Front View of Prototype
Subsequently, the device proceeded into the mechanical prototyping stage. During this
process, the housing was designed to fit the electronic components. A friction hinge mechanism,
seen in Figure 12, was chosen to secure the LCD and ultrasonic sensor, allowing for easy angle
adjustments. The Arduino, breadboard, and other components were mounted to the base of the
housing. A cutout on the top plate was made to give the user access to the power and menu
buttons. After the mechanical design was finalized, the housing parts were then created in a
campus machine shop. Once the mechanical parts were machined, the electronics were
incorporated into the housing to create a stable, functioning prototype. Finally, the jumper wires
used with the electronic components were replaced with custom hook-up wires to construct a
cleaner operating environment for the user.
23
Figure 12: Prototype Frictional Hinge
XI. Design Improvements
Stud-E was designed to address the main issue of poor posture developing in young
Asian students. As the first design for poor-posture prevention, the prototype mainly focuses on
the situation in which the user would be sitting at his desk in a standard sitting position. This
assumed position does not take into account specialized situations such as the user tilting to the
side or hunching his shoulders, which can also be classified as poor posture.
In addition, the timer feature in Stud-E currently does not allow early session
terminations or time extensions. With these added options, the user would be able to customize
the device to coincide with his natural studying habits. Battery life and power consumption are
also issues for Stud-E; these could be addressed by incorporating integrated circuits and revised
power utilization in the device. Future Stud-E designs can employ a low power and more flexible
system-on-chip platform. Studies and experiments can be performed with the help of customers
to better understand the usability of Stud-E and identify improvement areas. With more time and
resources, Stud-E will contain features fit for different operational scenarios, making it more
versatile for the consumer.
XII. Business Model
i. Company Vision
The company aims to address the common problem that Asian Americans experience
while studying: poor posture. In the future, Stud-E will be mass-produced and marketed to the
United States Department of Education. Stud-E will be used in the public school system and
many households across the nation. In this way, students will develop good posture habits by the
time they reach adulthood, and practice them throughout their lives.
ii. Financial Breakdown & Price Policy
Stud-Es prototype cost approximately $93.76. Appendix E contains the breakdown of
both the prototype and bulk production cost. Materials and parts are cheaper when purchased in
24
larger quantities, but the largest decrease in price was due to substituting the Arduino prototype
board and breadboard with a printed circuit board. Other significant reductions in cost were due
to the bulk purchase of the buzzer, LCD screen, and hinge.
Maintaining the quality and price of Stud-E during mass production without sacrificing
the customers experience and health benefits is of the highest priority. However, a price level
that balances the companys profit margin and product attractiveness is ideal. This means that
while top grade parts might not be used, the product quality will still be above average.
If the company is successful in collaborating with large companies, or even the
Department of Education, discounts would be given for bulk purchases. Lower prices are more
appealing to the public and would assist in maximizing sales and profit.
iii. Market Strategy
The target audience of Stud-E is 8 to 14 year old Asian Americans. Stud-Es place in the
market would mainly be in general office supply stores, superstores, and pharmacies.
Approaching stores such as Staples, Walmart, Target, and CVS would be best as these stores
appeal to Stud-Es consumer group. Local branches of these companies would be approached
first and expansion would occur later on. When approaching potential customers or companies,
existing problems with posture would be shown through statistics and demographics to make the
products purpose, solving those problems, clear.
A. Market Analysis and Competitive Stance
Due to the increased use of computers and technology today, young people studying for
long hours find themselves in more situations where they are hunched over papers or screens.
Despite this trend, research shows that there are currently only two other products in the market
whose functions compare to that of Stud-E. LUMObacks sole function is to correct posture
through the use of a belt. Designed with a greater emphasis on dealing with posture-related
health problems, LUMOback is not an effective or comprehensive study device for long hours of
managed, concentrated study. The other possible substitute product in this market is Phillips
ErgoSensor monitor. As the name states, this is a monitor with integrated posture-correction
functions. While it covers issues that could originate from bad back or neck-postures, it is not
nearly as portable, nor as economic and practical as Stud-E. To this end, Stud-E is designed to
target a gap in the student market, in order to provide for longer, healthier, and more focused
study sessions.
B. Consumer Analysis
During an average persons 20-year long academic career, students spend thousands of
hours at their desks studying. As this habit develops, it becomes both increasingly detrimental to
ones health, as well as a habit difficult to break. While this problem is drastically evident in
teens, Asians experience this issue more intensely due to the extra attention placed on academics
in early childhood. A study by the Chinese newspaper DongJiang Times News reveals that 59%
25
of primary school students have incorrect postures in front of their desks, which cause spinal and
optical problems. Another study by Yan Tai Evening News concludes that 40% of cases of
myopia, or nearsightedness, in Chinese primary school students are caused by incorrect posture.
While statistically half the students in primary schools have bad posture, many more students
develop these issues later in life. Stud-E was developed to ameliorate these poor posture issues,
which reflect in the development of myopia and other illnesses.
iv. Product Assortment, Strategy, and Goals
The life expectancy for Stud-E depends on the amount of usage and the environment that
the product is used in; the limiting factor for having a long product life is the LCD screen
backlight. These lights tend to dim and eventually die out after about 60,000 hours of use [18].
Regardless of the product life, new and improved versions of the product will be developed
yearly, with software updates available when necessary. The SWOT analysis below shows areas
of improvement, as well as things to take cautionary measures against. The company will be
taking advantage of all opportunities while maintaining product strengths.
Table 1: SWOT Analysis
Strengths
Originality
Accuracy
Room for Growth
Weaknesses
Constant Calibration Necessary
Not Fully Automated
Short Battery Life
Opportunities
Collaboration with the Department of
Education
Lack of Competitors in Market
Threats
Emergence of More Featured
Products
Limited Manufacturer Ties
As of now, there is much room for product improvement. Aside from software and
hardware updates mentioned previously, Stud-E will be further developed aesthetically. With
time and more funding, Stud-E will be sold in an assortment of colors and designs to appeal to
the younger population, the products target audience. The metal casing of the product will be
replaced with plastic, and the contents will be packaged more compactly. This will help to
reduce prices and attract more customers.
v. Sales Approach
As the company expands and the labor force increases, many approaches for maximizing
sales will be made. In order to effectively market Stud-E, advertisements and promotions would
be placed strategically on other products related to reading, writing, and studying. Advertising
would be done through online, television, and radio station advertisements. An online website
will be created with the products information, its availability in stores, and options to purchase
online. For a grassroots connection, visits to middle schools and high schools would be
26
coordinated to spread information about posture. This would lead to the product potentially being
sold in school stores. To promote the product even more, sales pitches would be made to large
companies and departments of education across the nation.
A. Promotion
Before looking at the Stud-Es promotional campaign, it is important to research the
campaigns of its competitors. As mentioned before, the market in this field is rather
undeveloped, and only two competitors exist: LUMOback and the ErgoSensor monitor. Research
shows that LUMOback takes full advantage of the internet media. The product is reviewed on
many different health, technology, and entrepreneurial websites. Other than having their own
dedicated website highlighting all of LUMObacks features, they have also have an established
Facebook and Twitter page.
The ErgoSensor monitor, on the other hand, has few product advertisements. As the
posture correction feature is not the main highlight of this product, it is not widely advertised.
Moreover, it may also indicate that this feature does not serve its purpose as well as it was
intended to.
Likewise, promotional activities for Stud-E may also highlight cost-efficient, socially
influential media methods such as Facebook and Twitter pages. Setting up a domain name under
Stud-E will not be more than $20 per year. Excluding website design cost, establishing a Stud-E
website will cost less than $200 per year. Setting up advertisements on magazines and websites
costs around $20, while newspaper advertisements cost anywhere from $20 to $40 depending on
what day and what section it is put on. Lastly, Youtube is also available for Stud-Es promotional
campaign, providing advertising rates at about $0.10 to $0.30 per view.
Print advertising is also still widely used today. Handing out brochures is a fast, simple,
and prevalent method used. The rates in this field vary, but average around $150 for 200
brochures. These can be prepared for technology fairs as a means of promotion, or during
exhibitions. Although not as professional, flyers are much cheaper and are about half the price of
brochures; 200 flyers only cost around $80.
Table 2: Table of Available Economic Promotion Methods
Method Cost 1 Year 2 Years 3 Years 4 Years 5 Years
Website
($200/year) $200
Magazine Ad. ($20/ad) x 12
months
$240 $480 $720 $960 $1,200
27
Youtube Video Ad.
($100-$300/1000
view)
$100-
300
$200-
600
$300-
900
$400-
1,200
$400-
1,500
Brochures ($150/200
brochures)
$150 $300 $450 $600 $750
Flyers ($400/1000
flyers)
$400 $800 $1,200 $1,600 $2,000
As shown in the table above, prices will vary depending on the quantity of each item. As
a startup, it is important to promote the new product on a large scale during the launch phase.
Taking an average quantity of column three in the table for each item, the total promotional cost
is estimated to be $3,050.
In addition to these methods, the promotion of Stud-E should also include extroverted
promotional methods, such as contacting press, fairs, and exhibitions. Excluding costs for such
activities, the promotional expense is already $3,000 per year. As a startup, while it is important
to advertise Stud-E during this phase, a budget must be taken into consideration, which may limit
the number of promotional activities available. This budget will most likely vary in the future,
however, for an initial estimate, Stud-E advertising expenditures will be around $4,000 a year.
B. Distribution
Distribution is extremely important in marketing, but as Stud-E is a consumer product,
the large companies selling the product would have their own distribution methods.
XIII. Conclusion
Stud-E was designed to prevent poor posture in Asian-American students. The target
audience was decided based on studies supporting that between the ages of 8 and 14, children
have the best chance of developing and retaining good postural habits. In addition, the high
academic standard set by Asian culture causes a need for students to study longer. In its current
design, Stud-E addresses and solves these issues.
Stud-E tracks users posture while studying and warns them when they begin to slouch.
By practicing this over a period of time, students will develop and retain good posture habits.
The device uses an ultrasonic sensor, LCD, and Arduino board. It continuously measures the
angle the user is sitting at, and compares it to a threshold. If the measurement is less than the
threshold, a LED and buzzer will signal the user to adjust his/her posture. Other features of Stud-
E include an interactive menu with customizable settings and a timer for setting personal
studying schedules.
While Stud-E effectively monitors posture and acts as a study aid, there is plenty of room
for improvement. The design may be improved with changes to the outer housing. A lighter
28
material can be used to significantly reduce the weight of Stud-E, allowing it to be more
portable. The aesthetic aspects of the product could also be modified to transform Stud-E into
various cartoon characters. Some technical improvements could be done to enhance features and
power efficiency.
In order to market this product in the industry, the team takes advantage of retail
distribution methods, and uses low-cost media techniques mixed with print promotions. The
Stud-E campaign also looks at exhibition opportunities at technology, health, and education fairs.
By marketing this product to the correct audience, Stud-E will ultimately address the issue of
poor posture development in young Asian Americans.
29
XIV. References
[1] D. Soraya, Top 5 Consequences to Bad Posture, Los Angeles Sentinel, 26-Feb-2009.
[Online]. Available:
http://www.lasentinel.net/index.php?option=com_content&view=article&id=6528:top-
5-consequences-to-bad-posture&catid=67&Itemid=157. [Accessed: 18-May-2013].
[2] Good Working Positions, OSHA Ergonomic Solutions: Computer Work Stations.
[Online]. Available:
https://www.osha.gov/SLTC/etools/computerworkstations/positions.html. [Accessed:
18-May-2013].
[3] E. Geldhof, G. Cardon, I. De Bourdeaudhuij, and D. De Clercq, Back posture
education in elementary schoolchildren: a 2-year follow-up study, Eur Spine J, vol. 16,
no. 6, pp. 841850, Jun. 2007.
[4] M. J. Eaton and M. H. Dembo, Differences in the motivational beliefs of Asian
American and non-Asian students, Journal of Educational Psychology, vol. 89, no. 3,
pp. 433440, Sep. 1997.
[5] C. Rampell, Children of Immigrants Study More, The New York Times, 12-Jul-2013.
[Online]. Available: http://economix.blogs.nytimes.com/2012/07/12/children-of-
immigrants-study-more/. [Accessed: 21-May-2013].
[6] S. Gaglani, New Device Watches Your (LUMO)Back: Interview with Founder
Monisha Perkash, medGadget, 10-Jul-2012. [Online]. Available:
http://www.medgadget.com/2012/07/new-device-watches-your-lumoback-interview-
with-founder-monisha-perkash.html. [Accessed: 18-May-2013].
[7] M. Lasky, Review: LUMOback Posture Belt, Wired Magazine, 15-Mar-2013.
[Online]. Available: http://www.wired.com/reviews/2013/03/lumoback/. [Accessed:
22-May-2013].
[8] The Science of LUMOback, LUMO BodyTech Inc, 2013. [Online]. Available:
http://www.lumoback.com/learn/the-science-of-lumoback/. [Accessed: 18-May-2013].
[9] A. Chang, New Philips Monitor Uses Sensor to Promote Better Posture, Wired
Magazine, 06-Apr-2012. [Online]. Available:
http://www.wired.com/gadgetlab/2012/04/new-philips-monitor-uses-sensor-to-
promote-better-posture/. [Accessed: 22-May-2013].
[10] O. Jones, Proximity Sensing, Beyond Bits, no. 3, pp. 4952, Jul-2008.
[11] SainSmart. "SainSmart 12864 128x64 Graphic Blue LCD Display Module Backlight
For Arduino AVR," sainsmart.com. [Online]. Available:
http://www.sainsmart.com/sainsmart-12864-128x64-graphic-blue-lcd-display-module-
backlight-for-arduino-avr.html [Accessed: June 2013]
[12] Sharp IR Rangers Information, Acroname Robotics, 06-Mar-2011. [Online].
Available: http://www.acroname.com/robotics/info/articles/sharp/sharp.html.
[Accessed: 18-May-2013].
30
[13] G. McComb, PING))) Ultrasonic Distance Sensor, Parallax Inc., 21-Feb-2012.
[Online]. Available: http://learn.parallax.com/kickstart/28015. [Accessed: 18-May-
2013].
[14] Arduino. "Arduino Uno," arduino.cc. [Online]. Available:
http://arduino.cc/en/Main/ArduinoBoardUno [Accessed: June 2013].
[15] SainSmart. "Ultrasonic Ranging Detector Mod HC-SR04 Distance Sensor,"
sainsmart.com. [Online]. Available: http://www.sainsmart.com/ultrasonic-ranging-
detector-mod-hc-sr04-distance-sensor.html [Accessed: June 2013].
[16] Microtivity. "5mm Assorted Clear LED w/ Resistors (6 Colors, Pack of 60),"
microtivity.com. [Online]. Available: http://www.microtivity.com/p/IL184/5mm-
assorted-clear-led-w-resistors-6-colors-pack-of-60 [Accessed: June 2013].
[17] Vetco Electronics. "Piezo Speaker Module for Arduino," vetco.net. [Online]. Available:
http://www.vetco.net/catalog/product_info.php?products_id=13589&keywords=piezo
[Accessed: June 2013].
[18] Burden, Jack. LCD TV Misconceptions: Six Common Myths about LCD Displays,
LCDTV Buying Guide. [Online]. Available: http://lcdtvbuyingguide.com/lcdtv/lcdtv-
misconceptions.shtml
31
XV. Appendices
i. Appendix A Ultrasonic & Infrared Sensor Testing Raw Data
32
ii. Appendix B Prototype Budget Request and Parts List
33
iii. Appendix C Prototype Algorithms
A. Stud-E Program Flowchart, Part 1
34
B. Stud-E Program Flowchart, Part 2
35
C. Stud-E Program Flowchart, Part 3
36
D. Stud-E Program Code
/***************************************************************************/
/*
Stud-E
A device that helps promote proper sitting posture and studying habits,
aimed at an audience of young Asian students, with marketing targeted
mainly at the students and their parents.
A design project for the 2013 InnoService design competition.
Northeastern SASE Team:
Victoria Asman (Team lead, mechanical engineer)
Joy Rebustes (Team vice, mechanical engineer)
Yufeng Wang (Electrical & computer engineer)
Lukuan Yu (Electrical engineer)
Bernard Liang (Electrical engineer)
Joseph Alim (Mechanical engineer)
Program code for the Arduino Uno R3 that powers the device.
Author: Yufeng Wang
Created: 6/23/2013
Last modified by: Yufeng Wang
Date: 9/16/2013
*/
/***************************************************************************/
#include <U8glib.h> //library for SainSmart 12864 LCD
#include <EEPROM.h>
/************************** global variables ******************************/
/* LCD pin assignments
LCD_MODEL u8g(SCK, SID, CS, RESET); */
U8GLIB_ST7920_128X64 u8g(13, 11, 12, U8G_PIN_NONE);
//variables for battery status
const int battery = 0;
int voltage;
//variables for ultrasonic sensor
const int trig = 6;
const int echo = 7;
//variable for speaker
const int speaker = 10;
//variable for LED
const int led = 9;
//switches and buttons
const int buttonOK = 5;
const int buttonNext = 4;
37
//variables for calculations
const double pie = acos(-1); //in radians, 3.14
const double theta = (90.0 * pie) / 180.0; //convert degrees to radians
double threshold;
//addresses for EEPROM
const int eeprom_timer = 0; //default: off, zero
const int eeprom_study = 1; //default: 40 minutes
const int eeprom_break = 2; //default: 20 minutes
const int eeprom_mute = 3; //default: off, zero
const int eeprom_volume = 4; //default: medium, 6
//variables for user settings
volatile int timer_stat;
volatile int study_t;
volatile int break_t;
volatile int mute_stat;
volatile int volume;
//variables for timing
unsigned long time_sensor;
unsigned long time_base;
unsigned long time_left;
unsigned long time_passed;
//variable for timer feature
volatile int study = 1; //current session, 0=break, 1=study
//variable sets for menu UI
volatile int main_menu_redraw;
volatile int main_menu_current = 4; //highlight Exit
const int main_menu_items = 5;
char *main_menu_text[main_menu_items] = {
"Main Menu", "Timer", "Sound", "Reset", "Exit"};
volatile int main_timer_redraw;
volatile int main_timer_current = 4; //highlight Back
const int main_timer_items = 5;
char *main_timer_text[main_timer_items] = {
"Main > Timer", "Status", "Study time", "Break time", "Back"};
volatile int timer_status_redraw;
volatile int timer_status_current = 3; //highligh Back
const int timer_status_items = 4;
char *timer_status_text[timer_status_items] = {
"Timer > Status", "On", "Off", "Back"};
volatile int timer_study_redraw;
volatile int timer_study_current = 4; //highligh Back
const int timer_study_items = 5;
char *timer_study_text[timer_study_items] = {
"Timer > Study", "20 min", "30 min", "40 min", "Back"};
volatile int timer_break_redraw;
volatile int timer_break_current = 4; //highligh Back
const int timer_break_items = 5;
char *timer_break_text[timer_break_items] = {
38
"Timer > Break", "20 min", "30 min", "40 min", "Back"};
volatile int main_sound_redraw;
volatile int main_sound_current = 3; //highlight Back
const int main_sound_items = 4;
char *main_sound_text[main_sound_items] = {
"Main > Sound", "Volume", "Mute", "Back"};
volatile int sound_volume_redraw;
volatile int sound_volume_current = 4; //highlight Back
const int sound_volume_items = 5;
char *sound_volume_text[sound_volume_items] = {
"Sound > Volume", "High", "Medium", "Low", "Back"};
volatile int main_reset_redraw;
volatile int main_reset_current = 4; //highlight No
const int main_reset_items = 5;
char *main_reset_text[main_reset_items] = {
"Return settings", "to default.", "Are you sure?", "Yes", "No"};
/*************************** end: global variables *************************/
void setup()
{
//assign pin states
pinMode(trig, OUTPUT);
pinMode(echo, INPUT);
pinMode(speaker, OUTPUT);
pinMode(led, OUTPUT);
pinMode(buttonOK, INPUT);
pinMode(buttonNext, INPUT);
attachInterrupt(1, menu, RISING);
//Serial.begin(9600);
//read sensor once to start it up
//sensor_read();
u8g.begin();
lcd_print_logo();
millisec(1500);
clear_screen();
lcd_print1((char *) "Initializing...");
double table_length = sensor_read();
while (table_length > 2000.0) {table_length = sensor_read();}
//Serial.println(table_length);
millisec(1000);
//print: adjust sensor, sit straight
lcd_prompt_user();
while (!digitalRead(buttonOK)) { ;}
millisec(1000);
39
lcd_print1((char *) "Calibrating...");
double relative_dist = sensor_read();
while (relative_dist > 2000.0) {relative_dist = sensor_read();}
//Serial.println(relative_dist);
millisec(1000);
double phi = acos(table_length / relative_dist);
double angle = pie - phi - theta;
threshold = (table_length * sin(theta)) / sin(angle);
Serial.println(threshold);
if (threshold > 0.0 && threshold < 2000.0) {
lcd_print1((char *) "Setup complete.");
millisec(1250);
clear_screen();
} else {
lcd_warning();
while (1) {delay(5000);}
}
//load user settings
timer_stat = EEPROM.read(eeprom_timer);
study_t = EEPROM.read(eeprom_study);
break_t = EEPROM.read(eeprom_break);
mute_stat = EEPROM.read(eeprom_mute);
volume = EEPROM.read(eeprom_volume);
lcd_main_info();
millisec(500);
} //end: setup()
void loop()
{
if (timer_stat) {
lcd_start_msg();
millisec(1250);
if (study && timer_stat) {
time_left = study_t;
lcd_main_info();
time_base = millis();
time_passed = millis() - time_base;
while ((time_passed <= ((unsigned long)study_t * 60 * 1000)) &&
timer_stat) {
time_left = study_t - ((time_passed / 1000) / 60);
lcd_main_info();
test_posture();
time_passed = millis() - time_base;
}
if (timer_stat) {
time_left = 0;
lcd_main_info();
test_posture();
}
if (timer_stat) {
40
lcd_end_msg();
millisec(1250);
lcd_prompt_ready();
}
while (!digitalRead(buttonOK) && timer_stat) {
if (test_posture()) {lcd_prompt_ready();}
}
millisec(1000);
study = !study;
} else if (!study && timer_stat) {
time_left = break_t;
lcd_main_info();
time_base = millis();
time_passed = millis() - time_base;
while ((time_passed <= ((unsigned long)break_t * 60 * 1000)) &&
timer_stat) {
time_left = break_t - ((time_passed / 1000) / 60);
lcd_main_info();
time_passed = millis() - time_base;
}
if (timer_stat) {
time_left = 0;
lcd_main_info();
millisec(1000);
}
if (timer_stat) {
lcd_end_msg();
millisec(1250);
//message for adjusting sensor when user returns from break
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
h = u8g.getFontAscent() - u8g.getFontDescent();
y = (u8g.getHeight() - (h*3) - 2) / 2;
x = (w - u8g.getStrWidth("Adjust sensor as")) / 2;
u8g.drawStr(x, y, "Adjust sensor as");
y = y + h + 1;
x = (w - u8g.getStrWidth("needed. Press OK")) / 2;
u8g.drawStr(x, y, "needed. Press OK");
y = y + h + 1;
x = (w - u8g.getStrWidth("to continue.")) / 2;
u8g.drawStr(x, y, "to continue.");
} while (u8g.nextPage());
}
while (!digitalRead(buttonOK) && timer_stat) { ;}
41
millisec(1000);
if (timer_stat) {
threshold = sensor_read(); //redefine threshold
}
study = !study;
} //end: else-if
} else if (!timer_stat) {
//double distance_mm = sensor_read();
//Serial.println(distance_mm);
if (sensor_read() < threshold) {
time_sensor = millis();
blink_led(500);
while (sensor_read() < threshold) {
if ((millis() - time_sensor) >= 5000) {
if (mute_stat) {
blink_led(200);
} else {
blink_sound(400);
}
} else {
blink_led(400);
}
} //end: while
} //end: if
} //end: else-if
lcd_main_info();
} //end: loop()
/* useful miscellaneous functions */
// millisec: while interval has not passed yet, do nothing
// alternative to delay(), but able to catch interrupts
void millisec(unsigned long interval)
{
unsigned long time;
time = millis();
while ((millis() - time) <= interval) { ;} //empty loop
}
// clear_screen: writes an empty picture loop, clearing the screen
void clear_screen(void)
{
u8g.firstPage();
do {
//empty
} while (u8g.nextPage());
}
/* posture-related functions */
// test_posture: reads the distance, blink led and/or speaker
// to be used with study session of timer feature
// returns 1 if refresh of main info screen is needed
int test_posture(void)
{
//double distance_mm = sensor_read();
//Serial.println(distance_mm);
42
if (sensor_read() < threshold) {
time_sensor = millis();
blink_led(500);
while (sensor_read() < threshold) {
if ((millis() - time_sensor) >= 5000) {
if (mute_stat) {
blink_led(200); //rapid led blink
} else {
blink_sound(400); //speaker and led
}
} else {
blink_led(400); //if 5 seconds has not passed
}
} //end: while
return 1;
} else {
return 0;
}
} //end: test_posture()
// sensor_read: use ultrasonic sensor to read distance
// returns calculated distance of type double
double sensor_read(void)
{
digitalWrite(trig, LOW);
delayMicroseconds(3); //function accurate 3 microseconds and up
digitalWrite(trig, HIGH);
delayMicroseconds(10); //10 microseconds, send 8 pulses of 40 kHz
digitalWrite(trig, LOW);
unsigned long duration = pulseIn(echo, HIGH); //returns time in
microseconds
return (((double) duration * 0.34029) / 2.0); //millimeters, speed_sound:
340.29 m/s
//return (((double) duration / 2.9387) / 2.0); //millimeters, alternative
//return (((double) duration * 0.034029) / 2.0); //centimeters
//return (((double) duration / 29.3867) / 2.0); //centimeters, alternative
}
// blink_led: turn LED on then off, according to milliseconds specified
// also flashes a warning message on lcd
void blink_led(unsigned long interval)
{
lcd_print1((char *) "Sit straight!");
digitalWrite(led, HIGH);
millisec(interval);
clear_screen();
digitalWrite(led, LOW);
millisec(interval);
}
// blink_sound: turn led and speaker on and off, speaker at specified volume
// interval time is in milliseconds, also flashes a warning message on lcd
void blink_sound(unsigned long interval)
43
{
lcd_print1((char *) "Sit straight!");
digitalWrite(led, HIGH);
analogWrite(speaker, volume);
millisec(interval);
clear_screen();
digitalWrite(led, LOW);
analogWrite(speaker, 0);
millisec(interval);
}
/* lcd-related functions */
// lcd_print_logo: name of device is Study Buddy
void lcd_print_logo(void)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_timR18); //17 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
h = u8g.getFontAscent() - u8g.getFontDescent();
x = (w - u8g.getStrWidth("Stud-E")) / 2;
y = (u8g.getHeight() / 2) - (h/2) - 4;
u8g.drawStr(x, y, "Stud-E");
x = (w - 120) / 2; //box frame width 120 pixels
y = (u8g.getHeight() - 60) / 2; //box frame height 60 pixels
u8g.drawFrame(x, y, 120, 60);
u8g.setFont(u8g_font_5x7); //6 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
u8g.setDefaultForegroundColor();
h = u8g.getFontAscent() - u8g.getFontDescent();
x = (w - u8g.getStrWidth("Northeastern SASE")) /2;
y = y + 60 - h - 2;
u8g.drawStr(x, y, "Northeastern SASE");
} while (u8g.nextPage());
}
// lcd_print1: print one line of text at the center of the screen
void lcd_print1(char *text)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
44
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
h = u8g.getFontAscent() - u8g.getFontDescent();
x = (w - u8g.getStrWidth(text)) / 2;
y = (u8g.getHeight() / 2) - h;
u8g.drawStr(x, y, text);
} while (u8g.nextPage());
}
// lcd_prompt_user: have user adjust sensor and sit straight
void lcd_prompt_user(void)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
h = u8g.getFontAscent() - u8g.getFontDescent();
y = (u8g.getHeight() - (h*4) - 3) / 2;
x = (w - u8g.getStrWidth("Tilt sensor to")) / 2;
u8g.drawStr(x, y, "Tilt sensor to");
y = y + h + 1;
x = (w - u8g.getStrWidth("align with face.")) / 2;
u8g.drawStr(x, y, "align with face.");
y = y + h + 1;
x = (w - u8g.getStrWidth("Sit up straight,")) / 2;
u8g.drawStr(x, y, "Sit up straight,");
y = y + h + 1;
x = (w - u8g.getStrWidth("then press OK.")) / 2;
u8g.drawStr(x, y, "then press OK.");
} while (u8g.nextPage());
}
// lcd_warning: calibration failed, warn user to restart
void lcd_warning(void)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
45
h = u8g.getFontAscent() - u8g.getFontDescent();
x = (w - u8g.getStrWidth("Calibration failed.")) / 2;
y = (u8g.getHeight() / 2) - h;
u8g.drawStr(x, y, "Calibration failed.");
x = (w - u8g.getStrWidth("Please restart!")) / 2;
y = y + h + 1;
u8g.drawStr(x, y, "Please restart!");
} while (u8g.nextPage());
}
// lcd_start_msg: reads the current session and prints start message
void lcd_start_msg(void)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
h = u8g.getFontAscent() - u8g.getFontDescent();
y = (u8g.getHeight() - (h*3) - 2) / 2;
x = (w - u8g.getStrWidth("Starting")) / 2;
u8g.drawStr(x, y, "Starting");
char *text;
if (study) {
text = "study";
} else if (!study) {
text = "break";
}
y = y + h + 1;
x = (w - u8g.getStrWidth(text)) / 2;
u8g.drawStr(x, y, text);
y = y + h + 1;
x = (w - u8g.getStrWidth("session")) / 2;
u8g.drawStr(x, y, "session");
} while (u8g.nextPage());
} //end: lcd_start_msg()
// lcd_end_msg: reads the current session and prints end message
void lcd_end_msg(void)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
46
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
h = u8g.getFontAscent() - u8g.getFontDescent();
char *text;
if (study) {
text = "Study";
} else if (!study) {
text = "Break";
}
y = (u8g.getHeight() - (h*3) - 2) / 2;
x = (w - u8g.getStrWidth(text)) / 2;
u8g.drawStr(x, y, text);
y = y + h + 1;
x = (w - u8g.getStrWidth("session")) / 2;
u8g.drawStr(x, y, "session");
y = y + h + 1;
x = (w - u8g.getStrWidth("finished")) / 2;
u8g.drawStr(x, y, "finished");
} while (u8g.nextPage());
} //end: lcd_end_msg()
// lcd_prompt_ready: wait until user is ready to move to next session
// to be used with study session of timer feature
void lcd_prompt_ready(void)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
h = u8g.getFontAscent() - u8g.getFontDescent();
y = (u8g.getHeight() - (h*3) - 2) / 2;
x = (w - u8g.getStrWidth("Press OK to")) / 2;
u8g.drawStr(x, y, "Press OK to");
y = y + h + 1;
x = (w - u8g.getStrWidth("continue to")) / 2;
u8g.drawStr(x, y, "continue to");
y = y + h + 1;
x = (w - u8g.getStrWidth("next session.")) / 2;
u8g.drawStr(x, y, "next session.");
} while (u8g.nextPage());
}
// lcd_main_info: prints the main information screen
47
// main aspects are current session, timer status, volume level, and a main
message
void lcd_main_info(void)
{
u8g.firstPage();
do {
u8g_uint_t w, h, x, y;
u8g.setDefaultForegroundColor();
w = u8g.getWidth();
//header: session and battery indicator
char *header;
if (study) {
header = "Session:Study";
} else if (!study) {
header = "Session:Break";
}
u8g.setFont(u8g_font_5x7); //6 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent(); //height of current line
x = 0;
y = 1;
if (timer_stat) {
u8g.drawStr(x, y, header);
}
//analogRead() returns a 10-bit integer, ranges from 0 to 1023
//a voltage divider circuit is used to bring the battery's 9v into range
//Vin is approximately 4.5v at theoretically max
voltage = (analogRead(battery) * (4.5 / 1024) * 2) / 9.0 * 100;
if (voltage <= 65) {
x = w - u8g.getStrWidth("Low Batt!");
u8g.drawStr(x, y, "Low Batt!");
//u8g.setPrintPos(x, y);
//u8g.print(voltage);
//Serial.println(voltage);
}
//main message
char *message;
if (timer_stat) {
message = "Remaining minutes:";
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
y = y + h + 6; //set y position to below previous line
h = u8g.getFontAscent() - u8g.getFontDescent(); //redefine height
x = (w - u8g.getStrWidth(message)) / 2; //center text
u8g.drawStr(x, y, message);
u8g.setFont(u8g_font_timR18); //17 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
y = y + h + 4;
if (time_left >= 10) {
x = (w - u8g.getStrWidth("40")) / 2;
} else if (time_left < 10) {
48
x = (w - u8g.getStrWidth("4")) / 2;
}
u8g.setPrintPos(x, y);
u8g.print(time_left);
} else if (!timer_stat) {
message = "Posture:";
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
y = y + h + 6;
h = u8g.getFontAscent() - u8g.getFontDescent();
x = (w - u8g.getStrWidth(message)) / 2;
u8g.drawStr(x, y, message);
message = "Good";
u8g.setFont(u8g_font_timR18); //17 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
y = y + h + 4;
x = (w - u8g.getStrWidth(message)) / 2;
u8g.setPrintPos(x, y);
u8g.print(message);
}
//footer: timer_stat and volume
char *footer1;
char *footer2;
u8g.setFont(u8g_font_5x7); //6 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
if (timer_stat) {
footer1 = "Timer:On";
} else if (!timer_stat) {
footer1 = "Timer:Off";
}
if (mute_stat) {
footer2 = "Volume:Mute";
} else if (!mute_stat) {
switch (volume) {
case 2:
footer2 = "Volume:Low";
break;
case 6:
footer2 = "Volume:Medium";
break;
case 10:
footer2 = "Volume:High";
break;
}
} //end: else-if
h = u8g.getFontAscent() - u8g.getFontDescent();
x = 0;
y = u8g.getHeight() - h - 1;
u8g.drawStr(x, y, footer1);
49
x = w - u8g.getStrWidth(footer2);
u8g.drawStr(x, y, footer2);
} while (u8g.nextPage());
} //end: lcd_main_info()
/***************************************************************************/
/* sets of functions for displaying and refreshing the individual menus */
void draw_main_menu(void)
{
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < main_menu_items; i++) {
x = (w - u8g.getStrWidth(main_menu_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 0) {
u8g.drawHLine(0, h-1, w);
}
if (i == main_menu_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, main_menu_text[i]);
} //end: for
}
void update_main_menu(void)
{
if (digitalRead(buttonNext)) {
main_menu_current++;
if (main_menu_current >= main_menu_items) {
main_menu_current = 1;
}
main_menu_redraw = 1;
}
}
void draw_main_timer(void)
{
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < main_timer_items; i++) {
50
x = (w - u8g.getStrWidth(main_timer_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 0) {
u8g.drawHLine(0, h-1, w);
}
if (i == main_timer_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, main_timer_text[i]);
} //end: for
}
void update_main_timer(void)
{
if (digitalRead(buttonNext)) {
main_timer_current++;
if (main_timer_current >= main_timer_items) {
main_timer_current = 1;
}
main_timer_redraw = 1;
}
}
void draw_timer_status(void)
{
if (timer_stat) {
timer_status_text[1] = "** On **";
timer_status_text[2] = "Off";
} else if (!timer_stat) {
timer_status_text[1] = "On";
timer_status_text[2] = "** Off **";
}
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < timer_status_items; i++) {
x = (w - u8g.getStrWidth(timer_status_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 0) {
u8g.drawHLine(0, h-1, w);
}
if (i == timer_status_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, timer_status_text[i]);
51
} //end: for
}
void update_timer_status(void)
{
if (digitalRead(buttonNext)) {
timer_status_current++;
if (timer_status_current >= timer_status_items) {
timer_status_current = 1;
}
timer_status_redraw = 1;
}
}
void draw_timer_study(void)
{
if (study_t == 20) {
timer_study_text[1] = "** 20 min **";
timer_study_text[2] = "30 min";
timer_study_text[3] = "40 min";
} else if (study_t == 30) {
timer_study_text[1] = "20 min";
timer_study_text[2] = "** 30 min **";
timer_study_text[3] = "40 min";
} else if (study_t == 40) {
timer_study_text[1] = "20 min";
timer_study_text[2] = "30 min";
timer_study_text[3] = "** 40 min **";
}
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < timer_study_items; i++) {
x = (w - u8g.getStrWidth(timer_study_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 0) {
u8g.drawHLine(0, h-1, w);
}
if (i == timer_study_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, timer_study_text[i]);
} //end: for
}
void update_timer_study(void)
{
if (digitalRead(buttonNext)) {
52
timer_study_current++;
if (timer_study_current >= timer_study_items) {
timer_study_current = 1;
}
timer_study_redraw = 1;
}
}
void draw_timer_break(void)
{
if (break_t == 20) {
timer_break_text[1] = "** 20 min **";
timer_break_text[2] = "30 min";
timer_break_text[3] = "40 min";
} else if (break_t == 30) {
timer_break_text[1] = "20 min";
timer_break_text[2] = "** 30 min **";
timer_break_text[3] = "40 min";
} else if (break_t == 40) {
timer_break_text[1] = "20 min";
timer_break_text[2] = "30 min";
timer_break_text[3] = "** 40 min **";
}
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < timer_break_items; i++) {
x = (w - u8g.getStrWidth(timer_break_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 0) {
u8g.drawHLine(0, h-1, w);
}
if (i == timer_break_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, timer_break_text[i]);
} //end: for
}
void update_timer_break(void)
{
if (digitalRead(buttonNext)) {
timer_break_current++;
if (timer_break_current >= timer_break_items) {
timer_break_current = 1;
}
timer_break_redraw = 1;
}
53
}
void draw_main_sound(void)
{
if (mute_stat) {
main_sound_text[2] = "Unmute";
} else if (!mute_stat) {
main_sound_text[2] = "Mute";
}
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < main_sound_items; i++) {
x = (w - u8g.getStrWidth(main_sound_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 0) {
u8g.drawHLine(0, h-1, w);
}
if (i == main_sound_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, main_sound_text[i]);
} //end: for
}
void update_main_sound(void)
{
if (digitalRead(buttonNext)) {
main_sound_current++;
if (main_sound_current >= main_sound_items) {
main_sound_current = 1;
}
main_sound_redraw = 1;
}
}
void draw_sound_volume(void)
{
if (volume == 10) {
sound_volume_text[1] = "** High **";
sound_volume_text[2] = "Medium";
sound_volume_text[3] = "Low";
} else if (volume == 6) {
sound_volume_text[1] = "High";
sound_volume_text[2] = "** Medium **";
sound_volume_text[3] = "Low";
} else if (volume == 2) {
sound_volume_text[1] = "High";
54
sound_volume_text[2] = "Medium";
sound_volume_text[3] = "** Low **";
}
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < sound_volume_items; i++) {
x = (w - u8g.getStrWidth(sound_volume_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 0) {
u8g.drawHLine(0, h-1, w);
}
if (i == sound_volume_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, sound_volume_text[i]);
} //end: for
}
void update_sound_volume(void)
{
if (digitalRead(buttonNext)) {
sound_volume_current++;
if (sound_volume_current >= sound_volume_items) {
sound_volume_current = 1;
}
sound_volume_redraw = 1;
}
}
void draw_main_reset(void)
{
volatile u8g_uint_t i, h, w, x;
u8g.setFont(u8g_font_6x13); //9 pixels font
u8g.setFontRefHeightText();
u8g.setFontPosTop();
h = u8g.getFontAscent() - u8g.getFontDescent();
w = u8g.getWidth();
for (i = 0; i < main_reset_items; i++) {
x = (w - u8g.getStrWidth(main_reset_text[i])) / 2;
u8g.setDefaultForegroundColor();
if (i == 2) {
u8g.drawHLine(0, (i+1)*h-1, w);
}
55
if (i == main_reset_current) {
u8g.drawBox(0, i*h+1, w, h);
u8g.setDefaultBackgroundColor();
}
u8g.drawStr(x, i*h, main_reset_text[i]);
} //end: for
}
void update_main_reset(void)
{
if (digitalRead(buttonNext)) {
main_reset_current++;
if (main_reset_current >= main_reset_items) {
main_reset_current = 3;
}
main_reset_redraw = 1;
}
}
/***************************************************************************/
/* function that handles the menu UI */
void menu(void)
{
volatile int exit_main = 0;
while (!exit_main) {
main_menu_redraw = 1;
do {
if (main_menu_redraw) {
u8g.firstPage();
do {
draw_main_menu();
} while (u8g.nextPage());
main_menu_redraw = 0;
}
update_main_menu();
} while (!digitalRead(buttonOK));
if (main_menu_current == 1) {
//main_timer
clear_screen();
volatile int exit_timer = 0;
while (!exit_timer) {
main_timer_redraw = 1;
do {
if (main_timer_redraw) {
u8g.firstPage();
do {
draw_main_timer();
} while (u8g.nextPage());
main_timer_redraw = 0;
}
update_main_timer();
} while (!digitalRead(buttonOK));
if (main_timer_current == 1) {
//timer_status
clear_screen();
56
timer_status_redraw = 1;
do {
if (timer_status_redraw) {
u8g.firstPage();
do {
draw_timer_status();
} while (u8g.nextPage());
timer_status_redraw = 0;
}
update_timer_status();
} while (!digitalRead(buttonOK));
if (timer_status_current == 1) {
//timer on
EEPROM.write(eeprom_timer, 1);
timer_stat = 1;
study = 1;
exit_timer = 1;
exit_main = 1;
continue;
} else if (timer_status_current == 2) {
//timer off
EEPROM.write(eeprom_timer, 0);
timer_stat = 0;
exit_timer = 1;
exit_main = 1;
continue;
} else if (timer_status_current == 3) {
//back to main_timer
continue;
}
} else if (main_timer_current == 2) {
//timer_study
clear_screen();
timer_study_redraw = 1;
do {
if (timer_study_redraw) {
u8g.firstPage();
do {
draw_timer_study();
} while (u8g.nextPage());
timer_study_redraw = 0;
}
update_timer_study();
} while (!digitalRead(buttonOK));
if (timer_study_current == 1) {
//20 min
EEPROM.write(eeprom_study, 20);
study_t = 20;
exit_timer = 1;
exit_main = 1;
continue;
} else if (timer_study_current == 2) {
//30 min
EEPROM.write(eeprom_study, 30);
study_t = 30;
exit_timer = 1;
exit_main = 1;
57
continue;
} else if (timer_study_current == 3) {
//40 min
EEPROM.write(eeprom_study, 40);
study_t = 40;
exit_timer = 1;
exit_main = 1;
continue;
} else if (timer_study_current == 4) {
//back to main_timer
continue;
}
} else if (main_timer_current == 3) {
//timer_break
clear_screen();
timer_break_redraw = 1;
do {
if (timer_break_redraw) {
u8g.firstPage();
do {
draw_timer_break();
} while (u8g.nextPage());
timer_break_redraw = 0;
}
update_timer_break();
} while (!digitalRead(buttonOK));
if (timer_break_current == 1) {
//20 min
EEPROM.write(eeprom_break, 20);
break_t = 20;
exit_timer = 1;
exit_main = 1;
continue;
} else if (timer_break_current == 2) {
//30 min
EEPROM.write(eeprom_break, 30);
break_t = 30;
exit_timer = 1;
exit_main = 1;
continue;
} else if (timer_break_current == 3) {
//40 min
EEPROM.write(eeprom_break, 40);
break_t = 40;
exit_timer = 1;
exit_main = 1;
continue;
} else if (timer_break_current == 4) {
//back to main_timer
continue;
}
} else if (main_timer_current == 4) {
//back to main_menu
exit_timer = 1;
continue;
}
}
58
} else if (main_menu_current == 2) {
//main_sound
clear_screen();
volatile int exit_sound = 0;
while (!exit_sound) {
main_sound_redraw = 1;
do {
if (main_sound_redraw) {
u8g.firstPage();
do {
draw_main_sound();
} while (u8g.nextPage());
main_sound_redraw = 0;
}
update_main_sound();
} while (!digitalRead(buttonOK));
if (main_sound_current == 1) {
//sound_volume
clear_screen();
sound_volume_redraw = 1;
do {
if (sound_volume_redraw) {
u8g.firstPage();
do {
draw_sound_volume();
} while (u8g.nextPage());
sound_volume_redraw = 0;
}
update_sound_volume();
} while (!digitalRead(buttonOK));
if (sound_volume_current == 1) {
//high
EEPROM.write(eeprom_volume, 10);
volume = 10;
exit_sound = 1;
exit_main = 1;
continue;
} else if (sound_volume_current == 2) {
//medium
EEPROM.write(eeprom_volume, 6);
volume = 6;
exit_sound = 1;
exit_main = 1;
continue;
} else if (sound_volume_current == 3) {
//low
EEPROM.write(eeprom_volume, 2);
volume = 2;
exit_sound = 1;
exit_main = 1;
continue;
} else if (sound_volume_current == 4) {
//back to main_sound
continue;
}
} else if (main_sound_current == 2) {
//mute or unmute
59
if (mute_stat) { //mute on, turn off
EEPROM.write(eeprom_mute, 0);
mute_stat = 0;
} else if (!mute_stat) { //mute off, turn on
EEPROM.write(eeprom_mute, 1);
mute_stat = 1;
}
exit_sound = 1;
exit_main = 1;
continue;
} else if (main_sound_current == 3) {
//back to main_menu
exit_sound = 1;
continue;
}
}
} else if (main_menu_current == 3) {
//main_reset
clear_screen();
main_reset_current = 4;
main_reset_redraw = 1;
do {
if (main_reset_redraw) {
u8g.firstPage();
do {
draw_main_reset();
} while (u8g.nextPage());
main_reset_redraw = 0;
}
update_main_reset();
} while (!digitalRead(buttonOK));
if (main_reset_current == 3) {
//yes
EEPROM.write(eeprom_timer, 0);
timer_stat = 0;
EEPROM.write(eeprom_study, 40);
study_t = 40;
EEPROM.write(eeprom_break, 20);
break_t = 20;
EEPROM.write(eeprom_mute, 0);
mute_stat = 0;
EEPROM.write(eeprom_volume, 6);
volume = 6;
exit_main = 1;
continue;
} else if (main_reset_current == 3) {
//no
continue;
}
} else if (main_menu_current == 4) {
//exit
exit_main = 1;
continue;
}
} //end: while
} //end: menu()
/************************************************************************/
60
iv. Appendix D Solidworks Technical Drawings
61
62
63
v. Appendix E Stud-E Prototype & Bulk Production Cost
Stud-E Prototype Production Cost
Product Cost Quantity
Total
Cost
Arduino Uno R3 Prototype Board $17.62 1 $17.62
Breadboard $8.89 1 $8.89
SaintSmart LCD (128x64) $19.00 1 $19.00
Ultrasonic Sensor (HC-SR04) $5.19 1 $5.19
Buzzer $12.69 1 $12.69
LED $0.10 1 $0.10
Push Switches $0.74 3 $2.22
Push & Lock Switch $0.74 1 $0.74
10k Ohm Resistors $1.25 5 $0.25
200 Ohm Resistor $0.00 1 $0.00
F/F Jumper Wires $0.40 9 $3.60
9V Battery Connector $1.18 1 $1.18
Hookup Wires $8.49 90cm $0.33
Aluminum Plates $0.00 3 $0.00
Aluminum Standoffs $0.56 8 $4.48
Phillips Screws $9.10 8 $7.28
Hinge $10.19 1 $10.19
TOTAL $93.76
64
Stud-E Bulk Production Cost
Product Cost
Quanity
Included
Unit
Price
Quantity
Needed Cost for 1 Stud-E Cost per 100 Stud-E
Printed Circuit Board with
Microcontroller
$888.0
0 100 $8.88 1 $8.88 $888.00
LCD Display $7.12 1 $7.12 1 $7.12 $712
Ultrasonic Sensor $12.50 10 $1.25 1 $1.25 $125.00
Buzzer $6.45 50 $0.13 1 $0.13 $12.90
LED $9.59 100 $0.10 1 $0.10 $9.59
Push Switches $3.54 100 $0.04 3 $0.12 $3.54
Push & Lock Switch $8.90 100 $0.09 1 $0.09 $8.90
10k Ohm Resistors $0.25 100
Less than
$0.01 5 $0.01 $0.25
200 Ohm Resistor $0.25 100
Less than
$0.01 1 $0.10 $0.25
9V Battery Connector $9.30 100 $0.09 1 $0.09 $9.30
Hookup Wires $15.00 2000 feet
Less than
$0.01 180cm $0.01 $0.10
Housing with Hinge (plastic)
*A quote for custom plastic housing requires an actual model and weeks to process. It will be included in the final
budget.
Approx. Cost for 1 Stud-E without
Housing
Approx. Cost for 100
Stud-E without Housing
$17.90 $1,769.83