#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Pin definīcijas
const int startButton = 2;
const int modePinSweep = 3;
const int modePinPhase = 4;
const int btnUp = 5;
const int btnDown = 6;
const int modeAudioPin = 7; // Audio režīma slēdzis (5V = Ieslēgts)
const int potPin = A0; // Manuālais potenciometrs frekvencei
const int batteryPin = A1; // Akumulatora sprieguma mērīšana
const int audioPin = A2; // MCP6002 audio ieeja (2.5V viduspunkts)
const int contactPin = A3; // Kontakta kontrole ar ādu (100mV slieksnis)
const int zapperOut = 9; // Timer1 OC1A izeja uz CD4093 un MOSFET
const int buzzerLed = 10; // Pīkstulis un LED indikācija
// Projekta parametri
int mode = 1;
bool isRunning = false;
unsigned long startTime;
const unsigned long totalTimer = 420000; // 7 minūtes
const unsigned long sweepCycle = 120000; // 2 minūtes
const unsigned long phaseInterval = 2000;
// Mainīgie
float batteryVoltage = 0.0;
unsigned long lastLcdUpdate = 0;
bool phaseInverted = false;
unsigned long lastPhaseFlip = 0;
float currentDuty = 0.5;
long fineTuneOffset = 0;
int lastPotVal = 0;
unsigned long btnPressTime = 0;
int stepSize = 1;
// Audio un kontakta papildus mainīgie
unsigned long lastBuzzerMillis = 0;
bool contactOk = true;
void setup() {
pinMode(startButton, INPUT);
pinMode(modePinSweep, INPUT);
pinMode(modePinPhase, INPUT);
pinMode(modeAudioPin, INPUT);
pinMode(btnUp, INPUT);
pinMode(btnDown, INPUT);
pinMode(zapperOut, OUTPUT);
pinMode(buzzerLed, OUTPUT);
digitalWrite(zapperOut, LOW);
TCCR1A = 0;
TCCR1B = 0;
lcd.init();
lcd.backlight();
lcd.print("ZAPPER V10.0 PWM");
delay(1000);
lcd.clear();
}
void setHardwareSignal(float frequency, float duty, bool inverted) {
if (frequency < 10) frequency = 10;
unsigned long topValue = (16000000UL / (1 * (unsigned long)frequency)) - 1;
if (topValue > 65535) topValue = 65535;
ICR1 = topValue;
OCR1A = (unsigned int)(topValue * duty);
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
if (inverted) {
TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11);
} else {
TCCR1A = _BV(COM1A1) | _BV(WGM11);
}
}
void stopHardwareSignal() {
TCCR1A = 0;
TCCR1B = 0;
digitalWrite(zapperOut, LOW);
}
void updateBattery() {
int raw = analogRead(batteryPin);
batteryVoltage = (raw / 1023.0) * 5.0 * 2.0;
}
void readMode() {
// Ja uz D7 ir 5V, piespiedu kārtā ieslēdzam AUDIO režīmu (Mode 5)
if (digitalRead(modeAudioPin) == HIGH) {
mode = 5;
return;
}
bool s1 = digitalRead(modePinSweep);
bool s2 = digitalRead(modePinPhase);
if (s1 && s2) mode = 4;
else if (s1) mode = 2;
else if (s2) mode = 3;
else mode = 1;
}
void handleFineTune() {
bool up = digitalRead(btnUp);
bool down = digitalRead(btnDown);
if (up || down) {
if (btnPressTime == 0) btnPressTime = millis();
unsigned long duration = millis() - btnPressTime;
if (duration > 3000) stepSize = 100;
else if (duration > 1000) stepSize = 10;
else stepSize = 1;
if (up) fineTuneOffset += stepSize;
if (down) fineTuneOffset -= stepSize;
delay(100);
} else {
btnPressTime = 0;
stepSize = 1;
}
}
void stopZapper() {
isRunning = false;
stopHardwareSignal();
digitalWrite(buzzerLed, LOW);
lcd.clear();
lcd.print(" CYCLE FINISHED ");
digitalWrite(buzzerLed, HIGH); delay(1000); digitalWrite(buzzerLed, LOW);
delay(1000);
lcd.clear();
}
void startZapper() {
lcd.clear();
isRunning = true;
startTime = millis();
lastPhaseFlip = millis();
lastBuzzerMillis = millis();
digitalWrite(buzzerLed, HIGH); delay(200); digitalWrite(buzzerLed, LOW);
}
void runZapper() {
unsigned long currentTime = millis();
unsigned long elapsed = currentTime - startTime;
if (elapsed >= totalTimer) { stopZapper(); return; }
if (elapsed > 1000 && digitalRead(startButton) == HIGH) { stopZapper(); delay(500); return; }
readMode();
// PĀRBAUDĀM KONTAKTU UZ A3 (20 atbilst ~100mV slieksnim)
int contactVal = analogRead(contactPin);
if (contactVal >= 20) {
contactOk = true;
} else {
contactOk = false;
}
// Ja kontakta nav, signālu atslēdzam un reizi sekundē pīkstam
if (!contactOk) {
stopHardwareSignal();
if (currentTime - lastBuzzerMillis >= 1000) {
lastBuzzerMillis = currentTime;
digitalWrite(buzzerLed, HIGH); delay(50); digitalWrite(buzzerLed, LOW);
}
if (currentTime - lastLcdUpdate > 300) {
lastLcdUpdate = currentTime;
lcd.setCursor(0, 0); lcd.print("NO CONTACT! ");
lcd.setCursor(0, 1); lcd.print("CHECK ELECTRODES");
}
return;
}
// Ja kontakts ir, lasām potenciometru pārējiem režīmiem
int potVal = analogRead(potPin);
if (abs(potVal - lastPotVal) > 12 && mode != 5) { fineTuneOffset = 0; lastPotVal = potVal; }
if (mode != 2 && mode != 5) handleFineTune();
float freq;
if (mode == 5) {
// AUDIO REŽĪMS: Fiksēta 33.33 kHz nesošā frekvence
freq = 33333.33;
// Lasām audio signālu no pareizās ieejas - A2
int audioVal = analogRead(audioPin);
// PWM modulācija ap 2.5V viduspunktu (ADC vērtība ~512)
float audioSignal = (audioVal - 512) / 512.0;
currentDuty = 0.5 + (audioSignal * 0.4); // Modulācijas dziļums (10% līdz 90%)
phaseInverted = false;
}
else if (mode == 2) {
unsigned long sweepMillis = currentTime % sweepCycle;
float sweepPos = (sweepMillis < (sweepCycle / 2)) ?
((float)sweepMillis / (sweepCycle / 2.0)) :
(1.0 - ((float)(sweepMillis - (sweepCycle / 2.0)) / (sweepCycle / 2.0)));
freq = 10.0 + (39990.0 * (sweepPos * sweepPos));
currentDuty = 0.5;
phaseInverted = false;
}
else {
float normPot = potVal / 1023.0;
freq = 14.0 + (39986.0 * (normPot * normPot)) + (float)fineTuneOffset;
if (mode == 3) {
if (currentTime - lastPhaseFlip >= phaseInterval) {
phaseInverted = !phaseInverted;
lastPhaseFlip = currentTime;
}
currentDuty = 0.5;
}
else if (mode == 4) {
unsigned long dcMillis = currentTime % 4000;
if (dcMillis < 2000) currentDuty = 0.1 + (0.8 * (dcMillis / 2000.0));
else currentDuty = 0.9 - (0.8 * ((dcMillis - 2000) / 2000.0));
phaseInverted = false;
} else {
currentDuty = 0.5;
phaseInverted = false;
}
}
// Padedzam signālu uz taimeri (izeja D9)
setHardwareSignal(freq, currentDuty, phaseInverted);
// LCD informācijas atjaunošana darbības laikā
if (currentTime - lastLcdUpdate > 300) {
lastLcdUpdate = currentTime;
updateBattery();
lcd.setCursor(0, 0);
switch(mode) {
case 1: lcd.print("MANUAL "); break;
case 2: lcd.print("SWEEP "); break;
case 3: lcd.print("PHASE180 "); break;
case 4: lcd.print("DUTY MOD "); break;
case 5: lcd.print("AUDIO PWM"); break;
}
unsigned long rem = (totalTimer - elapsed) / 1000;
lcd.setCursor(11, 0);
lcd.print(rem/60); lcd.print(":");
if(rem%60 < 10) lcd.print("0"); lcd.print(rem%60);
lcd.setCursor(0, 1);
if (mode == 5) {
lcd.print("33.33kHz MOD ");
} else {
if (freq >= 1000) { lcd.print(freq/1000.0, 2); lcd.print("kHz "); }
else { lcd.print((int)freq); lcd.print("Hz "); }
}
lcd.setCursor(11, 1);
lcd.print(batteryVoltage, 1); lcd.print("V ");
}
}
void loop() {
if (!isRunning) {
updateBattery();
readMode();
if (mode != 5) handleFineTune();
lcd.setCursor(0, 0);
lcd.print("READY: ");
switch(mode) {
case 1: lcd.print("MANUAL "); break;
case 2: lcd.print("SWEEP "); break;
case 3: lcd.print("PHASE "); break;
case 4: lcd.print("DUTY CYC "); break; // Salabots šeit (pielikts break un sakārtotas iekavas)
case 5: lcd.print("AUDIO PWM"); break;
}
lcd.setCursor(0, 1);
lcd.print("BAT:"); lcd.print(batteryVoltage, 1); lcd.print("V START? ");
if (digitalRead(startButton) == HIGH && batteryVoltage >= 3.2) {
startZapper();
delay(300);
}
} else {
runZapper();
}
}Frekv+
ZAPPER sign
PWModulacion
(click to edit)
Frekv-
START
Frekvencies
Bat contr.