基于esp32 Arduino自制蓝牙HUD显示

物料

1. Esp32开发板(带蓝牙)--19元

2. 1.6寸 130*130 半反半透屏 SPI接口(强烈建议半反半透屏,整体效果均衡,阳光下效果也不错)   ---- 15元, 现在涨到20+了

3. 万能 PCB板,排针,排针座(如果屏幕直插,注意排针和排针座高度,或者直接用排线),蜂鸣器(可选) ---算10元吧

4. 蓝牙OBD(建议选拔掉壳后,薄薄的哪种,不影响把盖子盖回去)  ---10十~40元,基本最便宜的都能满足需求

连线也极其简单,就是屏幕,另外有一个按键,这个按键完全可以不要

/*******************************************************************************
   Start of Arduino_GFX setting

   Arduino_GFX try to find the settings depends on selected board in Arduino IDE
   Or you can define the display dev kit not in the board list
   Defalult pin list for non display dev kit:
   Arduino Nano, Micro and more: TFT_CS:  9, TFT_DC:  8, TFT_RST:  7, TFT_BL:  6
   ESP32 various dev board     : TFT_CS:  5, TFT_DC: 27, TFT_RST: 33, TFT_BL: 22
   ESP8266 various dev board   : TFT_CS: 15, TFT_DC:  4, TFT_RST:  2, TFT_BL:  5
   Raspberry Pi Pico dev board : TFT_CS: 17, TFT_DC: 27, TFT_RST: 26, TFT_BL: 28
   RTL872x various dev board   : TFT_CS: 18, TFT_DC: 17, TFT_RST:  2, TFT_BL: 23
   Seeeduino XIAO dev board    : TFT_CS:  3, TFT_DC:  2, TFT_RST:  1, TFT_BL:  0
   Teensy 4.1 dev board        : TFT_CS: 39, TFT_DC: 41, TFT_RST: 40, TFT_BL: 22
 ******************************************************************************/
#include <Arduino_GFX_Library.h>
#include "FreeMonoBold14pt7b.h"
#include "FreeMonoBold36pt7b.h"

#include "BluetoothSerial.h"
#include "ELMduino.h"
#include "time.h"
#include "esp_system.h"

uint8_t address[6]  = {0x34, 0x90, 0x1b, 0x20, 0xa6, 0x92};
String name = "OBDII";
BluetoothSerial SerialBT;
#define ELM_PORT SerialBT
#define DEBUG_PORT Serial
#define MAX_SPEED 512
#define INVALID_SPEED -1
#define BUTTON_PIN 32
#define BUZZER_VCC 18
#define BUZZER_GND 19

struct Button {
  const uint8_t PIN;
  uint32_t numberKeyPresses;
  unsigned long lastInterrupt;
  bool pressed;
};

Arduino_DataBus *bus = new Arduino_ESP32SPI(4 /* DC */, 15 /* CS */, 17 /* SCK */, 16 /* MOSI */, -1 /* MISO */, VSPI /* spi_num */);
Arduino_GFX *gfx = new Arduino_SSD1283A(bus, 2 /* RST */, 2 /* rotation */);
Button button1 = {BUTTON_PIN, 0, 0, false};
ELM327 myELM327;
int32_t oriSpeed = 0;
int32_t fixSpeed = 0;
int32_t lastOriSpeed = 0;

unsigned long bootTime = 0 ;
unsigned long runTime = 0;
bool isBuzzerEnable = true;
bool lastStatusOk = false;

void buzzerOn() {
  digitalWrite(BUZZER_VCC, HIGH);
}

void buzzerOff() {
  digitalWrite(BUZZER_VCC, LOW);
}

void buzzerTime(uint8_t t) {
  if (!isBuzzerEnable) {
    return;
  }
  for (uint8_t i = 0 ; i < t; i++) {
    buzzerOn();
    delay(200 + i * 30);
    buzzerOff();
    delay(50 + i * 10);
  }
}

//void measure(char *s, int16_t x, int16_t y) {
//
//  int16_t x1, y1;
//  uint16_t w, h;
//  gfx->getTextBounds(s, x, y, &x1, &y1, &w, &h);
//  //  gfx->fillRect(x1, y1, w, h, BLACK);
//  Serial.printf("x1 = %d , y1 = %d, w = %d, h = %d\n", x1, y1, w, h);
//}

