Hi,
Anyone can help me and write what is wrong with connection P=MOSFET + BD139 to Arduino?
Arduino D2 is connected to BD139 Base but it does not matter if there is LOW or HIGH - P-MOSFET has 12V all the time on his Drain.
(VCC is 12V)
Hi,
Anyone can help me and write what is wrong with connection P=MOSFET + BD139 to Arduino?
Arduino D2 is connected to BD139 Base but it does not matter if there is LOW or HIGH - P-MOSFET has 12V all the time on his Drain.
(VCC is 12V)
Break the problem down.
Begin with only the BJT part of the circuit. Connect an led + series resistor between the collector and 12V. Can the Arduino pin turn the led on and off?
I do not understand - if I see B139, left pin is connected to GND, middle pin connected to pmosfet collector and right pin is connected to arduino using 1k resistor.
but look at the pin numbers
or may be this :
but note that the numbers 1, 2, and 3 are only relevant to that diagram. There is no standard.
OK, now that we know that is correct, some questions:
Do you have all the grounds connected?
What is connected to the drain?
What is connected to R7?
How are you measuring the voltage on the drain?
Nothing wrong with the circuit but you will have to do some debugging.
Measure the voltage on the BD139 collector when the voltage from D2 is HIGH and LOW.
If it does not change, then the DB139 is probably bad or you have a bad solder joint or connection somewhere
Show the code but also check that pin D2 is defined as an output pin.
Incidentally, it is more conventional to draw a high side switch as you have like this:
Ignore the numbers on the pins.
A BD139 is overkill for this application.
D2 is defined as an output:
PIN_RELAY_PLUS = 2
pinMode(PIN_RELAY_PLUS, OUTPUT);
Normally BD139 has 0.6V and when D2 is try to steer then I see here 3.9V... something is wrong?
My code for this:
#include <EEPROM.h>
// ----------- Konfiguracja sprzętu -----------
const int PIN_RELAY_PLUS = 2; // Przekaźnik impulsu +12V (IN1)
const int PIN_RELAY_GND = 3; // Przekaźnik impulsu GND (IN2)
const int PIN_BTN_GND = 4; // Przycisk do masy (GND z auta)
const int PIN_BTN_12 = 5; // Przycisk +12V (przez dzielnik 100k/47k + Zener)
const int PIN_SENSE_12V = A0; // Pomiar napięcia instalacji (dzielnik 100k/47k)
const int PIN_BUZZER = 6; // Buzzer aktywny (plus do pinu 6, minus do GND)
// UWAGA: Buzzer aktywny ma wbudowany generator dźwięku
// Podłączenie: Pin + buzzer do PIN_BUZZER (pin 6), Pin - buzzer do GND
// ----------- Parametry pomiaru napięcia -----------
const float R1 = 100000.0; // górny rezystor dzielnika (100k)
const float R2 = 47000.0; // dolny rezystor dzielnika (47k)
const float VREF = 5.0; // zasilanie Arduino z LM2596 (ref. ADC)
const float CAL = 1.051; // korekcja kalibracyjna (dostrojone: 13.7V rzeczywiste / 13.17V odczytane)
// UWAGA: Kondensator 100nF równolegle z R2 (między A0 a GND) jako filtr przeciwzakłóceniowy
const float THRESHOLD_V = 12.5; // próg wyzwolenia sekwencji startowej
// ----------- Czasy -----------
const unsigned long PULSE_MS = 500; // długość impulsu na przekaźniku (dla sekwencji startowej)
const unsigned long LOOP_DELAY_MS = 50; // odświeżanie pętli
const unsigned long MIN_IMPULSE_MS = 10; // minimalna długość impulsu do wykrycia (10ms)
const unsigned long TOGGLE_MS = 10000; // czas przytrzymania do wyłączenia/włączenia układu (10s)
// ----------- Pamięć EEPROM -----------
const int EEPROM_DISABLE_GND_ADDR = 0; // adres w EEPROM dla flagi AUTO GND
const int EEPROM_DISABLE_PLUS_ADDR = 1; // adres w EEPROM dla flagi AUTO +12V
const int EEPROM_SYSTEM_ENABLED_ADDR = 2; // adres w EEPROM dla stanu włączenia układu
// ----------- Zmienne stanu -----------
bool systemEnabled = true; // czy układ jest włączony (true) czy wyłączony (false)
bool initialSequenceDone = false;
// Flagi AUTO dla sekwencji po 12.5V (domyślnie false = brak automatycznych impulsów)
// autoGnd = true -> po 12.5V wyślij impuls GND (użytkownik kiedyś kliknął GND)
// autoPlus = true -> po 12.5V wyślij impuls +12V (użytkownik kiedyś kliknął +12V)
bool autoGnd = false;
bool autoPlus = false;
// przycisk GND
bool btnGndPrev = false;
unsigned long btnGndPressTime = 0;
bool btnGndToggleDone = false; // czy już przełączono podczas tego przytrzymania
// przycisk +12V
bool btn12Prev = false;
unsigned long btn12PressTime = 0;
bool btn12ToggleDone = false; // czy już przełączono podczas tego przytrzymania
// ----------- Funkcja pomiaru napięcia -----------
// UWAGA: Kondensator 100nF równolegle z R2 (między A0 a GND) działa jako filtr przeciwzakłóceniowy
// - Kondensator nie wpływa na pomiar napięcia DC (tylko filtruje zakłócenia AC)
// - Długie przewody GND mogą powodować błędy - używaj wspólnego punktu masy
// Podłączenie kondensatora: jeden pin do A0 (PIN_SENSE_12V), drugi pin do GND
float readBatteryVoltage() {
// Wykonaj kilka pomiarów i uśrednij (filtracja zakłóceń z długich przewodów)
const int SAMPLES = 3;
long sum = 0;
for (int i = 0; i < SAMPLES; i++) {
sum += analogRead(PIN_SENSE_12V);
delay(1); // krótka przerwa między pomiarami
}
int raw = sum / SAMPLES;
float Vout = (raw * VREF) / 1023.0;
float Vin = Vout * ((R1 + R2) / R2) * CAL;
return Vin;
}
// ----------- Funkcje EEPROM -----------
void saveDisableFlagsToEEPROM() {
// Zapisujemy flagi AUTO (po przekroczeniu 12.5V) do EEPROM
EEPROM.write(EEPROM_DISABLE_GND_ADDR, autoGnd ? 1 : 0);
EEPROM.write(EEPROM_DISABLE_PLUS_ADDR, autoPlus ? 1 : 0);
}
void loadDisableFlagsFromEEPROM() {
byte valueGnd = EEPROM.read(EEPROM_DISABLE_GND_ADDR);
byte valuePlus = EEPROM.read(EEPROM_DISABLE_PLUS_ADDR);
autoGnd = (valueGnd == 1);
autoPlus = (valuePlus == 1);
}
void saveSystemEnabledToEEPROM() {
EEPROM.write(EEPROM_SYSTEM_ENABLED_ADDR, systemEnabled ? 1 : 0);
}
void loadSystemEnabledFromEEPROM() {
byte value = EEPROM.read(EEPROM_SYSTEM_ENABLED_ADDR);
// Jeśli EEPROM jest pusty (255) lub ma wartość 0, domyślnie włączony
if (value == 255) {
systemEnabled = true; // domyślnie włączony przy pierwszym uruchomieniu
} else {
systemEnabled = (value == 1);
}
}
// ----------- Buzzer -----------
void beep(int count, unsigned long durationMs) {
// Funkcja do odtwarzania dźwięków buzzer (dla buzzer aktywnego)
for (int i = 0; i < count; i++) {
digitalWrite(PIN_BUZZER, HIGH); // włącz buzzera
delay(durationMs);
digitalWrite(PIN_BUZZER, LOW); // wyłącz buzzera
if (i < count - 1) { // przerwa między sygnałami (nie po ostatnim)
delay(100);
}
}
}
// ----------- Impulsy przekaźników -----------
void pulsePlus(unsigned long durationMs) {
digitalWrite(PIN_RELAY_PLUS, HIGH); // HIGH = P-MOSFET ON (impuls +12V)
delay(durationMs);
digitalWrite(PIN_RELAY_PLUS, LOW); // LOW = P-MOSFET OFF
}
void pulseGnd(unsigned long durationMs) {
digitalWrite(PIN_RELAY_GND, HIGH); // HIGH = MOSFET ON (impuls GND)
delay(durationMs);
digitalWrite(PIN_RELAY_GND, LOW); // LOW = MOSFET OFF
}
// ----------- SETUP -----------
void setup() {
// NAJPIERW: ustaw wyjścia na LOW, żeby P-MOSFET i N-MOSFET były OFF od samego startu
pinMode(PIN_RELAY_PLUS, OUTPUT);
pinMode(PIN_RELAY_GND, OUTPUT);
digitalWrite(PIN_RELAY_PLUS, LOW); // D2 LOW = BD139 OFF = Gate do +12V = P-MOSFET OFF
digitalWrite(PIN_RELAY_GND, LOW); // D3 LOW = N-MOSFET OFF
Serial.begin(9600);
delay(50); // krótka chwila na ustabilizowanie UART
pinMode(PIN_BTN_GND, INPUT_PULLUP); // przycisk zwierający do masy
pinMode(PIN_BTN_12, INPUT); // przycisk +12V przez dzielnik
pinMode(PIN_SENSE_12V, INPUT);
pinMode(PIN_BUZZER, OUTPUT);
digitalWrite(PIN_BUZZER, LOW); // wyłącz buzzera na starcie
// Odczytaj zapisane stany z EEPROM
loadDisableFlagsFromEEPROM();
loadSystemEnabledFromEEPROM();
Serial.println("=== START UKŁADU ===");
Serial.print("Odczytano z EEPROM - Układ: ");
Serial.print(systemEnabled ? "WŁĄCZONY" : "WYŁĄCZONY");
Serial.print(", AUTO GND przy 12.5V: ");
Serial.print(autoGnd ? "TAK" : "NIE");
Serial.print(", AUTO +12V przy 12.5V: ");
Serial.println(autoPlus ? "TAK" : "NIE");
Serial.println("===================");
}
// ----------- LOOP -----------
void loop() {
// --- 1. Pomiar napięcia instalacji 12V ---
float Vin = readBatteryVoltage();
// ZAWSZE wypisujemy aktualne napięcie
Serial.print("VIN(12V): ");
Serial.print(Vin, 2);
Serial.print(" V ");
// --- 2. Sekwencja startowa po przekroczeniu 12.5V (tylko raz po włączeniu) ---
// Uruchamia się tylko gdy układ jest włączony
if (systemEnabled && !initialSequenceDone && Vin >= THRESHOLD_V) {
Serial.print(" | Sekwencja START -> ");
bool printed = false;
// Impuls +12V (tylko jeśli użytkownik zapamiętał AUTO +12V)
if (autoPlus) {
Serial.print(PULSE_MS);
Serial.print("ms +12V");
printed = true;
pulsePlus(PULSE_MS);
}
// Impuls GND (tylko jeśli użytkownik zapamiętał AUTO GND)
if (autoGnd) {
if (printed) {
Serial.print(", ");
}
Serial.print(PULSE_MS);
Serial.print("ms GND");
pulseGnd(PULSE_MS);
}
Serial.println();
initialSequenceDone = true;
}
// --- 3. Odczyt przycisków ---
// Przycisk GND: aktywny gdy D4 = LOW
bool btnGndNow = (digitalRead(PIN_BTN_GND) == LOW);
// Przycisk +12V: aktywny gdy D5 = HIGH (dzielnik daje ~3-4V)
bool btn12Now = (digitalRead(PIN_BTN_12) == HIGH);
Serial.print(" | BTN_GND: ");
Serial.print(btnGndNow ? "LOW(active)" : "HIGH");
Serial.print(" | BTN_12V: ");
Serial.print(btn12Now ? "HIGH(active)" : "LOW");
Serial.print(" | UKŁAD: ");
Serial.print(systemEnabled ? "WŁ" : "WYŁ");
Serial.print(" | PAMIĘĆ: AUTO_GND@12.5V=");
Serial.print(autoGnd ? "TAK" : "NIE");
Serial.print(", AUTO_+12V@12.5V=");
Serial.print(autoPlus ? "TAK" : "NIE");
unsigned long now = millis();
// --- 4. Wykrywanie impulsu przycisku GND i wysterowanie przekaźnika GND o taki sam czas ---
// Działa tylko gdy układ jest włączony
// zbocze narastające: przycisk właśnie wciśnięty - zapisz czas startu i zresetuj flagę przełączenia
if (btnGndNow && !btnGndPrev) {
btnGndPressTime = now;
btnGndToggleDone = false; // nowe przytrzymanie - można przełączać
}
// Sprawdzanie długiego przytrzymania przycisku GND (10s) do wyłączenia/włączenia układu
if (btnGndNow && !btnGndToggleDone) {
unsigned long pressDuration = now - btnGndPressTime;
if (pressDuration >= TOGGLE_MS) {
// Przytrzymanie >= 10s - przełącz stan układu (tylko raz podczas tego przytrzymania)
systemEnabled = !systemEnabled;
Serial.print(" | UKŁAD: ");
Serial.println(systemEnabled ? "WŁĄCZONY" : "WYŁĄCZONY");
saveSystemEnabledToEEPROM(); // Zapisz do EEPROM
// Dźwięk: 1 dłuższy sygnał = włączony, 3 krótkie sygnały = wyłączony
if (systemEnabled) {
beep(1, 500); // 1 dłuższy sygnał = włączony
} else {
beep(3, 200); // 3 sygnały = wyłączony
}
btnGndToggleDone = true; // zapamiętaj, że już przełączyliśmy - nie przełączaj ponownie aż puszczony
}
}
// zbocze opadające: przycisk puszczony - zmierz czas i wyślij impuls o takiej samej długości
if (!btnGndNow && btnGndPrev) {
unsigned long impulseDuration = now - btnGndPressTime;
// Sprawdzamy tylko krótkie impulsy (nie 10s+ które służą do przełączania)
if (impulseDuration >= MIN_IMPULSE_MS && impulseDuration < TOGGLE_MS) {
if (systemEnabled) {
Serial.print(" | Impuls GND: ");
Serial.print(impulseDuration);
Serial.print(" ms -> wysterowanie GND ");
Serial.print(impulseDuration);
Serial.println(" ms");
pulseGnd(impulseDuration);
// Przełącz AUTO GND: pierwsze kliknięcie po starcie -> zapamiętaj AUTO,
// kolejne kliknięcie -> wróć do wariantu bez AUTO
autoGnd = !autoGnd;
Serial.print(" | ZAPAMIĘTANO: AUTO GND przy 12.5V = ");
Serial.println(autoGnd ? "WŁĄCZONE (po 12.5V wyślij GND)" : "WYŁĄCZONE (brak auto GND)");
saveDisableFlagsToEEPROM(); // Zapisz do EEPROM
} else {
Serial.println(" | Układ wyłączony - ignoruję impuls GND");
}
}
}
btnGndPrev = btnGndNow;
// --- 5. Wykrywanie impulsu przycisku +12V i wysterowanie przekaźnika +12V o taki sam czas ---
// Działa tylko gdy układ jest włączony
// zbocze narastające: przycisk właśnie wciśnięty - zapisz czas startu i zresetuj flagę przełączenia
if (btn12Now && !btn12Prev) {
btn12PressTime = now;
btn12ToggleDone = false; // nowe przytrzymanie - można przełączać
}
// Sprawdzanie długiego przytrzymania przycisku +12V (10s) do wyłączenia/włączenia układu
if (btn12Now && !btn12ToggleDone) {
unsigned long pressDuration = now - btn12PressTime;
if (pressDuration >= TOGGLE_MS) {
// Przytrzymanie >= 10s - przełącz stan układu (tylko raz podczas tego przytrzymania)
systemEnabled = !systemEnabled;
Serial.print(" | UKŁAD: ");
Serial.println(systemEnabled ? "WŁĄCZONY" : "WYŁĄCZONY");
saveSystemEnabledToEEPROM(); // Zapisz do EEPROM
// Dźwięk: 1 dłuższy sygnał = włączony, 3 krótkie sygnały = wyłączony
if (systemEnabled) {
beep(1, 500); // 1 dłuższy sygnał = włączony
} else {
beep(3, 200); // 3 sygnały = wyłączony
}
btn12ToggleDone = true; // zapamiętaj, że już przełączyliśmy - nie przełączaj ponownie aż puszczony
}
}
// zbocze opadające: przycisk puszczony - zmierz czas i wyślij impuls o takiej samej długości
if (!btn12Now && btn12Prev) {
unsigned long impulseDuration = now - btn12PressTime;
// Sprawdzamy tylko krótkie impulsy (nie 10s+ które służą do przełączania)
if (impulseDuration >= MIN_IMPULSE_MS && impulseDuration < TOGGLE_MS) {
if (systemEnabled) {
Serial.print(" | Impuls +12V: ");
Serial.print(impulseDuration);
Serial.print(" ms -> wysterowanie +12V ");
Serial.print(impulseDuration);
Serial.println(" ms");
pulsePlus(impulseDuration);
// Przełącz AUTO +12V: pierwsze kliknięcie po starcie -> zapamiętaj AUTO,
// kolejne kliknięcie -> wróć do wariantu bez AUTO
autoPlus = !autoPlus;
Serial.print(" | ZAPAMIĘTANO: AUTO +12V przy 12.5V = ");
Serial.println(autoPlus ? "WŁĄCZONE (po 12.5V wyślij +12V)" : "WYŁĄCZONE (brak auto +12V)");
saveDisableFlagsToEEPROM(); // Zapisz do EEPROM
} else {
Serial.println(" | Układ wyłączony - ignoruję impuls +12V");
}
}
}
btn12Prev = btn12Now;
// --- 6. Wymuszenie wyjść w stan spoczynku (D2=LOW → BD139 OFF → P-MOSFET OFF; D3=LOW → N-MOSFET OFF) ---
digitalWrite(PIN_RELAY_PLUS, LOW);
digitalWrite(PIN_RELAY_GND, LOW);
// --- 7. Koniec cyklu ---
Serial.println();
delay(LOOP_DELAY_MS);
}
Yes
When D2 is HIGH it should be 0.5V or less.
When D2 is LOW, it should be 12V
do you know how to fix it?
First, show the code you used to do the test when you measured the voltage.
What was connected to the drain when you did the test?
There appears to be an issue in the connection between the LM2596 regulator and the Nano (post #9)
I reverse these pins OUT- and OUT+ because there was a mistake in EasyEDA library for this regulator. In real 5V is connected with OUT+ and GND with OUT-.
my code:
#include <EEPROM.h>
// ----------- Konfiguracja sprzętu -----------
const int PIN_RELAY_PLUS = 2; // Przekaźnik impulsu +12V (IN1)
const int PIN_RELAY_GND = 3; // Przekaźnik impulsu GND (IN2)
const int PIN_BTN_GND = 4; // Przycisk do masy (GND z auta)
const int PIN_BTN_12 = 5; // Przycisk +12V (przez dzielnik 100k/47k + Zener)
const int PIN_SENSE_12V = A0; // Pomiar napięcia instalacji (dzielnik 100k/47k)
const int PIN_BUZZER = 6; // Buzzer aktywny (plus do pinu 6, minus do GND)
// UWAGA: Buzzer aktywny ma wbudowany generator dźwięku
// Podłączenie: Pin + buzzer do PIN_BUZZER (pin 6), Pin - buzzer do GND
// ----------- Parametry pomiaru napięcia -----------
const float R1 = 100000.0; // górny rezystor dzielnika (100k)
const float R2 = 47000.0; // dolny rezystor dzielnika (47k)
const float VREF = 5.0; // zasilanie Arduino z LM2596 (ref. ADC)
const float CAL = 1.051; // korekcja kalibracyjna (dostrojone: 13.7V rzeczywiste / 13.17V odczytane)
// UWAGA: Kondensator 100nF równolegle z R2 (między A0 a GND) jako filtr przeciwzakłóceniowy
const float THRESHOLD_V = 12.5; // próg wyzwolenia sekwencji startowej
// ----------- Czasy -----------
const unsigned long PULSE_MS = 500; // długość impulsu na przekaźniku (dla sekwencji startowej)
const unsigned long LOOP_DELAY_MS = 50; // odświeżanie pętli
const unsigned long MIN_IMPULSE_MS = 10; // minimalna długość impulsu do wykrycia (10ms)
const unsigned long TOGGLE_MS = 10000; // czas przytrzymania do wyłączenia/włączenia układu (10s)
// ----------- Pamięć EEPROM -----------
const int EEPROM_DISABLE_GND_ADDR = 0; // adres w EEPROM dla flagi AUTO GND
const int EEPROM_DISABLE_PLUS_ADDR = 1; // adres w EEPROM dla flagi AUTO +12V
const int EEPROM_SYSTEM_ENABLED_ADDR = 2; // adres w EEPROM dla stanu włączenia układu
// ----------- Zmienne stanu -----------
bool systemEnabled = true; // czy układ jest włączony (true) czy wyłączony (false)
bool initialSequenceDone = false;
// Flagi AUTO dla sekwencji po 12.5V (domyślnie false = brak automatycznych impulsów)
// autoGnd = true -> po 12.5V wyślij impuls GND (użytkownik kiedyś kliknął GND)
// autoPlus = true -> po 12.5V wyślij impuls +12V (użytkownik kiedyś kliknął +12V)
bool autoGnd = false;
bool autoPlus = false;
// przycisk GND
bool btnGndPrev = false;
unsigned long btnGndPressTime = 0;
bool btnGndToggleDone = false; // czy już przełączono podczas tego przytrzymania
// przycisk +12V
bool btn12Prev = false;
unsigned long btn12PressTime = 0;
bool btn12ToggleDone = false; // czy już przełączono podczas tego przytrzymania
// ----------- Funkcja pomiaru napięcia -----------
// UWAGA: Kondensator 100nF równolegle z R2 (między A0 a GND) działa jako filtr przeciwzakłóceniowy
// - Kondensator nie wpływa na pomiar napięcia DC (tylko filtruje zakłócenia AC)
// - Długie przewody GND mogą powodować błędy - używaj wspólnego punktu masy
// Podłączenie kondensatora: jeden pin do A0 (PIN_SENSE_12V), drugi pin do GND
float readBatteryVoltage() {
// Wykonaj kilka pomiarów i uśrednij (filtracja zakłóceń z długich przewodów)
const int SAMPLES = 3;
long sum = 0;
for (int i = 0; i < SAMPLES; i++) {
sum += analogRead(PIN_SENSE_12V);
delay(1); // krótka przerwa między pomiarami
}
int raw = sum / SAMPLES;
float Vout = (raw * VREF) / 1023.0;
float Vin = Vout * ((R1 + R2) / R2) * CAL;
return Vin;
}
// ----------- Funkcje EEPROM -----------
void saveDisableFlagsToEEPROM() {
// Zapisujemy flagi AUTO (po przekroczeniu 12.5V) do EEPROM
EEPROM.write(EEPROM_DISABLE_GND_ADDR, autoGnd ? 1 : 0);
EEPROM.write(EEPROM_DISABLE_PLUS_ADDR, autoPlus ? 1 : 0);
}
void loadDisableFlagsFromEEPROM() {
byte valueGnd = EEPROM.read(EEPROM_DISABLE_GND_ADDR);
byte valuePlus = EEPROM.read(EEPROM_DISABLE_PLUS_ADDR);
autoGnd = (valueGnd == 1);
autoPlus = (valuePlus == 1);
}
void saveSystemEnabledToEEPROM() {
EEPROM.write(EEPROM_SYSTEM_ENABLED_ADDR, systemEnabled ? 1 : 0);
}
void loadSystemEnabledFromEEPROM() {
byte value = EEPROM.read(EEPROM_SYSTEM_ENABLED_ADDR);
// Jeśli EEPROM jest pusty (255) lub ma wartość 0, domyślnie włączony
if (value == 255) {
systemEnabled = true; // domyślnie włączony przy pierwszym uruchomieniu
} else {
systemEnabled = (value == 1);
}
}
// ----------- Buzzer -----------
void beep(int count, unsigned long durationMs) {
// Funkcja do odtwarzania dźwięków buzzer (dla buzzer aktywnego)
for (int i = 0; i < count; i++) {
digitalWrite(PIN_BUZZER, HIGH); // włącz buzzera
delay(durationMs);
digitalWrite(PIN_BUZZER, LOW); // wyłącz buzzera
if (i < count - 1) { // przerwa między sygnałami (nie po ostatnim)
delay(100);
}
}
}
// ----------- Impulsy przekaźników -----------
void pulsePlus(unsigned long durationMs) {
digitalWrite(PIN_RELAY_PLUS, HIGH); // HIGH = P-MOSFET ON (impuls +12V)
delay(durationMs);
digitalWrite(PIN_RELAY_PLUS, LOW); // LOW = P-MOSFET OFF
}
void pulseGnd(unsigned long durationMs) {
digitalWrite(PIN_RELAY_GND, HIGH); // HIGH = MOSFET ON (impuls GND)
delay(durationMs);
digitalWrite(PIN_RELAY_GND, LOW); // LOW = MOSFET OFF
}
// ----------- SETUP -----------
void setup() {
// NAJPIERW: ustaw wyjścia na LOW, żeby P-MOSFET i N-MOSFET były OFF od samego startu
pinMode(PIN_RELAY_PLUS, OUTPUT);
pinMode(PIN_RELAY_GND, OUTPUT);
digitalWrite(PIN_RELAY_PLUS, LOW); // D2 LOW = BD139 OFF = Gate do +12V = P-MOSFET OFF
digitalWrite(PIN_RELAY_GND, LOW); // D3 LOW = N-MOSFET OFF
Serial.begin(9600);
delay(50); // krótka chwila na ustabilizowanie UART
pinMode(PIN_BTN_GND, INPUT_PULLUP); // przycisk zwierający do masy
pinMode(PIN_BTN_12, INPUT); // przycisk +12V przez dzielnik
pinMode(PIN_SENSE_12V, INPUT);
pinMode(PIN_BUZZER, OUTPUT);
digitalWrite(PIN_BUZZER, LOW); // wyłącz buzzera na starcie
// Odczytaj zapisane stany z EEPROM
loadDisableFlagsFromEEPROM();
loadSystemEnabledFromEEPROM();
Serial.println("=== START UKŁADU ===");
Serial.print("Odczytano z EEPROM - Układ: ");
Serial.print(systemEnabled ? "WŁĄCZONY" : "WYŁĄCZONY");
Serial.print(", AUTO GND przy 12.5V: ");
Serial.print(autoGnd ? "TAK" : "NIE");
Serial.print(", AUTO +12V przy 12.5V: ");
Serial.println(autoPlus ? "TAK" : "NIE");
Serial.println("===================");
}
// ----------- LOOP -----------
void loop() {
// --- 1. Pomiar napięcia instalacji 12V ---
float Vin = readBatteryVoltage();
// ZAWSZE wypisujemy aktualne napięcie
Serial.print("VIN(12V): ");
Serial.print(Vin, 2);
Serial.print(" V ");
// --- 2. Sekwencja startowa po przekroczeniu 12.5V (tylko raz po włączeniu) ---
// Uruchamia się tylko gdy układ jest włączony
if (systemEnabled && !initialSequenceDone && Vin >= THRESHOLD_V) {
Serial.print(" | Sekwencja START -> ");
bool printed = false;
// Impuls +12V (tylko jeśli użytkownik zapamiętał AUTO +12V)
if (autoPlus) {
Serial.print(PULSE_MS);
Serial.print("ms +12V");
printed = true;
pulsePlus(PULSE_MS);
}
// Impuls GND (tylko jeśli użytkownik zapamiętał AUTO GND)
if (autoGnd) {
if (printed) {
Serial.print(", ");
}
Serial.print(PULSE_MS);
Serial.print("ms GND");
pulseGnd(PULSE_MS);
}
Serial.println();
initialSequenceDone = true;
}
// --- 3. Odczyt przycisków ---
// Przycisk GND: aktywny gdy D4 = LOW
bool btnGndNow = (digitalRead(PIN_BTN_GND) == LOW);
// Przycisk +12V: aktywny gdy D5 = HIGH (dzielnik daje ~3-4V)
bool btn12Now = (digitalRead(PIN_BTN_12) == HIGH);
Serial.print(" | BTN_GND: ");
Serial.print(btnGndNow ? "LOW(active)" : "HIGH");
Serial.print(" | BTN_12V: ");
Serial.print(btn12Now ? "HIGH(active)" : "LOW");
Serial.print(" | UKŁAD: ");
Serial.print(systemEnabled ? "WŁ" : "WYŁ");
Serial.print(" | PAMIĘĆ: AUTO_GND@12.5V=");
Serial.print(autoGnd ? "TAK" : "NIE");
Serial.print(", AUTO_+12V@12.5V=");
Serial.print(autoPlus ? "TAK" : "NIE");
unsigned long now = millis();
// --- 4. Wykrywanie impulsu przycisku GND i wysterowanie przekaźnika GND o taki sam czas ---
// Działa tylko gdy układ jest włączony
// zbocze narastające: przycisk właśnie wciśnięty - zapisz czas startu i zresetuj flagę przełączenia
if (btnGndNow && !btnGndPrev) {
btnGndPressTime = now;
btnGndToggleDone = false; // nowe przytrzymanie - można przełączać
}
// Sprawdzanie długiego przytrzymania przycisku GND (10s) do wyłączenia/włączenia układu
if (btnGndNow && !btnGndToggleDone) {
unsigned long pressDuration = now - btnGndPressTime;
if (pressDuration >= TOGGLE_MS) {
// Przytrzymanie >= 10s - przełącz stan układu (tylko raz podczas tego przytrzymania)
systemEnabled = !systemEnabled;
Serial.print(" | UKŁAD: ");
Serial.println(systemEnabled ? "WŁĄCZONY" : "WYŁĄCZONY");
saveSystemEnabledToEEPROM(); // Zapisz do EEPROM
// Dźwięk: 1 dłuższy sygnał = włączony, 3 krótkie sygnały = wyłączony
if (systemEnabled) {
beep(1, 500); // 1 dłuższy sygnał = włączony
} else {
beep(3, 200); // 3 sygnały = wyłączony
}
btnGndToggleDone = true; // zapamiętaj, że już przełączyliśmy - nie przełączaj ponownie aż puszczony
}
}
// zbocze opadające: przycisk puszczony - zmierz czas i wyślij impuls o takiej samej długości
if (!btnGndNow && btnGndPrev) {
unsigned long impulseDuration = now - btnGndPressTime;
// Sprawdzamy tylko krótkie impulsy (nie 10s+ które służą do przełączania)
if (impulseDuration >= MIN_IMPULSE_MS && impulseDuration < TOGGLE_MS) {
if (systemEnabled) {
Serial.print(" | Impuls GND: ");
Serial.print(impulseDuration);
Serial.print(" ms -> wysterowanie GND ");
Serial.print(impulseDuration);
Serial.println(" ms");
pulseGnd(impulseDuration);
// Przełącz AUTO GND: pierwsze kliknięcie po starcie -> zapamiętaj AUTO,
// kolejne kliknięcie -> wróć do wariantu bez AUTO
autoGnd = !autoGnd;
Serial.print(" | ZAPAMIĘTANO: AUTO GND przy 12.5V = ");
Serial.println(autoGnd ? "WŁĄCZONE (po 12.5V wyślij GND)" : "WYŁĄCZONE (brak auto GND)");
saveDisableFlagsToEEPROM(); // Zapisz do EEPROM
} else {
Serial.println(" | Układ wyłączony - ignoruję impuls GND");
}
}
}
btnGndPrev = btnGndNow;
// --- 5. Wykrywanie impulsu przycisku +12V i wysterowanie przekaźnika +12V o taki sam czas ---
// Działa tylko gdy układ jest włączony
// zbocze narastające: przycisk właśnie wciśnięty - zapisz czas startu i zresetuj flagę przełączenia
if (btn12Now && !btn12Prev) {
btn12PressTime = now;
btn12ToggleDone = false; // nowe przytrzymanie - można przełączać
}
// Sprawdzanie długiego przytrzymania przycisku +12V (10s) do wyłączenia/włączenia układu
if (btn12Now && !btn12ToggleDone) {
unsigned long pressDuration = now - btn12PressTime;
if (pressDuration >= TOGGLE_MS) {
// Przytrzymanie >= 10s - przełącz stan układu (tylko raz podczas tego przytrzymania)
systemEnabled = !systemEnabled;
Serial.print(" | UKŁAD: ");
Serial.println(systemEnabled ? "WŁĄCZONY" : "WYŁĄCZONY");
saveSystemEnabledToEEPROM(); // Zapisz do EEPROM
// Dźwięk: 1 dłuższy sygnał = włączony, 3 krótkie sygnały = wyłączony
if (systemEnabled) {
beep(1, 500); // 1 dłuższy sygnał = włączony
} else {
beep(3, 200); // 3 sygnały = wyłączony
}
btn12ToggleDone = true; // zapamiętaj, że już przełączyliśmy - nie przełączaj ponownie aż puszczony
}
}
// zbocze opadające: przycisk puszczony - zmierz czas i wyślij impuls o takiej samej długości
if (!btn12Now && btn12Prev) {
unsigned long impulseDuration = now - btn12PressTime;
// Sprawdzamy tylko krótkie impulsy (nie 10s+ które służą do przełączania)
if (impulseDuration >= MIN_IMPULSE_MS && impulseDuration < TOGGLE_MS) {
if (systemEnabled) {
Serial.print(" | Impuls +12V: ");
Serial.print(impulseDuration);
Serial.print(" ms -> wysterowanie +12V ");
Serial.print(impulseDuration);
Serial.println(" ms");
pulsePlus(impulseDuration);
// Przełącz AUTO +12V: pierwsze kliknięcie po starcie -> zapamiętaj AUTO,
// kolejne kliknięcie -> wróć do wariantu bez AUTO
autoPlus = !autoPlus;
Serial.print(" | ZAPAMIĘTANO: AUTO +12V przy 12.5V = ");
Serial.println(autoPlus ? "WŁĄCZONE (po 12.5V wyślij +12V)" : "WYŁĄCZONE (brak auto +12V)");
saveDisableFlagsToEEPROM(); // Zapisz do EEPROM
} else {
Serial.println(" | Układ wyłączony - ignoruję impuls +12V");
}
}
}
btn12Prev = btn12Now;
// --- 6. Wymuszenie wyjść w stan spoczynku (D2=LOW → BD139 OFF → P-MOSFET OFF; D3=LOW → N-MOSFET OFF) ---
digitalWrite(PIN_RELAY_PLUS, LOW);
digitalWrite(PIN_RELAY_GND, LOW);
// --- 7. Koniec cyklu ---
Serial.println();
delay(LOOP_DELAY_MS);
}
| Event | What Arduino detects | Effect |
|---|---|---|
| +12V button click (D5) | Falling edge, hold time 10 ms–10 s | pulsePlus(duration) → D2 HIGH for that time |
| Start sequence (after voltage ≥ 12.5 V) | autoPlus == true | pulsePlus(500) → D2 HIGH for 500 ms |
so D2 (P-MOSFET) is driven only when the +12V button (D5) is clicked or when the start sequence with autoPlus runs.