Introduction: How to Make a Step Counter?

I used to perform well at many sports: walking, running, riding bicycle, playing badminton etc.

I love riding to travel around before long. Well, look at my portly belly……

Well, anyway, I decide to restart to exercise. What equipment should I prepare? Besides sports facility, yes! I need an instrument! I believe with it, I can keep appropriate amount of exercise. Here the instrument comes into being.
Let’s begin with a video~

The instrument not just can record steps
(and calories) at real time, but show time. What is special is that the format of showing is pointer~ so cool! I really, really like it!

You can upload your records to the Internet

only by one click. All records can be displayed by Blynk (a smart-phone software introduced before). The same as wearable smart watch, the instrument get time on line (So you need not afraid of the power and time updating).

Hardware in meed:

FireBeetle Board-ESP32

FireBeetle Covers-Proto Board

OLED12864 dispaly screen

Acceleration module

3.7V battery ( bought online, the volume is around 600mAH)

3 bottoms ( bought online)

It is very convenient to build this project by Blybk.

Step 1: Create a Blynk Project

Add two controls:

Value Display * 1

Real-time clock * 1

The name of Value Display should be set to steps, but no setting for the properties of Real-time clock. Choose V1 as the input pin to asjust the layout of controls, shown as below.

Step 2: Download Programs to FireBeetle Board-ESP32

Click here to download the source code to esp32. The source code consists library files and 3D printing files. You should save the library file to lib of arduino. And the 3D files can print crusts directly.

Below is the main program

<p>#include <br>#include   // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
#include "OLEDDisplayUi.h"
#include "images.h"
#include 
#include 
#include 
#include 
#include 
 
#define POWER_KEY 1
#define MENU_KEY  2
#define UPLOAD_KEY 3
 
boolean upload = false;
 
SSD1306  display(0x3c, 18, 0);
 
OLEDDisplayUi ui ( &display );
 
SimpleTimer timer;
WidgetRTC rtc;
 
int screenW = 128;
int screenH = 64;
int clockCenterX = screenW/2;
int clockCenterY = ((screenH-16)/2)+16;   // top yellow part is 16 px height
int clockRadius = 23;
 
#define DEVICE (0x53)      //ADXL345 device address
#define TO_READ (6)        //num of bytes we are going to read each time (two bytes for each axis)
 
byte buff[TO_READ] ;        //6 bytes buffer for saving data read from the device
char str[100];              //string buffer to transform data before sending it to the serial port
int regAddress = 0x32;      //first axis-acceleration-data register on the ADXL345
int xx, yy, zz;                //three axis acceleration data
 
static int currentValue = 0;
static unsigned long stepsSum=0;
 
char auth[] = "YourAuthToken";
 
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";
 
const char running_Logo_bits[] PROGMEM = {
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x64,0x03,0x00,0x00,0x00,0xF8,0x01,0x00,0x00,0x00,0xF8,0x01,0x00,0x00,0x00,0xFC,
  0x01,0x00,0x00,0x00,0xFC,0x05,0x00,0x00,0x00,0xFC,0x01,0x00,0x00,0x00,0xFC,0x00,
  0x00,0x00,0x00,0xF8,0x01,0x00,0x00,0x00,0xF8,0x01,0x00,0x00,0x00,0xE0,0x03,0x00,
  0x00,0x60,0xF1,0x07,0x00,0x00,0x20,0xF8,0x17,0x00,0x00,0xC0,0xF8,0x0F,0x00,0x00,
  0xE0,0xFB,0x17,0x00,0x00,0xC0,0xFF,0x13,0x00,0x00,0x00,0xFF,0x03,0x00,0x00,0x80,
  0xFE,0x03,0x00,0x00,0x00,0xF9,0x03,0x00,0x00,0x00,0xFA,0x03,0x00,0x00,0x00,0xF8,
  0x03,0x00,0x00,0x00,0xF0,0x07,0x00,0x00,0x00,0xF4,0x07,0x00,0x00,0x00,0xF4,0x0F,
  0x00,0x00,0x00,0xF9,0x0F,0x00,0x00,0x00,0xFC,0x1F,0x00,0x00,0x80,0xFE,0x1F,0x00,
  0x00,0x00,0xFF,0x1F,0x00,0x00,0xA0,0xFF,0x5F,0x00,0x00,0xC0,0x3F,0x3F,0x00,0x00,
  0xE8,0x1F,0x3F,0x00,0x00,0xE8,0xA7,0x3E,0x00,0x00,0xF0,0x03,0x7C,0x00,0x00,0xE0,
  0x05,0x7C,0x00,0x00,0xE0,0x05,0xF8,0x01,0x00,0xC0,0x01,0xF0,0x03,0x00,0xC0,0x03,
  0xE8,0x07,0x00,0xC0,0x03,0x88,0x6F,0x00,0x80,0x03,0x40,0x1E,0x00,0xA0,0x03,0x40,
  0xFC,0x00,0x80,0x03,0x00,0xF8,0x01,0x00,0x07,0x00,0xF4,0x00,0x00,0x07,0x00,0xE8,
  0x00,0x80,0x0F,0x00,0xE8,0x00,0x90,0x0F,0x00,0xE0,0x00,0xE8,0x0F,0x00,0xE8,0x00,
  0xF0,0x09,0x00,0x60,0x01,0xF0,0x04,0x00,0x00,0x00,
};
 