void initBuzzer() {
  pinMode(BUZZER_VCC, OUTPUT);  // Buzzer VCC
  pinMode(BUZZER_GND, OUTPUT);  // Buzzer GND
  digitalWrite(BUZZER_VCC, HIGH);
  digitalWrite(BUZZER_GND, LOW);
  delay(50);
  digitalWrite(BUZZER_VCC, LOW);
}

void initTFT() {
  gfx->begin();
  gfx->fillScreen(BLACK);
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);
  gfx->setFont(&FreeMonoBold14pt7b);
  gfx->fillScreen(BLACK);
}


void showRuntime() {
  uint16_t x = 1;
  uint16_t y = 20;

  gfx->setTextColor(YELLOW, BLACK);
  gfx->setCursor(x, y);
  gfx->setFont(&FreeMonoBold14pt7b);

  uint8_t h = runTime / 3600;
  uint8_t m = runTime / 60 % 60;
  uint8_t s = runTime % 60;
  gfx->printf("%02d:%02d:%02d", h, m, s);

}

void showFixSpeed(int32_t speed) {
  uint16_t x = 0;
  uint16_t y = 80;
  gfx->setTextColor(WHITE, BLACK);
  gfx->setCursor(x, y);
  gfx->setFont(&FreeMonoBold36pt7b);
  gfx->printf("%3d", speed);
}


void showOriSpeed(int32_t speed) {
  uint16_t x = 0;
  uint16_t y = 120;
  gfx->setFont(&FreeMonoBold14pt7b);
  gfx->setTextColor(GREEN, BLACK);
  gfx->setCursor(1, 120);
  gfx->printf("%3d", speed);
  gfx->setTextColor(PINK, BLACK);
  gfx->setCursor(60, 120);
  gfx->printf("km/h");
}

void initOBD() {
  int8_t retryCount = 0;
  gfx->setFont(&FreeMonoBold14pt7b);
  gfx->setCursor(0, 60);
  gfx->println("initOBD");

  DEBUG_PORT.begin(115200);
  //  SerialBT.setPin("1234");
  ELM_PORT.begin("ArduHUD", true);

  while (!ELM_PORT.connect(address)) {
    //  while (!ELM_PORT.connect("MI9")) {
    DEBUG_PORT.println("Couldn't connect to OBD scanner - 1");
    gfx->fillScreen(BLACK);
    gfx->setCursor(0, 60);
    gfx->printf("Connect\n   %d", ++retryCount);
    if (retryCount > 5) {
      gfx->fillScreen(BLACK);
      gfx->setCursor(0, 60);
      gfx->println("Restart");
      delay(2000);
      esp_restart();
    }
  }

  if (!myELM327.begin(ELM_PORT, true, 2000)) {
    DEBUG_PORT.println("Couldn't connect to OBD scanner - 2");
    gfx->fillScreen(BLACK);
    gfx->setCursor(0, 60);
    gfx->println("No connection");
  }

  DEBUG_PORT.println("Connected to ELM327");
}


void printSpeed() {
  static uint8_t noDataCount = 0;
  oriSpeed = myELM327.kph();
  if (myELM327.status != ELM_SUCCESS) {
    noDataCount++;
    if (noDataCount >= 3) {
      myELM327.printError();
      gfx->fillScreen(BLACK);
      gfx->setCursor(0, 60);
      gfx->println("no data");
      lastStatusOk = false;
    }
  } else {
    if (oriSpeed > MAX_SPEED) {
      oriSpeed = INVALID_SPEED;
    }
    fixSpeed = (int)(oriSpeed * 1.05 );
    if (!lastStatusOk) {
      gfx->fillScreen(BLACK);
    }
    showFixSpeed(fixSpeed);
    showOriSpeed(oriSpeed);
    lastStatusOk  = true;
    DEBUG_PORT.printf("oriSpeed = %d , lastOriSpeed = %d\n", oriSpeed, lastOriSpeed);
    if (oriSpeed > 120 && lastOriSpeed <= 120) {
      buzzerTime(3);
    } else if ( oriSpeed > 100 && lastOriSpeed <= 100) {
      buzzerTime(2);
    } else if (oriSpeed > 80 && lastOriSpeed <= 80) {
      buzzerTime(1);
    }
    lastOriSpeed = oriSpeed;
    noDataCount = 0;
  }
}

