Project in progress
Onboard computer for bicycle

Onboard computer for bicycle © GPL3+

DIY onboard computer for bicycle

  • 3,129 views
  • 10 comments
  • 14 respects

Components and supplies

Ard nano
Arduino Nano R3
Or similar with 32kB of ROM and 2kB of RAM.
×1
Mfr 25fbf52 475r sml
Resistor 475 ohm
For orange LEDs
×6
11026 02
Jumper wires (generic)
Male to male and male to female
×1
12002 04
Breadboard (generic)
Or one large
×2
09590 01
LED (generic)
White(x20), red(x15) and orange(x12)
×47
Mfr 25fbf52 2k21 sml
Resistor 2.21k ohm
For push buttons(safety reasons)
×6
Mfr 25frf52 100r sml
Resistor 100 ohm
For white and red LEDs
×11
Mfr 25fbf52 221r sml
Resistor 221 ohm
For "ambient light"
×1
OLED display
Monochrome, 128x64 px, IIC - 0.96" SSD1306 or 1.3" SH1103
×1
IRFZ44 MOSFET
N channel MOSFET for lights.
×1
Digital hall sensor
49E OH49E SS49E, linear
×1
Analog hall sensor
3503 TO-92UA, linear
×1
DS3231 RTC
For time, date and temperature
×1
Resistor 100k
Pull-down resistor for speed & RPM sensors
×2
USB cabel
Mini or micro
×1
SPST Switch
×2
Momentary Push Button Switch
×6

Necessary tools and machines

Digital multimeter
09507 01
Soldering iron (generic)
Later

Apps and online services

About this project

Story

I like motorbikes, but I'm not old enough for supersport bikes and I don't have enough money. On bikes I like rear ends, tail lights. One day I decided to do little circuit. Circuit's task was to flash rear light if I press brake lever on my bicycle (I used 2013+ Kawasaki Ninja ZX6R Programmable Integrated Tail Light from TSTIndustries as idea). Circuit was too complicated for me because my knowledge in electrical engineering was poor, so I gave up from idea.

Few months later professor in school was talking about some microcontroller, that microcontroller was Arduino, heart of this project. Idea woke up. I googled about Arduino, how to, examples etc. I learned a lot about electrical engineering (but knowledge is still poor), programing (I love it!) while I work on this project.

I did First few schematics for the project. At the beginning project was very simple, just push buttons for rear and front lights(and high beam via PWM), Arduino, blue LED as indicator for lights, hall sensors for brake light and that is it. So simple. After that I was buying components I needed. Code I wrote for that simple project used under 50% of RAM and ROM. I said, it was very simple, under 200 lines of code.

But, then I said "I have more Resources to use, why I don't build onboard compuer with display?". And I decided to do more on the project. I added OLED display, RTC (while riding sometimes I lost the term of time :D), turn signals, tachometer and speedometer, etc... So the project has become complicated. Now main code has over 2k of lines and it use almost all Resources from Arduino Nano.

Also I had one idea about GPS and GSM modules, but I decided to leave that idea because I don't have much space on my bicycle for another modules.