// utility function for digital clock display: prints leading 0
String twoDigits(int digits){
  if(digits < 10) {
    String i = '0'+String(digits);
    return i;
  }
  else {
    return String(digits);
  }
}
 
void clockOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
  if((hour()==0) && (minute()==0) && (second()==0))
    stepsSum = 0;
}
 
void analogClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  display->drawCircle(clockCenterX + x, clockCenterY + y, 2);
 
  //hour ticks
  for( int z=0; z < 360;z= z + 30 ){
    float angle = z ;
    angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
    int x2 = ( clockCenterX + ( sin(angle) * clockRadius ) );
    int y2 = ( clockCenterY - ( cos(angle) * clockRadius ) );
    int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) );
    int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) );
    display->drawLine( x2 + x , y2 + y , x3 + x , y3 + y);
  }
 
  // display second hand
  float angle = second() * 6 ;
  angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
  int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) );
  int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) );
  display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
   
  // display minute hand
  angle = minute() * 6 ;
  angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
  x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) );
  y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) );
  display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
 
  // display hour hand
  angle = hour() * 30 + int( ( minute() / 12 ) * 6 )   ;
  angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
  x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) );
  y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) );
  display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
}
 
void digitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  String date = String(year())+"/"+twoDigits(month())+"/"+twoDigits(day());
  String timenow = String(hour())+":"+twoDigits(minute())+":"+twoDigits(second());
   
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_24);
  display->drawString(clockCenterX + x , 20, timenow);
  display->setFont(ArialMT_Plain_16);
  display->drawString(60 , 45, date);
}
 
void writeTo(int device, byte address, byte val) {
  Wire.beginTransmission(device); //start transmission to device 
  Wire.write(address);        // send register address
  Wire.write(val);        // send value to write
  Wire.endTransmission(); //end transmission
}
 
//reads num bytes starting from address register on device in to buff array
void readFrom(int device, byte address, int num, byte buff[]) {
  Wire.beginTransmission(device); //start transmission to device 
  Wire.write(address);        //sends address to read from
  Wire.endTransmission(); //end transmission
 
  Wire.beginTransmission(device); //start transmission to device
  Wire.requestFrom(device, num);    // request 6 bytes from device
 
  int i = 0;
  while(Wire.available())    //device may send less than requested (abnormal)
  {
    buff= Wire.read(); // receive a byte
    i++;
  }
  Wire.endTransmission(); //end transmission
}
 
void runningFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  float calValue = stepsSum*0.4487;
   
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_24);
  display->drawString(clockCenterX , clockCenterY, str);
 
  sprintf(str,"%.2fcal",calValue);
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_10);
  display->drawString(100 , 20, str);
   
  display->drawXbm(10, 14, 34, 50, running_Logo_bits);
}
 
void uploadFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  display->setFont(ArialMT_Plain_16);
  display->drawString(60 , 45, "upload data ...");
}
 
// This array keeps function pointers to all frames
// frames are the single views that slide in
FrameCallback frames[] = { analogClockFrame, digitalClockFrame, runningFrame, uploadFrame};
 
// how many frames are there?
int frameCount = 4;
 
// Overlays are statically drawn on top of a frame eg. a clock
OverlayCallback overlays[] = { clockOverlay };
int overlaysCount = 1;
 
void uploadToBlynk(void){
  if(upload == true){
    Blynk.virtualWrite(V0,stepsSum);
    Blynk.virtualWrite(V1,stepsSum);
  }
}
 