void IRAM_ATTR isr() {
  unsigned long curT = millis();
  DEBUG_PORT.printf("isr, time : %d, lastTime : %d \n", curT, button1.lastInterrupt);
  if (curT - button1.lastInterrupt < 10) {
    DEBUG_PORT.printf("skip isr, time : %d \n", curT - button1.lastInterrupt);
    return;
  }
  button1.lastInterrupt = curT;
  button1.numberKeyPresses += 1;
  isBuzzerEnable = !isBuzzerEnable;
  button1.pressed = true;
}

void setup(void)
{
  Serial.begin(115200);
  bootTime = millis();
  initBuzzer();
  initTFT();
  initOBD();
  // init Button
  pinMode(button1.PIN, INPUT_PULLUP);
  attachInterrupt(button1.PIN, isr, RISING);
  //  attachInterrupt(button1.PIN, isr, FALLING);
}


void loop()
{
  static long lastRefresh = 0;
  if (millis() - lastRefresh > 500) {
    lastRefresh = millis();
    runTime =  (millis() - bootTime) / 1000;
    showRuntime();
    printSpeed();
  }
  if (button1.pressed) {
    button1.pressed = false;
    gfx->fillScreen(BLACK);
    gfx->setCursor(0, 60);
    gfx->println(isBuzzerEnable ? "Enable Buzzer" : "Disable Buzzer");
    delay(1000);
  }
}

 

 

版权声明:本文为CSDN博主「yongwn」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yongwn/article/details/121673302

物料

1. Esp32开发板(带蓝牙)--19元

2. 1.6寸 130*130 半反半透屏 SPI接口(强烈建议半反半透屏,整体效果均衡,阳光下效果也不错)   ---- 15元, 现在涨到20+了

3. 万能 PCB板,排针,排针座(如果屏幕直插,注意排针和排针座高度,或者直接用排线),蜂鸣器(可选) ---算10元吧

4. 蓝牙OBD(建议选拔掉壳后,薄薄的哪种,不影响把盖子盖回去)  ---10十~40元,基本最便宜的都能满足需求

连线也极其简单,就是屏幕,另外有一个按键,这个按键完全可以不要

/*******************************************************************************
   Start of Arduino_GFX setting

   Arduino_GFX try to find the settings depends on selected board in Arduino IDE
   Or you can define the display dev kit not in the board list
   Defalult pin list for non display dev kit:
   Arduino Nano, Micro and more: TFT_CS:  9, TFT_DC:  8, TFT_RST:  7, TFT_BL:  6
   ESP32 various dev board     : TFT_CS:  5, TFT_DC: 27, TFT_RST: 33, TFT_BL: 22
   ESP8266 various dev board   : TFT_CS: 15, TFT_DC:  4, TFT_RST:  2, TFT_BL:  5
   Raspberry Pi Pico dev board : TFT_CS: 17, TFT_DC: 27, TFT_RST: 26, TFT_BL: 28
   RTL872x various dev board   : TFT_CS: 18, TFT_DC: 17, TFT_RST:  2, TFT_BL: 23
   Seeeduino XIAO dev board    : TFT_CS:  3, TFT_DC:  2, TFT_RST:  1, TFT_BL:  0
   Teensy 4.1 dev board        : TFT_CS: 39, TFT_DC: 41, TFT_RST: 40, TFT_BL: 22
 ******************************************************************************/
#include <Arduino_GFX_Library.h>
#include "FreeMonoBold14pt7b.h"
#include "FreeMonoBold36pt7b.h"

#include "BluetoothSerial.h"
#include "ELMduino.h"
#include "time.h"
#include "esp_system.h"

