組員:411214204 郭凱翔
動機:
我喜歡車,想自己改車,所以想做個結合測轉速和測距的儀器,方便隨時調校我的車,呸爆別人。
作品介紹:
材料:
Arduino板、超音波感測器(HC-SR04)、OLED模組、紅外線感測器、按鈕、麵包板、按鈕。
製作:
將超音波感測器、OLED模組和紅外線感測器與Arduino板接在一起,編寫驅動程式,讓三個元件能夠一起運作。
接線圖:
成品:
程式碼:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Pins
#define trigPin 6
#define echoPin 7
#define buttonPin 2
#define rpmSensorPin 3
// Mode Control
int mode = 1; // 1 = distance, 2 = tachometer
unsigned long lastButtonPress = 0;
int pressCount = 0;
// RPM
volatile int rpmCount = 0;
volatile unsigned long lastPulseTime = 0;
unsigned long lastRPMUpdate = 0;
float rpm = 0;
// Distance
long duration;
float distance;
void countRevolutions() {
unsigned long now = millis();
if (now - lastPulseTime > 50) {
rpmCount++;
lastPulseTime = now;
}
}
void printCentered(const char* text, int y, int textSize = 1) {
display.setTextSize(textSize);
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
int x = (SCREEN_WIDTH - w) / 2;
display.setCursor(x, y);
display.print(text);
}
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(rpmSensorPin, INPUT);
attachInterrupt(digitalPinToInterrupt(rpmSensorPin), countRevolutions, RISING);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
Serial.begin(9600);
}
void loop() {
if (digitalRead(buttonPin) == LOW) {
delay(50); // debounce
if (digitalRead(buttonPin) == LOW) {
if (millis() - lastButtonPress < 400) {
pressCount++;
} else {
pressCount = 1;
}
lastButtonPress = millis();
while (digitalRead(buttonPin) == LOW);
}
}
if (pressCount == 1 && millis() - lastButtonPress > 400) {
mode = 1;
pressCount = 0;
} else if (pressCount == 2 && millis() - lastButtonPress > 400) {
mode = 2;
pressCount = 0;
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
if (mode == 1) {
// Distance mode
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.0343 / 2;
printCentered("Mode: Distance", 0);
char distStr[10];
dtostrf(distance, 5, 1, distStr);
char finalStr[20];
snprintf(finalStr, sizeof(finalStr), "Dist: %s cm", distStr);
printCentered(finalStr, 25);
Serial.print("Distance: ");
Serial.println(distStr);
} else if (mode == 2) {
// Tachometer mode
if (millis() - lastRPMUpdate >= 1000) {
rpm = rpmCount * 60.0;
rpmCount = 0;
lastRPMUpdate = millis();
}
printCentered("Mode: Tachometer", 0);
char rpmStr[10];
dtostrf(rpm, 5, 1, rpmStr);
char finalStr[20];
snprintf(finalStr, sizeof(finalStr), "RPM: %s", rpmStr);
printCentered(finalStr, 25);
Serial.print("RPM: ");
Serial.println(rpmStr);
}
display.display();
}
心得:
這次的實作我覺得非常有困難難度,因為我從來沒有用過OLED和紅外線接收發射器,從接線、寫程式到最後的上傳測試,對我來說都非常具有挑戰性,但我也充分理解了要怎麼去幫OLED和紅外線接收發射器去編寫程式,最後還是順利地完成了,這次實作讓我對於Arduino的操作又更加多元了,也增加了我的成就感,希望我之後能夠再做出其他具有挑戰性的作品。
成果展示:
https://youtu.be/ViHuT__4_t8