What does have onboard Computer?

  • Distances - Main distance ; Daily distance (auto reset every day) ; Trip A & B (resettable)
  • Top speed & Max speed (resettable)
  • Average distance & speed (both resettable)
  • Trip time & Trip time B (both resettalbe)
  • Average efficiency (also resettable)
  • Speedometer
  • Tachometer
  • Front light - Daily light ; Normal light ; High beam (flashing possible)
  • Rear light - Daily light ; Normal light ; Fog light ; Brake light
  • Turn signals & hazard light (just in case :D)
  • "Ambient light" for speeds on rudder (adjust R8 and R9, but don't use resistors below 10k, you can damage pin D0)
  • Time, date & ambient temperature info (date & time don't support AM/PM mode)
  • "Target mode" - Also Know as "goal mode". Set target/goal distance and let Arduino track your goal for you. In "target mode" you can see info how far you are from finish and how much time you need to complete the goal. This is WIP mode, it'll be done soon.
  • Settings mode - Unit (Metric/Imperial ; default: Metric) ; "Ambient light" (On/Off ; default: On) ; Screen saver (On/Off ; default: On) ; Brake light flashes (Yes/No ; default: Yes) ; Date & time adjustment ; Headlight mode (Constant on or flashes every 1/10s, 1/5s, 1/4s, 1/3s) ; Front & rear brake calibration (hall sensors).
  • Turn off/on display by holding screen button (PIN_BTN_SCR_CONTROL) less than 0.5s
  • Reset resettable stats by holding screen button (PIN_BTN_SCR_CONTROL) more than 0.5s
  • Cycle through stats via pressing screen button (PIN_BTN_SCR_CONTROL)
  • To turn on or off hazard light, hold left turn signal button more than 0.5s (PIN_BTN_TURN_SIGNAL_L)
  • To cycle through time, date & temp info hold right turn singal button more than 0.5s (PIN_BTN_TURN_SIGNAL_R)
  • To turn on or off fog light hold light button (PIN_BTN_LIGHTS) more than 0.5s

If you want go to settings mode, on start press screnn button (PIN_BTN_SCR_CONTROL). If you don't want, just press right turn signal button (PIN_BTN_TURN_SIGNAL_R). To cycle through settings press left turn signal button (PIN_BTN_TURN_SIGNAL_L). To change setting value(+) press light button(PIN_BTN_LIGHTS). To change setting value(-) press high beam button(PIN_BTN_HIGH_BEAM).

This project Works on 5V, but LEDs require 12V (I use 12V from PC). Also, after WIP part of development, project will work on LiIon batteries (eg. from old laptop) with 5V and 12V boost converter(MT3608 2V-24V @ 2A). For charging I'm going to use 6xTP056(@ 1A) because I have 6 LiIon batteries(around 42Wh). Also there will be USB port for charging mobile device.

Now

Little tachometer animation on startup

On PCB

I did little work. Headlight is around 1W and tail light is 0.5W. See images below.

Code

Program.inoC/C++
** UPDATED: 25.11.2017.
** UPDATED: 27.11.2017. - DO A HARD RESET(NEW EEPROM ADDRESSES)
** UPDATED: 13.1.2018. - SUPPORT FOR SH1106 DISPLAY DRIVER(1.3" OLED DISPLAY)

It's main code for whole project. It's WIP, but it's almost done. Just copy the code, paste it in Arduino IDE and upload it to Arduino. Code requires RTClib(from Adafruit) for RTC module and Adafruit GFX library for OLED display.
/*

    - Credits: Pararera
    - Version: v1.0
    - Last update: XX.XX.XXXX.
    - Default settings[SETTING_UNIT]: Metric
    - Default time format: 0-23
    - Contact e-Mail address: pararera@outlook.com
    - Facebook: www.facebook.com/Pararera



    ** CHANGE LOG

        v1.0:
            - Initial release     

*/




// LIBRARIES
#include                                                                       <RTClib.h>
#include                                                                       <EEPROM.h>
#include                                                                       <Wire.h> 
#include                                                                       <SPI.h>
#include                                                                       <Adafruit_SH1106.h>
#include                                                                       <Adafruit_GFX.h>





// SCREEN AND REAL TIME CLOCK OBJECTS
#define OLED_RESET                                                     			4
#ifdef SH1106_I2C_ADDRESS
    Adafruit_SH1106 display(OLED_RESET);
#else
    Adafruit_SSD1306 display(OLED_RESET);
#endif
RTC_DS3231 rtc;


// SETTINGS
#define HARD_RESET                                                       		0 // 1 TO RESET EVERYTHING IN EEPROM TO DEFAULT VALUES (FOR TESTING PURPOSES)
#define OLD_DISTANCE                                                            1273240 // DISTANCE I RODE BEFORE THIS PROJECT (0 IF YOU DON'T NEED IT)
#define OLD_MAX_SPEED                                                           43 // MAX SPEED I DID BEFORE THIS PROJECT (0 IF YOU DON'T NEED IT)
#define WHEELE_EXTENT                                                           2.35619449019 // EXTENT OF MY FRONT WHEELE IN METERS (29" WHEELE). ADJUST IT FOR YOURSELF
#define WHEELE_EXTENT_FOR_CALC                                                  235619 // FRIST SIX NUMBERS FROM "WHEELE_EXTENT" AS INT VALUE (FOR SPEED CALCULATION)
#define RPM_ANIM_ON_BOOT                                                        1 // SET TO ZERO TO SKIP RPM ANIMATION ON BOOT

#define FRONT_LIGHT_PWM                                                         120 // BRIGHTNESS OF FRONT LIGHT (YOU CAN CHANGE IT IF YOU WANT. VALUE HAVE TO BE BETWEEN 0 AND 255) **
#define FRONT_DLIGHT_PWM                                                        45 // BRIGHTNESS OF FRONT DAILY LIGHTS (YOU CAN CHANGE IT IF YOU WANT. VALUE HAVE TO BE BETWEEN 0 AND 255) **
#define REAR_LIGHT_PWM                                                          86 // BRIGHTNESS OF REAR LIGHT (YOU CAN CHANGE IT IF YOU WANT. VALUE HAVE TO BE BETWEEN 0 AND 255) ** 
#define REAR_DLIGHT_PWM                                                         45 // BRIGHTNESS OF REAR DAILY LIGHTS (YOU CAN CHANGE IT IF YOU WANT. VALUE HAVE TO BE BETWEEN 0 AND 255) **

#define BR_DLIGHT_MIN                                                           16
#define BR_DLIGHT_MAX                                                           100
#define BR_LIGHT_MIN                                                            86
#define BR_LIGHT_MAX                                                            145
#define BR_DTAILLIGHT_MIN                                                       8
#define BR_DTAILLIGHT_MAX                                                       64
#define BR_TAILLIGHT_MIN                                                        86
#define BR_TAILLIGHT_MAX                                                        145

#define BRAKE_LIGHT_PWM1                                                        186 // BRIGHTNESS OF BRAKE LIGHT FLASH (1ST FLASH. IT SHOULD BE MORE THAN "REAR_LIGHT_PWM")
#define BRAKE_LIGHT_PWM2                                                        250 // BRIGHTNESS OF BRAKE LIGHT FASH (2ND FLASH. IT SHOULD BE MORE THAN "BRAKE_LIGHT_PWM1")
#define FOG_LIGHT_PWM                                                           250 // BRIGHTNESS OF FOG LIGHT

#define TIME_FOR_SLEEP                                                          65000 // TIME IN IDLE BEFORE SLEEP MODE
#define TIME_FOR_SAVE                                                           15000 // TIME BETWEEN TWO SAVES
#define TIME_FOR_FLASH_TURN_SIGNAL                                              250 // TIME BETWEEN TWO FLASHES OF TURN SIGNAL
#define TIME_BETWEEN_FLASHES                                                    35 // TIME BETWEEN TWO FLASHES OF REAR LIGHT WHILE BRAKING (WHILE FOG LIGHTS ARE OFF)
#define TIME_BETWEEN_FLASHES_FL                                                 35 // TIME BETWEEN TWO FLASHES OF REAR LIGHT WHILE BRAKING (WHILE FOG LIGHTS ARE ON)
#define TIME_RESET_TACHOMETER                                                   1500 // TIME WITHOUT REVOLUTIONS
#define FLASHES_MIN                                                             8
#define FLASHES_MAX                                                             13



// SETTINGS
#define EEPROM_FLASHES                                                          0 // SETTING_BRAKE_FLASHES
#define EEPROM_UNIT                                                             1 // SETTING_UNIT
#define EEPROM_SCREEN_SAVER                                                     2 // SETTING_SCREEN_SAVER
#define EEPROM_FLASH_BRAKE_LIGHT                                                3 // SETTING_FLASH_BRAKE_LIGHT
#define EEPROM_LIGHT_TIME                                                       4 // SETTING_LIGHT_TIME
#define EEPROM_BR_DLIGHT                                                        5 // SETTING_BR_DLIGHT
#define EEPROM_BR_LIGHT                                                         6 // SETTING_BR_LIGHT
#define EEPROM_BR_DTAIL                                                         7 // SETTING_BR_DTAILLIGHT
#define EEPROM_BR_TAIL                                                          8 // SETTING_BR_TAILLIGHT
//
#define EEPROM_SETTING_STEP                                                     9
#define EEPROM_RTC_DAY                                                          10
#define EEPROM_RTC_MONTH                                                        11 
#define EEPROM_RTC_YEAR                                                         12 


// TOP SPEEDS
#define EEPROM_MAX_SPEED                                                        20 // SPEED_MAX
#define EEPROM_TOP_SPEED                                                        21 // SPEED_TOP


// STATES
#define EEPROM_SCREEN_STATUS                                                    22 // STATE_SCREEN_STATUS
#define EEPROM_LIGHTS                                                           23 // STATE_LIGHT
#define EEPROM_FOG_LIGHTS                                                       24 // STATE_FOG_LIGHT
#define EEPROM_SCREEN_INFO                                                      25 // STATE_SCREEN_INFO
// 26TH ADDRESS IS FREE


// OTHER
#define EEPROM_DISTANCE_PD_DAY                                                  27 



// DISTANCES
#define EEPROM_DISTANCE                                                         28 // + 4  DISTANCE_TOTAL 
#define EEPROM_DISTANCE_B                                                       32 // + 4  DISTANCE_TRIP_A
#define EEPROM_DISTANCE_C                                                       36 // + 4  DISTANCE_TRIP_B
#define EEPROM_DISTANCE_PD                                                      40 // + 4  DISTANCE_PER_DAY


// STATS
#define EEPROM_TOTAL_SPEED                                                      44 // + 4  STAT_TOTAL_SPEED
#define EEPROM_TAKEN_SPEED                                                      48 // + 4  STAT_TAKEN_SPEED
#define EEPROM_TIME_ON_BICYCLE                                                  52 // + 4  STAT_PEDAL_TIME
#define EEPROM_TIME_AVG_DIST                                                    56 // + 4  STAT_TIME_AVG_DIST
#define EEPROM_AVG_DISTANCE                                                     60 // + 4  STAT_AVG_DISTANCE
#define EEPROM_WOKR_HOURS                                                       64 // + 4  STAT_WORK_HOURS
#define EEPROM_TIME_ON_BICYCLE_B                                                68 // + 4  STAT_PEDAL_TIME_B
#define EEPROM_REVTOTAL                                                         72 // + 4  STAT_REVTOTAL
#define EEPROM_REVTOTAL_DIST                                                    76 // + 4  STAT_REV_DISTANCE
#define EEPROM_DISTANCE_PD_AVG                                                  80 // + 4  STAT_DIST_PD_AVG
#define EEPROM_DISTANCE_PD_AVG_TAKEN                                            84 // + 4  STAT_DIST_PD_TAKEN


// 88 - 99 FREE ADDRESSES


// TRIGGERS
#define EEPROM_FRONT_BRAKE_TRIGGER                                              100 // + 4  TRIGGER_FRONT_BRAKE
#define EEPROM_REAR_BRAKE_TRIGGER                                               104 // + 4  TRIGGER_REAR_BRAKE



// PINS
#define PIN_BTN_SCR_CONTROL                                                     8
#define PIN_BTN_LIGHTS                                                          4
#define PIN_BTN_HIGH_BEAM                                                       11
#define PIN_BTN_TURN_SIGNAL_L                                                   7
#define PIN_BTN_TURN_SIGNAL_R                                                   12

#define PIN_LED_TAIL_LIGHT                                                      6
#define PIN_LED_TURN_SIGNAL_L                                                   13 // ONLY OUTPUT PIN!
#define PIN_LED_TURN_SIGNAL_R                                                   0
#define PIN_LED_2ND_TAIL_LIGHT                                                  5
#define PIN_LED_FRONT_LIGHT                                                     10
#define PIN_LED_2ND_FRONT_LIGHT                                                 9

#define PIN_RPM_SENSOR                                                          2 // INTERRUPT PIN! DO NOT CHANGE IT!!
#define PIN_SPEED_SENSOR                                                        3 // INTERRUPT PIN! DO NOT CHANGE IT!!
#define PIN_FRONT_BRAKE_SENSOR                                                  0 // ANALOG PIN
#define PIN_REAR_BRAKE_SENSOR                                                   1 // ANALOG PIN



// SCREEN DESIGN
#define SCR_SPEED_X                                                             25
#define SCR_SPEED_Y                                                             13
#define SCR_SPEED_SIZE                                                          3
#define SCR_SPEED_KMH_X                                                         62
#define SCR_SPEED_KMH_Y                                                         27
#define SCR_SPEED_KMH_SIZE                                                      1

#define SCR_INFO_X                                                              1
#define SCR_INFO_Y                                                              45
#define SCR_INFO_Y2                                                             56
#define SCR_INFO_SIZE                                                           1 

#define SCR_TIME_X                                                              25
#define SCR_TIME_Y                                                              1
#define SCR_TIME_SIZE                                                           1

#define SCR_RPM_X                                                               83
#define SCR_RPM_Y                                                               27
#define SCR_RPM_Y2                                                              13
#define SCR_RPM_SIZE                                                            1
#define SCR_RPM_SIZE2                                                           2

#define SCR_TURN_SIGNAL_Y                                                       11   
#define SCR_TURN_SIGNAL_SIZE                                                    2
#define SCR_TURN_SIGNAL_L_X                                                     61   
#define SCR_TURN_SIGNAL_R_X                                                     72

#define SCR_ICONS_X                                                             2  
#define SCR_ICONS_SIZE                                                          1  
#define SCR_ICONS_LI_Y                                                          1  
#define SCR_ICONS_HB_Y                                                          13  
#define SCR_ICONS_FL_Y                                                          25  

#define SCR_BRAKE_X                                                             121 
#define SCR_BRAKE_Y                                                             -1 
#define SCR_BRAKE_W                                                             8 
#define SCR_BRAKE_H                                                             33


#define SCR_LINE1_X                                                             20 
#define SCR_LINE1_Y                                                             1 
#define SCR_LINE1_L                                                             39

#define SCR_LINE2_X                                                             0
#define SCR_LINE2_Y                                                             39
#define SCR_LINE2_L                                                             75

#define SCR_LINE3_X                                                             120
#define SCR_LINE3_Y                                                             1
#define SCR_LINE3_L                                                             64

#define SCR_LINE4_X                                                             75
#define SCR_LINE4_Y                                                             39
#define SCR_LINE4_L                                                             36


// MACRO FUNCTIONS
#define screenLines() \
            display.drawFastVLine(SCR_LINE1_X, SCR_LINE1_Y, SCR_LINE1_L, WHITE); \
            display.drawFastHLine(SCR_LINE2_X, SCR_LINE2_Y, SCR_LINE2_L, WHITE); \
            display.drawFastVLine(SCR_LINE3_X, SCR_LINE3_Y, SCR_LINE3_L, WHITE); \
            display.drawFastVLine(SCR_LINE4_X, SCR_LINE4_Y, SCR_LINE4_L, WHITE)



// SETTINGS
#define SETTING_BRAKE_FLASHES                                                   0
#define SETTING_UNIT                                                            1
#define SETTING_SCREEN_SAVER                                                    2
#define SETTING_FLASH_BRAKE_LIGHT                                               3
#define SETTING_LIGHT_TIME                                                      4
#define SETTING_BR_DLIGHT                                                       5
#define SETTING_BR_LIGHT                                                        6
#define SETTING_BR_DTAILLIGHT                                                   7
#define SETTING_BR_TAILLIGHT                                                    8         

uint8_t settings[9] = {
    10, // SETTING_BRAKE_FLASHES (8 - 13)
    0, // SETTING_UNIT (0 = METRIC ; 1 = IMPERIAL)
    1, // SETTING_SCREEN_SAVER (0 = NO ; 1 = YES)
    1, // SETTING_FLASH_BRAKE_LIGHT (0 = NO ; 1 = YES)
    0, // SETTING_LIGHT_TIME (0 = 1/10S ; 1 = 1/5S ; 2 = 1/4S ; 3 = 1/3S ; 4 = FULL)
    45, // SETTING_BR_DLIGHT (16 - 100)
    120, // SETTING_BR_LIGHT (86 - 145)
    45, // SETTING_BR_DTAILLIGHT (8 - 64)
    86 // SETTING_BR_TAILLIGHT (86 - 145)       
};


// SPEEDS
#define SPEED_MAX                                                               0
#define SPEED_TOP                                                               1

uint8_t speedStat[2] = {
    0, // SPEED_MAX
    0, // SPEED_TOP
};


// SYSTEM STATES
#define STATE_SCREEN_STATUS                                                     0
#define STATE_LIGHT                                                             1
#define STATE_FOG_LIGHT                                                         2
#define STATE_SCREEN_INFO                                                       3
#define STATE_HIGH_BEAM                                                         4

uint8_t states[5] = {
    1, // STATE_SCREEN_STATUS
    0, // STATE_LIGHT
    0, // STATE_FOG_LIGHT
    0, // STATE_SCREEN_INFO
    0 // STATE_HIGH_BEAM
};


// DISTANCES
#define DISTANCE_TOTAL                                                          0
#define DISTANCE_TRIP_A                                                         1
#define DISTANCE_TRIP_B                                                         2
#define DISTANCE_PER_DAY                                                        3

volatile uint32_t distances[4] = {
    0, // DISTANCE_TOTAL
    0, // DISTANCE_TRIP_A
    0, // DISTANCE_TRIP_B
    0 // DISTANCE_PER_DAY
};


// STATS
#define STAT_TOTAL_SPEED                                                        0
#define STAT_TAKEN_SPEED                                                        1
#define STAT_PEDAL_TIME                                                         2
#define STAT_TIME_AVG_DIST                                                      3
#define STAT_AVG_DISTANCE                                                       4
#define STAT_WORK_HOURS                                                         5
#define STAT_PEDAL_TIME_B                                                       6
#define STAT_REVTOTAL                                                           7
#define STAT_REV_DISTANCE                                                       8
#define STAT_DIST_PD_AVG                                                        9
#define STAT_DIST_PD_TAKEN                                                      10

uint32_t stats[11] = { // DEFAULT VALUES
    0, // STAT_TOTAL_SPEED
    0, // STAT_TAKEN_SPEED
    0, // STAT_PEDAL_TIME   
    0, // STAT_TIME_AVG_DIST
    0, // STAT_AVG_DISTANCE
    0, // STAT_WORK_HOURS
    0, // STAT_PEDAL_TIME_B
    0, // STAT_REVTOTAL
    0, // STAT_REV_DISTANCE
    0, // STAT_DIST_PD_AVG
    0 // STAT_DIST_PD_TAKEN
};


// TRIGGERS
#define TRIGGER_FRONT_BRAK                                                      0
#define TRIGGER_REAR_BRAKE                                                      1

uint16_t triggers[2] = {
    800, // TRIGGER_FRONT_BRAKE
    800 // TRIGGER_REAR_BRAKE
};


// BUTTONS
#define BTN_LEFT_TS                                                             0
#define BTN_LIGHT                                                           1
#define BTN_SCREEN_INFO                                                         2
#define BTN_RIGHT_TS                                                            3
#define BTN_HIGH_BEAM                                                           4

uint32_t pressedButton[5] = {
    0, // BTN_LEFT_TS  ALSO IN USE FOR INFO ABOUT DAY IN SETTINGS
    0, // BTN_LIGHT  ALSO IN USE FOR INFO ABOUT YEAR IN SETTINGS
    0, // BTN_RIGHT_TS  ALSO IN USE FOR INFO ABOUT MINUTES IN SETTINGS
    0, // BTN_SCREEN_INFO  ALSO IN USE FOR INFO ABOUT HOUR IN SETTINGS
    0 // BTN_HIGH_BEAM  ALSO IN USE FOR INFO ABOUT MONTH IN SETTINGS
};


uint32_t tick                                   =                               0;
uint32_t animResetTick                          =                               0; // ALSO IN USE AS "TIMER" FOR TIME WHILE SYSTEM ISN'T ON
uint32_t activeTick                             =                               0;
bool brake                                      =                               false;
uint8_t brakeFlash                              =                               1; // ALSO IN USE FOR BRAKE TRIGGER STEP
uint32_t brakeTick                              =                               0; //
uint32_t turnSignalFlashTick                    =                               0;
bool turnSignalFlash                            =                               false; // ALSO IN USE FOR INFO DOES SOMEONE CHANGED SOMETHING IN SETTINGS
uint8_t turnSignals                             =                               0; // ALSO IN USE FOR INFO WHICH SETTING IS SELECTED IN SETTINGS
uint32_t savedTick                              =                               0;
bool updateBrakes                               =                               false; // ALSO IN USE FOR INFO DOES SYSTEM SHOULD ADJUST RTC CHIP
bool refreshScreen                              =                               false;
volatile uint32_t speedTick                     =                               0;
uint32_t speedRefreshTick                       =                               0;
uint32_t speed                                  =                               0; // ALSO IN USE FOR INFO ABOUT SECOND IN SETTINGS
volatile uint32_t revDuration                   =                               0;
bool sleepMode                                  =                               false;
uint8_t timeInfo                                =                               2; // 0 = TIME ; 1 = DATE ; 2 = TEMP
volatile uint32_t revDurationRPM                =                               0;
volatile uint32_t revTick                       =                               0;
uint32_t clockTick                              =                               0;
uint32_t lastHeadlightTime                      =                               0; // ALSO IN USE FOR INFO ABOUT DAY (FOR DISTANCE PER DAY STAT)
bool headlightState                             =                               true;
uint8_t rev                                     =                               0;
bool btnPressed1                                =                               false;
bool btnPressed2                                =                               false;
const uint16_t headlightTicks[4] =
{
    100,
    200,
    250,
    333
};


// ADDITIONAL FUNCTIONS FOR EEPROM (CREDITS: Kevin Elsenberger)
void EEPROMUpdatelong(int8_t address, int32_t value)
{
    int8_t four = (value & 0xFF);
    int8_t three = ((value >> 8) & 0xFF);
    int8_t two = ((value >> 16) & 0xFF);
    int8_t one = ((value >> 24) & 0xFF);

    EEPROM.update(address, four);
    EEPROM.update(address + 1, three);
    EEPROM.update(address + 2, two);
    EEPROM.update(address + 3, one);
}

int32_t EEPROMReadlong(int8_t address)
{
    int32_t four = EEPROM.read(address);
    int32_t three = EEPROM.read(address + 1);
    int32_t two = EEPROM.read(address + 2);
    int32_t one = EEPROM.read(address + 3);

    return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}



// SCREEN FUNCTIONS
void screenIconUpdate(uint8_t icon, bool state)
{
    const char screenIcons[4][3] =
    {
        "DL",
        "LI",
        "HB",
        "FL"
    };
    const uint8_t screenIconPosY[4] =
    {
        SCR_ICONS_LI_Y,
        SCR_ICONS_LI_Y,
        SCR_ICONS_HB_Y,
        SCR_ICONS_FL_Y 
    };
    refreshScreen = true;

    display.setCursor(SCR_ICONS_X, screenIconPosY[icon]);
    display.setTextSize(SCR_ICONS_SIZE);   

    if (state) display.print(screenIcons[icon]);
        else display.print("  ");       
}

void screenInfoSetup(const char* text)
{
    refreshScreen = true;

    display.setTextSize(SCR_INFO_SIZE);
    display.setCursor(SCR_INFO_X, SCR_INFO_Y2);
    display.print(F("            "));
    display.setCursor(SCR_INFO_X, SCR_INFO_Y);
    display.print(F("           "));

    display.setCursor(SCR_INFO_X, SCR_INFO_Y);
    display.print(text);
    display.setCursor(SCR_INFO_X, SCR_INFO_Y2);
}

void screenZeros(const float curDist)
{
    uint8_t zeros = 0;

    if (curDist < 10.00) zeros = 5;
    else if (curDist < 100.00) zeros = 4;
    else if (curDist < 1000.00) zeros = 3;
    else if (curDist < 10000.00) zeros = 2;
    else if (curDist < 100000.00) zeros = 1;

    copySign('0', zeros);
}

void copySign(const char sign, uint8_t times)
{
    for (times != 0; times--;) display.print(sign);
} 

void screenDistance(uint8_t distanceID = 0)
{
    float dist = 0.00;
    const char* text[5] = {
        "TOTAL",
        "TRIP A",
        "TRIP B",
        "TRIP/DAY",
        "AVG/DAY"
    };

    if (!distanceID) dist = (distances[DISTANCE_TOTAL] + OLD_DISTANCE) * WHEELE_EXTENT / 1000.00;
    else if (distanceID == 1) dist = distances[DISTANCE_TRIP_A] * WHEELE_EXTENT / 1000.00;
    else if (distanceID == 2) dist = distances[DISTANCE_TRIP_B] * WHEELE_EXTENT / 1000.00;
    else if (distanceID == 3) dist = distances[DISTANCE_PER_DAY] * WHEELE_EXTENT / 1000.00;
    else if (distanceID == 4) dist = (stats[STAT_DIST_PD_AVG] * WHEELE_EXTENT / 1000.00) / stats[STAT_DIST_PD_TAKEN];

    screenInfoSetup(text[distanceID]);
    screenZeros(dist);    

    if (!settings[SETTING_UNIT])
    {
        display.print(dist, 1);
        display.print(F("km"));
    }
    else
    {
        display.print(dist * 621 / 1000, 1);
        display.print(F("mi"));     
    }       
}

void screenStatReset(const char* text)
{
    screenInfoSetup(text);
    display.print("RESET");
}

void screenSpeedStat(uint8_t speedID)
{
    if (!speedID) screenInfoSetup("TOP SPEED"); // RESETTABLE
        else screenInfoSetup("MAX SPEED");

    if (!settings[SETTING_UNIT])
    {
        display.print(speedStat[speedID], 1);
        display.print(F("km/h"));
    }
    else
    {
        display.print(speedStat[speedID] * 621371192 / 1000000000, 1);
        display.print(F("mi/h"));      
    }       
}

void screenAvgSpeed() // RESETTABLE
{   
    screenInfoSetup("AVG SPEED");

    if (!settings[SETTING_UNIT])
    {
    	display.print(stats[STAT_TOTAL_SPEED] / (stats[STAT_TAKEN_SPEED] + 1), 1);
    	display.print(F("km/h"));
    }
    else
    {
    	display.print(stats[STAT_TOTAL_SPEED] / (stats[STAT_TAKEN_SPEED] + 1) * 621371192 / 1000000000, 1);
    	display.print(F("mi/h"));    	
    } 	
}

void screenTripTimeStat(uint8_t tripID)
{
    if (tripID == STAT_PEDAL_TIME) screenInfoSetup("TRIP TIME"); // RESETTABLE
        else screenInfoSetup("TRIP TIME B"); // RESETTABLE

    display.print(stats[tripID] / 3600, 1);
    display.print("h ");  
    display.print((stats[tripID] % 3600) / 60, 1);
    display.print(F("min"));     
}

void screenAvgDistance() // RESETTABLE
{
    uint8_t average = (stats[STAT_AVG_DISTANCE] * WHEELE_EXTENT) / ((stats[STAT_TIME_AVG_DIST] + 1) / 60);    
  
    screenInfoSetup("AVG DIST");

    if (!settings[SETTING_UNIT])
    {
    	display.print(average, 1);
    	display.print(F("m/min"));
    }
    else
    {
    	display.print(average * 1093 / 1000, 1);
    	display.print(F("yd/min"));    	
    } 	
}

void screenEfficiency() // RESETTABLE
{
    screenInfoSetup("AVG EFF");

    if (!settings[SETTING_UNIT])
    {
        display.print(stats[STAT_REV_DISTANCE] * WHEELE_EXTENT / 1000 / (stats[STAT_REVTOTAL] + 1), 1);
        display.print(F("m/rev"));
    }
    else
    {
        display.print(stats[STAT_REV_DISTANCE] * WHEELE_EXTENT * 1093 / 1000 / (stats[STAT_REVTOTAL] + 1), 1);
        display.print(F("yd/rev"));  
    }       

}

void screenWorkHours()
{ 
    screenInfoSetup("WORK TIME");
	display.print(stats[STAT_WORK_HOURS] / 3600, 1); 
	display.print("h ");
	display.print((stats[STAT_WORK_HOURS] % 3600) / 60, 1); 
	display.print(F("min"));         
}


void printDateTime(const uint8_t value)
{
    if (value < 10)
    {
        display.print('0');
        display.print(value);
    } 
    else display.print(value);    
}

void screenTimeDateTemp(bool change = true)
{ 
	DateTime time = rtc.now();
    clockTick = tick;

    if (change)
    {
        timeInfo++;
        if (timeInfo > 2) timeInfo = 0;
    }

	// CLEANS AREA FOR TIME, DATE AND TEMP
    display.setTextSize(SCR_TIME_SIZE);
    display.setCursor(SCR_TIME_X, SCR_TIME_Y);
    display.print(F("       "));
    display.setCursor(SCR_TIME_X, SCR_TIME_Y);        

    if (!timeInfo) // TIME
    {
        printDateTime(time.hour());
        display.print(':');
        printDateTime(time.minute());
    }
    else if (timeInfo == 1) // DATE
    {
        const char daysOfTheWeek[7][4] =
        {
            "Sun",
            "Mon",
            "Tue",
            "Wed",
            "Thu",
            "Fri",
            "Sat"
        };

        display.print(daysOfTheWeek[time.dayOfTheWeek()]);
        display.print(' ');
        printDateTime(time.day()); 
        display.print('.');
    }
    else // TEMP
    {
        int16_t temp = rtc.temp();

        if (!settings[SETTING_UNIT])
        {
            display.print(temp, 1);
            display.print('C');      
        }
        else
        {
            temp = (temp * 9.00) / 5.00 + 32.00;

            display.print(temp, 1);
            display.print('F');
        }
    }

    refreshScreen = true;	
}



void screenTSL()
{
    display.setCursor(SCR_TURN_SIGNAL_L_X, SCR_TURN_SIGNAL_Y);
    display.setTextSize(SCR_TURN_SIGNAL_SIZE);  
}

void screenTSR()
{
        display.setCursor(SCR_TURN_SIGNAL_R_X, SCR_TURN_SIGNAL_Y);
        display.setTextSize(SCR_TURN_SIGNAL_SIZE); 
}

void screenTurnSignalLeft()
{
    refreshScreen = true;

    screenTSL();
    display.print('<');      
}

void screenTurnSignalRight()
{
    refreshScreen = true;

    screenTSR();
    display.print('>');      
}

void screenTurnSignalClear()
{
    refreshScreen = true;

    screenTSL();
    display.print(' ');

    screenTSR();
    display.print(' ');      
}

void screenTahometer()
{
    display.setTextSize(1);

    display.setCursor(100, 1);
    display.print("150");

    display.setCursor(112, 14);
    display.print('-');  

    display.setCursor(106, 29);
    display.print("95");

    display.setCursor(112, 43);
    display.print('-');  

    display.setCursor(106, 57);
    display.print("40");     
}

void screenSetSpeed(uint8_t speed, bool speedUnit)
{
    refreshScreen = true;

    display.setCursor(SCR_SPEED_X, SCR_SPEED_Y);
    display.setTextSize(SCR_SPEED_SIZE);
    if (!speed) display.print('0');            
    display.print(speed);

    if (speedUnit)
    {
        display.setTextSize(SCR_SPEED_KMH_SIZE);
        display.setCursor(SCR_SPEED_KMH_X, SCR_SPEED_KMH_Y);
        if (!settings[SETTING_UNIT]) display.print(F("km/h"));
            else display.print(F("mi/h"));             
    }   
}

void bootScreen(bool onBoot = true)
{
    display.setTextColor(WHITE, BLACK);
    display.fillScreen(BLACK);

    screenLines();
    screenSetSpeed(0, true);
    screenTahometer();
    screenUpdate(false);
    screenTimeDateTemp(false);  

    if (onBoot)
    {
        screenTurnSignalLeft();
        screenTurnSignalRight();
        screenIconUpdate(1, true);
        screenIconUpdate(2, true);
        screenIconUpdate(3, true);

        display.display();  
    }
    else
    {
        refreshScreen = true;

        if (turnSignals == 1) screenTurnSignalLeft();
            else screenTurnSignalRight();

        if (states[STATE_LIGHT] != 0) screenIconUpdate(states[STATE_LIGHT], true);
        if (states[STATE_HIGH_BEAM]) screenIconUpdate(2, true);
        if (states[STATE_FOG_LIGHT]) screenIconUpdate(3, true);
    }
}   

void screenSettingsFlashes()
{
    screenSelectedSetting(1); 
    display.setCursor(1, 30);
    display.print(F("FLASHES: "));
    if (!settings[SETTING_FLASH_BRAKE_LIGHT]) display.print("No");
    else
    {
        display.print("Yes");
        display.setTextColor(WHITE, BLACK);
        display.print("  "); 
        screenSelectedSetting(2);
        display.print(settings[SETTING_BRAKE_FLASHES]);
    } 
}

void screenSettings()
{
	display.fillScreen(BLACK);

	// TITLE
	display.setTextColor(WHITE, BLACK);
	display.setCursor(1, 1);
	display.setTextSize(2);
	display.print(F("SETTINGS"));
    display.setTextSize(1);

	if (turnSignals < 4) // FIRST "PAGE"
	{
		// UNIT
		display.setCursor(1, 20);
		screenSelectedSetting(0);
        display.print(F("UNITS: "));
		if (!settings[SETTING_UNIT]) display.print(F("Metric"));
			else display.print(F("Imperial"));

        // FLASHES FOR BRAKE LIGHT
        screenSettingsFlashes();

        // SCREEN SAVER
        screenSelectedSetting(3);  
        display.setCursor(1, 40);
        display.print(F("SCR SAVER: "));
        if (!settings[SETTING_SCREEN_SAVER]) display.print("No");
            else display.print("Yes");                             
	}
	else if (turnSignals < 11) // SECOND "PAGE"
	{
		display.setTextColor(WHITE, BLACK);

		display.setCursor(1, 20);
        screenDateSetting(3, pressedButton[0], pressedButton[4], pressedButton[1]);					

		display.setCursor(1, 30);
        screenTimeSetting(3, pressedButton[3], pressedButton[2], speed);    	

		// DATE
		if (turnSignals >= 4 && turnSignals <= 6)
		{
			display.setCursor(1, 20);
            screenDateSetting(turnSignals - 4, pressedButton[0], pressedButton[4], pressedButton[1]);
		}	

		// TIME
		else if (turnSignals >= 7 && turnSignals <= 9)
		{
			display.setCursor(1, 30);
			screenTimeSetting(turnSignals - 7, pressedButton[3], pressedButton[2], speed); 				
		}

        // LIGHTS
        screenSelectedSetting(10); 
        display.setCursor(1, 40);
        display.print(F("HEADLIGHT: "));

        if (!settings[SETTING_LIGHT_TIME]) display.print("1/10s");
        else if (settings[SETTING_LIGHT_TIME] == 1) display.print("1/5s");
        else if (settings[SETTING_LIGHT_TIME] == 2) display.print("1/4s");
        else if (settings[SETTING_LIGHT_TIME] == 3) display.print("1/3s");
        else display.print("Full");										
	}
    else if (turnSignals < 14) // THIRD "PAGE"
    {
        // BRAKE TRIGGER STEP
        screenSelectedSetting(11);   
        display.setCursor(1, 20);
        display.print("STEP: ");  
        display.print(brakeFlash); 

        // FRONT BRAKE TRIGGER & CURRENT VALUE FROM SENSOR
        screenSelectedSetting(12); 
        display.setCursor(1, 30);
        display.print(F("FRONT BR: "));  
        display.print(triggers[TRIGGER_FRONT_BRAK]);

        // REAR BRAKE TRIGGER & CURRENT VALUE FROM SENSOR
        screenSelectedSetting(13); 
        display.setCursor(1, 40);
        display.print(F("REAR BR: "));  
        display.print(triggers[TRIGGER_REAR_BRAKE]);               
    }
    else if (turnSignals < 18) // FOURTH "PAGE"
    {
        // BRAKE TRIGGER STEP
        display.setTextColor(WHITE, BLACK);
        display.setCursor(1, 20);
        display.print("HEADLIGHT: ");
        screenSelectedSetting(14);     
        display.print(settings[SETTING_BR_DLIGHT]);
        display.setTextColor(WHITE, BLACK);
        display.print("/"); 
        screenSelectedSetting(15);
        display.print(settings[SETTING_BR_LIGHT]);

        display.setCursor(1, 30);
        display.setTextColor(WHITE, BLACK);
        display.print("TAIL LIGHT: ");
        screenSelectedSetting(16);     
        display.print(settings[SETTING_BR_DTAILLIGHT]);
        display.setTextColor(WHITE, BLACK);
        display.print("/"); 
        screenSelectedSetting(17);
        display.print(settings[SETTING_BR_TAILLIGHT]);                       
    }			
}

void screenDateSetting(uint8_t setting, uint8_t day, uint8_t month, uint8_t year)
{
    display.setTextColor(WHITE, BLACK);
    display.print("DATE: "); 

    if (!setting && setting != 3) display.setTextColor(BLACK, WHITE);
        else display.setTextColor(WHITE, BLACK);
    display.print(day);

    display.setTextColor(WHITE, BLACK);
    display.print('.');

    if (setting == 1 && setting != 3) display.setTextColor(BLACK, WHITE);
        else display.setTextColor(WHITE, BLACK);    
    display.print(month);

    display.setTextColor(WHITE, BLACK);
    display.print('.');

    if (setting == 2 && setting != 3) display.setTextColor(BLACK, WHITE);
        else display.setTextColor(WHITE, BLACK);
    display.print(2000 + year);

    display.setTextColor(WHITE, BLACK);
    display.print('.');      
}

void screenTimeSetting(uint8_t setting, uint8_t hour, uint8_t minute, uint8_t second)
{
    display.setTextColor(WHITE, BLACK);
    display.print("TIME: "); 

    if (!setting && setting != 3) display.setTextColor(BLACK, WHITE);
        else display.setTextColor(WHITE, BLACK);
    display.print(hour);

    display.setTextColor(WHITE, BLACK);
    display.print(':');

    if (setting == 1 && setting != 3) display.setTextColor(BLACK, WHITE);
        else display.setTextColor(WHITE, BLACK);    
    display.print(minute);

    display.setTextColor(WHITE, BLACK);
    display.print(':');

    if (setting == 2 && setting != 3) display.setTextColor(BLACK, WHITE);
        else display.setTextColor(WHITE, BLACK);
    display.print(second);    
}

void screenSelectedSetting(uint8_t setting)
{
    if (turnSignals == setting) display.setTextColor(BLACK, WHITE);
        else display.setTextColor(WHITE, BLACK);  
}

void screenUpdate(bool clock)
{
    if (!states[STATE_SCREEN_INFO]) screenDistance();
    else if (states[STATE_SCREEN_INFO] == 1) screenDistance(3);
    else if (states[STATE_SCREEN_INFO] == 2) screenDistance(4);
    else if (states[STATE_SCREEN_INFO] == 3) screenDistance(1);
    else if (states[STATE_SCREEN_INFO] == 4) screenDistance(2);
    else if (states[STATE_SCREEN_INFO] == 5) screenSpeedStat(SPEED_TOP);
    else if (states[STATE_SCREEN_INFO] == 6) screenSpeedStat(SPEED_MAX);
    else if (states[STATE_SCREEN_INFO] == 7) screenAvgDistance();
    else if (states[STATE_SCREEN_INFO] == 8) screenAvgSpeed();
    else if (states[STATE_SCREEN_INFO] == 9) screenTripTimeStat(STAT_PEDAL_TIME);
    else if (states[STATE_SCREEN_INFO] == 10) screenTripTimeStat(STAT_PEDAL_TIME_B);
    else if (states[STATE_SCREEN_INFO] == 11) screenEfficiency();
	else screenWorkHours();

    if (clock) screenTimeDateTemp();  
}

void frontLights(uint8_t first = 0, bool second = false)
{
    analogWrite(PIN_LED_FRONT_LIGHT, first); 
    digitalWrite(PIN_LED_2ND_FRONT_LIGHT, second);  
}

void rearLights(uint8_t first = 0, uint8_t second = 0)
{
   analogWrite(PIN_LED_TAIL_LIGHT, first);
   analogWrite(PIN_LED_2ND_TAIL_LIGHT, second); 
}



...

This file has been truncated, please download it to see its full contents.
Temp function for RTCC/C++
Function for reading temperature from DS3231. Paste this code in RTClib.cpp and in RTClib.h under "class RTC_DS3231" paste "int16_t temp();"
int16_t RTC_DS3231::temp()
{
    float rv;
    uint8_t temp_msb, temp_lsb;
    int8_t nint;

    Wire.beginTransmission(DS3231_I2C_ADDR);
    Wire.write(DS3231_TEMPERATURE_ADDR);
    Wire.endTransmission();

    Wire.requestFrom(DS3231_I2C_ADDR, 2);
    temp_msb = Wire.read();
    temp_lsb = Wire.read() >> 6;

    if ((temp_msb & 0x80) != 0)
        nint = temp_msb | ~((1 << 8) - 1);      // if negative get two's complement
    else
        nint = temp_msb;
    rv = 0.25 * temp_lsb + nint;

    return int(rv);
}

Schematics

Project scheme
Part by part. Simple and clean scheme.
Completed project scheme
Completed scheme of the project. If it looks confusing for you, use first scheme.

Comments

Similar projects you might like

Bluetooth-Enabled Bicycle Turn Signal

Project tutorial by simonwongwong

  • 914 views
  • 2 comments
  • 12 respects

Arduino Nano as CP/M-Compatible Computer

Project in progress by FoxyLab

  • 13,962 views
  • 17 comments
  • 32 respects

Probability | Autonomous Rover

Project in progress by colepurtzer

  • 6,228 views
  • 19 comments
  • 41 respects

Arduino TV Volume Control

Project tutorial by Sam

  • 5,428 views
  • 1 comment
  • 15 respects

Interactive Children's Jack-In-The-Box

Project tutorial by Team 10

  • 597 views
  • 0 comments
  • 4 respects
Add projectSign up / Login