uint8_t address[6]  = {0x34, 0x90, 0x1b, 0x20, 0xa6, 0x92};
String name = "OBDII";
BluetoothSerial SerialBT;
#define ELM_PORT SerialBT
#define DEBUG_PORT Serial
#define MAX_SPEED 512
#define INVALID_SPEED -1
#define BUTTON_PIN 32
#define BUZZER_VCC 18
#define BUZZER_GND 19

struct Button {
  const uint8_t PIN;
  uint32_t numberKeyPresses;
  unsigned long lastInterrupt;
  bool pressed;
};

Arduino_DataBus *bus = new Arduino_ESP32SPI(4 /* DC */, 15 /* CS */, 17 /* SCK */, 16 /* MOSI */, -1 /* MISO */, VSPI /* spi_num */);
Arduino_GFX *gfx = new Arduino_SSD1283A(bus, 2 /* RST */, 2 /* rotation */);
Button button1 = {BUTTON_PIN, 0, 0, false};
ELM327 myELM327;
int32_t oriSpeed = 0;
int32_t fixSpeed = 0;
int32_t lastOriSpeed = 0;

unsigned long bootTime = 0 ;
unsigned long runTime = 0;
bool isBuzzerEnable = true;
bool lastStatusOk = false;

void buzzerOn() {
  digitalWrite(BUZZER_VCC, HIGH);
}

void buzzerOff() {
  digitalWrite(BUZZER_VCC, LOW);
}

void buzzerTime(uint8_t t) {
  if (!isBuzzerEnable) {
    return;
  }
  for (uint8_t i = 0 ; i < t; i++) {
    buzzerOn();
    delay(200 + i * 30);
    buzzerOff();
    delay(50 + i * 10);
  }
}

//void measure(char *s, int16_t x, int16_t y) {
//
//  int16_t x1, y1;
//  uint16_t w, h;
//  gfx->getTextBounds(s, x, y, &x1, &y1, &w, &h);
//  //  gfx->fillRect(x1, y1, w, h, BLACK);
//  Serial.printf("x1 = %d , y1 = %d, w = %d, h = %d\n", x1, y1, w, h);
//}

void initBuzzer() {
  pinMode(BUZZER_VCC, OUTPUT);  // Buzzer VCC
  pinMode(BUZZER_GND, OUTPUT);  // Buzzer GND
  digitalWrite(BUZZER_VCC, HIGH);
  digitalWrite(BUZZER_GND, LOW);
  delay(50);
  digitalWrite(BUZZER_VCC, LOW);
}

void initTFT() {
  gfx->begin();
  gfx->fillScreen(BLACK);
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);
  gfx->setFont(&FreeMonoBold14pt7b);
  gfx->fillScreen(BLACK);
}


void showRuntime() {
  uint16_t x = 1;
  uint16_t y = 20;

  gfx->setTextColor(YELLOW, BLACK);
  gfx->setCursor(x, y);
  gfx->setFont(&FreeMonoBold14pt7b);

  uint8_t h = runTime / 3600;
  uint8_t m = runTime / 60 % 60;
  uint8_t s = runTime % 60;
  gfx->printf("%02d:%02d:%02d", h, m, s);

}

void showFixSpeed(int32_t speed) {
  uint16_t x = 0;
  uint16_t y = 80;
  gfx->setTextColor(WHITE, BLACK);
  gfx->setCursor(x, y);
  gfx->setFont(&FreeMonoBold36pt7b);
  gfx->printf("%3d", speed);
}


void showOriSpeed(int32_t speed) {
  uint16_t x = 0;
  uint16_t y = 120;
  gfx->setFont(&FreeMonoBold14pt7b);
  gfx->setTextColor(GREEN, BLACK);
  gfx->setCursor(1, 120);
  gfx->printf("%3d", speed);
  gfx->setTextColor(PINK, BLACK);
  gfx->setCursor(60, 120);
  gfx->printf("km/h");
}