void uiInit(void){
  ui.setTargetFPS(30);
  //ui.setActiveSymbol(activeSymbol);
  //ui.setInactiveSymbol(inactiveSymbol);
  ui.setIndicatorPosition(TOP);
  ui.setIndicatorDirection(LEFT_RIGHT);
  ui.setFrameAnimation(SLIDE_LEFT);
  ui.setFrames(frames, frameCount);
  ui.setOverlays(overlays, overlaysCount);
  ui.disableAutoTransition();
  ui.switchToFrame(2);
  ui.init();
  display.flipScreenVertically();
}
 
void adxl345Init(void){
  writeTo(DEVICE, 0x2D, 0);      
  writeTo(DEVICE, 0x2D, 16);
  writeTo(DEVICE, 0x2D, 8);
}
 
void updateAdxl345(void){
  readFrom(DEVICE, regAddress, TO_READ, buff); //read the acceleration data from the ADXL345
  xx = (((int)buff[1]) << 8) | buff[0];   
  yy = (((int)buff[3])<< 8) | buff[2];
  zz = (((int)buff[5]) << 8) | buff[4];
   
  if(xx < 100){
    sprintf(str, "%d", stepsSum);  
    return;
  }
 
  if(fabs(xx - currentValue) > 80){
    if(xx < currentValue){
      stepsSum++;
    }
    currentValue = xx;
  }
  sprintf(str, "%d", stepsSum);  
}
 
int getKeys(void){
    if(digitalRead(D2) == LOW){
      delay(5);
      if(digitalRead(D2) == LOW){
        while(digitalRead(D2) == LOW);
        return POWER_KEY;
      }
    }
     if(digitalRead(D3) == LOW){
      delay(5);
      if(digitalRead(D3) == LOW){
        while(digitalRead(D3) == LOW);
        return MENU_KEY;
      }
    }
     if(digitalRead(D4) == LOW){
      delay(5);
      if(digitalRead(D4) == LOW){
        while(digitalRead(D4) == LOW);
        return UPLOAD_KEY;
      }
    }
    return 0;
}
 
void doKeysFunction(void){
  static int uiFrameIndex = 2;
  int keys = getKeys();
  if(keys == POWER_KEY){
    static char i = 0;
    if(i){
      ui.init();
     display.flipScreenVertically();
     display.displayOn();
    }else{
     display.displayOff();
    }
    i = ~i;
  }
  if(keys == MENU_KEY){
    if(upload == false){
      uiFrameIndex++;
      if(uiFrameIndex == 3)
       uiFrameIndex = 0;     
      ui.switchToFrame(uiFrameIndex);
    }else{
      ui.switchToFrame(3);
    }
  }
  if(keys == UPLOAD_KEY){
    if(upload == true){
      upload = false;
      ui.switchToFrame(uiFrameIndex);
    }else{
      upload = true;
      ui.switchToFrame(3);
    }
  }
}
 
void setup() {
  pinMode(D2,INPUT);
  pinMode(D3,INPUT);
  pinMode(D4,INPUT);
  Blynk.begin(auth, ssid, pass);
  rtc.begin();
  uiInit();
  adxl345Init();
 
  timer.setInterval(30,updateAdxl345);
  timer.setInterval(100,uploadToBlynk);
}
 
void loop() {
  int remainingTimeBudget = ui.update();
  static int testSum = 0;
  if((testSum < 100) || (upload == true)){
   Blynk.run();
   testSum++;
  }
  if (remainingTimeBudget > 0) {
    delay(remainingTimeBudget);
  }
  doKeysFunction();
  timer.run();
}</p>

Caution: You should modify Wi-Fi setting, passport and AUTHTOKENS to yourself.

<p>char auth[] = "YourAuthToken";<br> 
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";</p>

Step 3: Hardware Connection

Connect OLED12864 and acceleration module to I2C, bottoms to D2, D3, D4. Moreover, add 51k pull-up resistors to bottoms to reach 3.3V, shown as below.

Caution: It’s wrong to connect pull-up resistors to AREF, the right one is to 3.3V

The hardware soldering image, shown as below:

After the solder, assembling hardware module to crust, shown as below:

Comprehensive effect image~

Comments

About This Instructable

806views

10favorites

License:

Bio: I'm from DFRobot.com, we will often make some interesting applications and share with you all. If you have any questions, welcome to comment.
More by Jaychouu:How to make a small measuring WheelHow to make an office thermometer with DS18B20?How to Make a Temperature Gun With Esp32
Add instructable to: