设为首页收藏本站

[应用教程] 【FireBeetle Board-ESP32应用教程】跑步运动的计步神器

Chocho2017 发表于 2017-6-13 15:20:38 | 显示全部楼层 [复制链接]
17 2623
曾几何时
我也是个运动健儿,骑单车、打羽毛球,不落下风
曾几何时
骑着我的捷安特,问道青城山,驰骋都江堰,毫不逊色
而如今
。。。 。。。 。。。
:'(:'(:'(:'(:'(:'(:'(:'(:'(

    于此,为了昔日健硕的身躯,我下定决心重新出发,锻炼身体。每天坚持跑步两公里。咦?得有一个计步器记录每天的步数。于是,就有了这个计步神器的诞生,先来一发视频:


    此神器,可以实时的记录步数(以及消耗的卡路里),可以显示时间,最炫酷的当然是以指针的形式显示时间:
show.gif

还可以将数据上传到网络,通过手机软件(Blynk)显示数据,同时获取网络时间(就不用担心电池没电了时间跑飞)。

所需硬件:
     DFR0478 FireBeetle Board-ESP32
     DFR0486  OLED12864显示屏
     SEN0140 加速度计模块
      3.7V锂电池(这个是在网上买的,容量是600mAH)
      3个按键(网上买的)
手机软件用的是Blynk,搭建起来方便,关于如何使用Blynk建立IoT项目,可以参考我之前的帖子,点击链接

1、创建一个Blynk项目
    添加如下两个控件:
      Value Display × 1
      Real-time clock × 1
    其中Real-time clock控件的属性不需要任何设置,Value Display控件名称设置成steps,INPUT引脚选择V1。然后调整两个控件的布局,如下图所示:
9.png


2、下载程序到FireBeetle Board-ESP32
    程序源码,点击下载,源码中还包括了库文件和3D打印文件,需要将库文件放到Arduino IDE的libraries下面,3D文件可以直接打印出外壳。
    主程序代码如下:
[AppleScript] 纯文本查看 复制代码
#include <TimeLib.h>
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"`
#include "OLEDDisplayUi.h"
#include "images.h"
#include <SimpleTimer.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <WidgetRTC.h>

#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();
}



    需要注意的是,将源码中的WiFi、密码,以及AUTHTOKENS改成你自己的,修改部分如下:

[AppleScript] 纯文本查看 复制代码
char auth[] = "YourAuthToken";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";


3、硬件组装
    OLED12864显示屏和加速度计模块都连接到I2C,按键分别连接到D2、D3、D4,其中,按键需要加51K上拉电阻,上拉到3.3V,如下图所示:

3.png

注意:图中上拉接到AREF是错的,需要连接到3.3V

    硬件焊接图,如下所示:

1.png 2.png


    硬件焊接完成后,将硬件模块组装到外壳中,如下所示:

4.png 5.png 6.png


    整体效果展示:

7.png 8.png


发表于 2017-6-13 15:21:57 | 显示全部楼层
照例,自己先抢个沙发。;P;P;P;P;P;P;P;P
回复 支持 反对

使用道具 举报

发表于 2017-6-13 15:35:52 | 显示全部楼层
楼主焊工牛B 看起来蛮帅的
回复 支持 反对

使用道具 举报

发表于 2017-6-13 16:41:18 | 显示全部楼层
UI界面不错,顶。
回复 支持 反对

使用道具 举报

发表于 2017-6-13 19:02:34 | 显示全部楼层
楼主的飞线功底果然扎实,牛逼!
回复 支持 反对

使用道具 举报

发表于 2017-6-14 08:56:10 | 显示全部楼层
Youyou 发表于 2017-6-13 19:02
楼主的飞线功底果然扎实,牛逼!

哈哈,还行吧。谢谢夸奖。
回复 支持 反对

使用道具 举报

发表于 2017-6-14 10:46:08 | 显示全部楼层
喜欢~界面非常酷!我之前也想用Blynk这款蓝牙APP,但注册几次都失败了。。。
回复 支持 反对

使用道具 举报

发表于 2017-6-14 11:06:55 | 显示全部楼层
这个厉害了,哈哈哈
回复 支持 反对

使用道具 举报

发表于 2017-6-14 13:22:09 | 显示全部楼层
源代码 发表于 2017-6-14 10:46
喜欢~界面非常酷!我之前也想用Blynk这款蓝牙APP,但注册几次都失败了。。。 ...

你可以能下载的版本不对,我在另外一篇帖子里面提到过的。你可以去看一下。我之前的Blynk软件就是这个问题,一直注册不成功。
回复 支持 反对

使用道具 举报

发表于 2017-6-14 13:22:31 | 显示全部楼层
hnyzcj 发表于 2017-6-14 11:06
这个厉害了,哈哈哈

呵呵 ,谢谢。
回复 支持 反对

使用道具 举报

发表于 2017-6-14 14:13:45 | 显示全部楼层
Chocho2017 发表于 2017-6-14 13:22
你可以能下载的版本不对,我在另外一篇帖子里面提到过的。你可以去看一下。我之前的Blynk软件就是这个问 ...

好的  我去看看
回复 支持 反对

使用道具 举报

发表于 2017-6-14 15:10:25 | 显示全部楼层

:victory::victory::victory::victory::victory::victory::victory::victory::victory::victory:
回复 支持 反对

使用道具 举报

发表于 2017-6-26 15:35:08 | 显示全部楼层
太牛逼了
回复 支持 反对

使用道具 举报

发表于 2017-6-26 16:00:16 | 显示全部楼层
那个10自由度惯性导航模块和OLED的接线没讲清楚啊,大哥请讲一下
回复 支持 反对

使用道具 举报

发表于 2017-6-27 10:47:53 | 显示全部楼层
xiaohe9527 发表于 2017-6-26 16:00
那个10自由度惯性导航模块和OLED的接线没讲清楚啊,大哥请讲一下

是接I2C的,SDA接SDA,SCL接SCL。简单啦。
回复 支持 反对

使用道具 举报

发表于 2017-7-6 15:26:37 | 显示全部楼层
虽然硬件不限听那个,打算做下试试
回复 支持 反对

使用道具 举报

发表于 2017-7-7 10:50:34 | 显示全部楼层
请问您的51K上拉电阻是如何测量的?
回复 支持 反对

使用道具 举报

发表于 2017-7-7 14:55:08 | 显示全部楼层
gray6666 发表于 2017-7-7 10:50
请问您的51K上拉电阻是如何测量的?

51K只是个电阻的参考范围,你可以用47K的。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册  

本版积分规则 允许回帖同步到新浪微博  

推荐阅读

精华导读




公司简介| 联系我们| 小黑屋| 加入我们| 微博| 优酷| 英文网站| DF创客社区 ( 沪ICP备09038501号-4  
友情链接| 硬创邦| 花生壳社区| 模友之吧| 电子发烧友社区| 创客星球| 云汉电子社区| 电子工程网| 与非网| Arduino中文社区| 南极熊3D打印网| OneNET|

上海智位机器人有限公司  沪ICP备09038501号-4   

Powered by Discuz! X3.1

Licensed Comsenz Inc.

返回顶部 返回列表