void initOBD() {
  int8_t retryCount = 0;
  gfx->setFont(&FreeMonoBold14pt7b);
  gfx->setCursor(0, 60);
  gfx->println("initOBD");

  DEBUG_PORT.begin(115200);
  //  SerialBT.setPin("1234");
  ELM_PORT.begin("ArduHUD", true);

  while (!ELM_PORT.connect(address)) {
    //  while (!ELM_PORT.connect("MI9")) {
    DEBUG_PORT.println("Couldn't connect to OBD scanner - 1");
    gfx->fillScreen(BLACK);
    gfx->setCursor(0, 60);
    gfx->printf("Connect\n   %d", ++retryCount);
    if (retryCount > 5) {
      gfx->fillScreen(BLACK);
      gfx->setCursor(0, 60);
      gfx->println("Restart");
      delay(2000);
      esp_restart();
    }
  }

  if (!myELM327.begin(ELM_PORT, true, 2000)) {
    DEBUG_PORT.println("Couldn't connect to OBD scanner - 2");
    gfx->fillScreen(BLACK);
    gfx->setCursor(0, 60);
    gfx->println("No connection");
  }

  DEBUG_PORT.println("Connected to ELM327");
}


void printSpeed() {
  static uint8_t noDataCount = 0;
  oriSpeed = myELM327.kph();
  if (myELM327.status != ELM_SUCCESS) {
    noDataCount++;
    if (noDataCount >= 3) {
      myELM327.printError();
      gfx->fillScreen(BLACK);
      gfx->setCursor(0, 60);
      gfx->println("no data");
      lastStatusOk = false;
    }
  } else {
    if (oriSpeed > MAX_SPEED) {
      oriSpeed = INVALID_SPEED;
    }
    fixSpeed = (int)(oriSpeed * 1.05 );
    if (!lastStatusOk) {
      gfx->fillScreen(BLACK);
    }
    showFixSpeed(fixSpeed);
    showOriSpeed(oriSpeed);
    lastStatusOk  = true;
    DEBUG_PORT.printf("oriSpeed = %d , lastOriSpeed = %d\n", oriSpeed, lastOriSpeed);
    if (oriSpeed > 120 && lastOriSpeed <= 120) {
      buzzerTime(3);
    } else if ( oriSpeed > 100 && lastOriSpeed <= 100) {
      buzzerTime(2);
    } else if (oriSpeed > 80 && lastOriSpeed <= 80) {
      buzzerTime(1);
    }
    lastOriSpeed = oriSpeed;
    noDataCount = 0;
  }
}

void IRAM_ATTR isr() {
  unsigned long curT = millis();
  DEBUG_PORT.printf("isr, time : %d, lastTime : %d \n", curT, button1.lastInterrupt);
  if (curT - button1.lastInterrupt < 10) {
    DEBUG_PORT.printf("skip isr, time : %d \n", curT - button1.lastInterrupt);
    return;
  }
  button1.lastInterrupt = curT;
  button1.numberKeyPresses += 1;
  isBuzzerEnable = !isBuzzerEnable;
  button1.pressed = true;
}

void setup(void)
{
  Serial.begin(115200);
  bootTime = millis();
  initBuzzer();
  initTFT();
  initOBD();
  // init Button
  pinMode(button1.PIN, INPUT_PULLUP);
  attachInterrupt(button1.PIN, isr, RISING);
  //  attachInterrupt(button1.PIN, isr, FALLING);
}


void loop()
{
  static long lastRefresh = 0;
  if (millis() - lastRefresh > 500) {
    lastRefresh = millis();
    runTime =  (millis() - bootTime) / 1000;
    showRuntime();
    printSpeed();
  }
  if (button1.pressed) {
    button1.pressed = false;
    gfx->fillScreen(BLACK);
    gfx->setCursor(0, 60);
    gfx->println(isBuzzerEnable ? "Enable Buzzer" : "Disable Buzzer");
    delay(1000);
  }
}

 

 

版权声明:本文为CSDN博主「yongwn」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yongwn/article/details/121673302

生成海报
点赞 0

yongwn

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

基于esp32 Arduino自制蓝牙HUD显示

物料 1. Esp32开发板(带蓝牙)--19元 2. 1.6寸 130*130 半反半透屏 SPI接口(强烈建议半反半透屏,整体效果均衡,阳光下效果也不错&#xff09

数码管轮播显示

硬件: 数码管10个引脚,8个控制二极管亮、灭,2个引脚为负极。1k欧电阻链接负极,接gnd。 将8个二极管引脚依次链接0-7号引脚。 软件: /*共阳极单数码管显示&