曾几何时 我也是个运动健儿,骑单车、打羽毛球,不落下风 曾几何时 骑着我的捷安特,问道青城山,驰骋都江堰,毫不逊色 而如今 。。。 。。。 。。。 :'(:'(:'(:'(:'(:'(:'(:'(:'(:'(
于此,为了昔日健硕的身躯,我下定决心重新出发,锻炼身体。每天坚持跑步两公里。咦?得有一个计步器记录每天的步数。于是,就有了这个计步神器的诞生,先来一发视频:
此神器,可以实时的记录步数(以及消耗的卡路里),可以显示时间,最炫酷的当然是以指针的形式显示时间:
还可以将数据上传到网络,通过手机软件(Blynk)显示数据,同时获取网络时间(就不用担心电池没电了时间跑飞)。
所需硬件: 3.7V锂电池(这个是在网上买的,容量是600mAH) 3个按键(网上买的) 手机软件用的是Blynk,搭建起来方便,关于如何使用Blynk建立IoT项目,可以参考我之前的帖子,点击链接。
1、创建一个Blynk项目 添加如下两个控件: Value Display × 1 Real-time clock × 1 其中Real-time clock控件的属性不需要任何设置,Value Display控件名称设置成steps,INPUT引脚选择V1。然后调整两个控件的布局,如下图所示:
2、下载程序到FireBeetle Board-ESP32 主程序代码如下:
- #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改成你自己的,修改部分如下:
- 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,如下图所示:
注意:图中上拉接到AREF是错的,需要连接到3.3V
硬件焊接图,如下所示:
硬件焊接完成后,将硬件模块组装到外壳中,如下所示:
整体效果展示:
查看更多ESP32/ESP8266教程和项目,请点击 : ESP32教程 汇总贴 |