Проверялось на (заточено на) Daewoo Nexia N150, но должно работать на любой машине с электронным спидометром (датчик скорости — 6 импульсов на метр, вроде как стандарт). Фотографии немного мутные (любительские):
а) мужским
б) женским
Голоса синтезированы на компьютере, записаны в виде набора mp3-файлов на микроСД карту. Это значит, что вы можете их поменять или записать.
2. Настройки выполняются с ПДУ от телевизора (или любого другого с достаточным количеством кнопок, настоятельно рекомендую ПДУ с кнопками 0-9). Настройки запоминаются в момент изменения.
3. В случае отказа/потери ПДУ, извещатель может быть оперативно переключен на режимы «нет звуков» или «нет звуков, кроме ручника». Для этого используется тройное включение габаритов (идея использовать мигание габаритами в качестве управляющего сигнала для настройки спёрта с какого-то устройства регулировки яркости ДХО).
— Включен дальний свет (мигание дальним игнорируется, предупреждает один раз после включения, далее не напоминает, пока дальний не переключат)
— Включите ходовые огни (если начато движение без включенных габаритов, у меня ДХО и ближний не работают, если не включены габариты).
— Напряжение бортовой сети (точность до десятой доли вольта)
— Превышение порога скорости 40, 50,… 120, 130 км/ч.
— Понижение порога скорости 40, 50,… 120, 130 км/ч.
— Изменение громкости, переключение голоса, отключение/включение каждого из озвучиваемых событий (включение вольтметра вызывает одновременно озвучивание напряжения).
Видео с демонтрацией:
2. К лампочкам — ручника, дальнего света, подсветки приборов (габариты).
Согласование уровней сделано довольно просто — выводы ардуины подтянуты внутренним резистором в «1», а сигналы 12В уровня из приборной панели идут через диоды. Когда с панели идет +12, диод закрыт — на ардуине «лог.1». Когда сигнал с панели идет землёй — диод открыт, внутренний подтягивающий резистор игнорируется, на выводе ардуино «лог.0».
Вольтметр — просто резистивный делитель на аналоговый вход. Отношение примерно 1:13, из того расчета, что при максимальном напряжении бортовой сети 16В (аварийный режим) АЦП достигнет своего предела при опорном сигнале 1,2В.
2. Модуль mp3 — DFplayer mini
Данный модуль в интернет-схемах подключается по tx/rx сигналам, я добавил анализ сигнала busy, для поимки момента окончания воспроизведения звука, чтоб новое оповещение не перебивало текущее, а вставало в очередь.
3. Усилитель PAM8403 (необязательный элемент)
4. Макетная плата, 5 резисторов (2 на АЦП вольтметра, и 3 на выводы DFplayer), 4 диода (согласование с +12В), а также пара конденсаторов и микросхема стабилизатора питания +5В типа LM7805 (у меня стоит DC/DC преобразователь AMSR 7805, потому что был в запасе и не греется), пъезозуммер (пищит при переполнении очереди мр3-файлов, больше для поиска ошибок при отладке), разъемы для подключения ИК-датчика (джек 2.5 в моем случае, но это непринципиально) и динамика (я взял RCA), ну и разъем для панели приборов (я взял IDC10, с защелками на папе — достаточно легкий и многоконтактный)
#include <Wire.h>
//#include <LiquidCrystal_I2C.h>
#include <IRremote.h>
#include <EEPROM.h>
#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>
int RECV_PIN = 6; //пин подключения IR приёмника
IRrecv irrecv(RECV_PIN);
decode_results results;
byte cfg[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
byte mp3stek[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte mp3stekpos = 0;
volatile byte busy = 1; //mp3 busy 0=play
volatile byte softbusy = 0;
volatile byte nomer_mp3 = 1;
volatile unsigned long micros_sp = 0;
volatile byte sz = 0; //счетчик обнуления
volatile unsigned int sp = 0; //скорость
volatile unsigned int sp20 = 0; //скорость*10
volatile boolean st = false; //триггер
volatile byte ruka = 1; //ручник
volatile byte dsvet = 0; //д.свет
volatile byte gaba = 0; //габариты
volatile byte lastspeed = 0; //последняя скорость
volatile byte lastdsvet = 0; //переменная для отсчета д.света
volatile byte lastgaba = 0; //переменная для отсчета DHO
volatile byte lastgabaonoff = 0; //переменная для отсчета щелчкоф габаритов
volatile word gabaonofftimer = 0; //переменная для отсчета времени щелчкоф габаритов
volatile byte gabaonoffcounter = 0; //переменная для отсчета времени щелчкоф габаритов
volatile byte speed40 = 38; // 40
volatile byte speed60 = 58; // 60
volatile byte speed80 = 78; // 80
volatile byte speed110 = 108; // 110
volatile byte unspeed40 = 36; // no 40
volatile byte unspeed60 = 56; // no 60
volatile byte unspeed80 = 76; // no 80
volatile byte unspeed110 = 106; // no 110
volatile byte speed50 = 48; // 50
volatile byte unspeed50 = 46; // no 50
volatile byte speed70 = 68; // 70
volatile byte unspeed70 = 66; // no 70
volatile byte speed90 = 88; // 90
volatile byte unspeed90 = 86; // no 90
volatile byte speed100 = 98; // 100
volatile byte unspeed100 = 96; // no 100
volatile byte speed120 = 118; // 120
volatile byte unspeed120 = 116; // no 120
volatile byte speed130 = 128; // 130
volatile byte unspeed130 = 126; // no 130
volatile byte s40 = 0;
volatile byte s50 = 0;
volatile byte s60 = 0;
volatile byte s70 = 0;
volatile byte s80 = 0;
volatile byte s90 = 0;
volatile byte s100 = 0;
volatile byte s110 = 0;
volatile byte s120 = 0;
volatile byte s130 = 0;
//LiquidCrystal_I2C lcd(0x3F, 16, 2);
float sensorValue = 0; //V
float outputValue = 0; //V
void setup()
{
Serial.begin(9600);
Serial.println("start programm NEXIA 1.0");
//start IR reciver
irrecv.enableIRIn(); // Start the receiver
// initialize the LCD
//lcd.begin();
// Turn on the blacklight and print a message.
//lcd.backlight();
// lcd.print("Hello, world!");
//tone (17,3000); //тестовый сигнал на выводе D3
pinMode(2, INPUT); // пин будет работать на вход speed
digitalWrite(2, HIGH);//подключаем подтягивающий резистор
pinMode(3, INPUT); // пин будет работать на вход
digitalWrite(3, HIGH);//подключаем подтягивающий резистор
pinMode(4, INPUT); // пин будет работать на вход
digitalWrite(4, HIGH);//подключаем подтягивающий резистор
pinMode(5, INPUT); // пин будет работать на вход
digitalWrite(5, HIGH);//подключаем подтягивающий резистор
// pinMode(13, OUTPUT); //
lastgabaonoff = digitalRead(5); //gaba
attachInterrupt(0,speedometr, RISING);
cfg[0]=EEPROM.read(5); //0=all sound 1=no sound(ruka) 2=no sound all
cfg[1]=EEPROM.read(6); //volume mp3 0..30
cfg[2]=EEPROM.read(7); //0 = dsvet sound? 1 = no dsvet sound
cfg[3]=EEPROM.read(8); //0 = 40sound
cfg[4]=EEPROM.read(9); //0 = 60sound
cfg[5]=EEPROM.read(10);//0 = 80sound
cfg[6]=EEPROM.read(11);//0 = 110 sound
cfg[7]=EEPROM.read(12);//0 = Voltmetr sound
cfg[8]=EEPROM.read(13);//0 = DHO sound
cfg[9]=EEPROM.read(14);//0 = 50sound
cfg[10]=EEPROM.read(15);//0 = 70sound
cfg[11]=EEPROM.read(16);//0 = 90sound
cfg[12]=EEPROM.read(17);//0 = 100sound
cfg[13]=EEPROM.read(18);//0 = 120sound
cfg[14]=EEPROM.read(19);//0 = 130sound
cfg[15]=EEPROM.read(20);//0 = голос0, 1=голос1
//управление мр3
pinMode(7, INPUT); //busy
mp3_set_serial (Serial);
// mp3_set_volume (25);
mp3setvol();
delay (100);
add_mp3(32); //включен голосовой режим
// Вольтметр
analogReference (INTERNAL);
// voltmeter();
if (cfg[7]==0){voltmetertest();} // вольтметр
}
void loop()
{
//индикация режимов датчиков
dsvet = digitalRead(3); // Получить состояние пина :
// if (dsvet==1) { lcd.setCursor(3, 0); lcd.print("DD ");}
// else{lcd.setCursor(3, 0); lcd.print("_s ");};
ruka = digitalRead(4); // Получить состояние пина :
// if (ruka==1) { lcd.setCursor(0, 0); lcd.print("_r ");}
// else{lcd.setCursor(0, 0); lcd.print("RR ");};
gaba = digitalRead(5); // Получить состояние пина :
// if (gaba==1) { lcd.setCursor(6, 0); lcd.print("GG");}
// else{lcd.setCursor(6, 0); lcd.print("_g");};
//voltmetertest(); //тест вольтметра
// digitalWrite(13, !digitalRead(2));
//измерение скорости
// lcd.setCursor(10, 0);
// lcd.print(" ");
// lcd.setCursor(10, 0);
// lcd.print(sp);
// lcd.setCursor(0, 1);
// lcd.print(" ");
// lcd.setCursor(0, 1);
// lcd.print(sp20);
if (sz != 0){sz--;}else{sp20=0;sp=0;};
delay(50);
// sdisplay();
//действия
gabamute(); //управление звуком по тройному щелчку габаритами
if ((sp20>0)&(ruka==0)) {rukabeep();}//пищит ручник
else
{ //обрабатываем д.свет и скорость только если не пищит ручник
if (dsvet==1) { if ( lastdsvet<200){lastdsvet=lastdsvet+1;};}
if (dsvet==1) { if ((lastdsvet>35)&(lastdsvet<38)){svetbeep();}; }
if (dsvet==0) {lastdsvet=0;};
//конец обработки д. света
//предупреждение о дхо
if ((gaba==0)&&(sp20>0)) { if ( lastgaba<150){lastgaba=lastgaba+1;};}
if ((gaba==0)&&(sp20>0)) { if ((lastgaba>20)&(lastgaba<23)){DHO_beep();}; }
if (gaba==1) {lastgaba=0;};
if (sp20==0) {lastgaba=0;};
//обрабатываем контроль превышения скорости 40, 60, 80, 110
if ((lastspeed<speed40)&(sp>=speed40)) {
if (s40<1) { svet1beep(); s40=1; }};
if ((lastspeed>=unspeed40)&(sp<unspeed40)) {
if (s40>0) { nsvet1beep(); s40=0; }};
if ((lastspeed<speed50)&(sp>=speed50)) {
if (s50<1) { svet50beep(); s50=1; }};
if ((lastspeed>=unspeed50)&(sp<unspeed50)) {
if (s50>0) { nsvet50beep(); s50=0; }};
if ((lastspeed<speed60)&(sp>=speed60)) {
if (s60<1) { svet2beep(); s60=1; }};
if ((lastspeed>=unspeed60)&(sp<unspeed60)) {
if (s60>0) { nsvet2beep(); s60=0; }};
if ((lastspeed<speed70)&(sp>=speed70)) {
if (s70<1) { svet70beep(); s70=1; }};
if ((lastspeed>=unspeed70)&(sp<unspeed70)) {
if (s70>0) { nsvet70beep(); s70=0; }}; //костыль. иначе на 66км/ч без конца твердит "нет 70"почему - непонятно. поставил костыли на все скорости.
if ((lastspeed<speed80)&(sp>=speed80)) {
if (s80<1) { svet3beep(); s80=1; }};
if ((lastspeed>=unspeed80)&(sp<unspeed80)) {
if (s80>0) { nsvet3beep(); s80=0; }};
if ((lastspeed<speed90)&(sp>=speed90)) {
if (s90<1) { svet90beep(); s90=1; }};
if ((lastspeed>=unspeed90)&(sp<unspeed90)) {
if (s90>0) { nsvet90beep(); s90=0; }};
if ((lastspeed<speed100)&(sp>=speed100)) {
if (s100<1) { svet100beep(); s100=1; }};
if ((lastspeed>=unspeed100)&(sp<unspeed100)) {
if (s100>0) { nsvet100beep(); s100=0; }};
if ((lastspeed<speed110)&(sp>=speed110)) {
if (s110<1) { svet4beep(); s110=1; }};
if ((lastspeed>=unspeed110)&(sp<unspeed110)) {
if (s110>0) { nsvet4beep(); s110=0; }};
if ((lastspeed<speed120)&(sp>=speed120)) {
if (s120<1) { svet120beep(); s120=1; }};
if ((lastspeed>=unspeed120)&(sp<unspeed120)) {
if (s120>0) { nsvet120beep(); s120=0; }};
if ((lastspeed<speed130)&(sp>=speed130)) {
if (s130<1) { svet130beep(); s130=1; }};
if ((lastspeed>=unspeed130)&(sp<unspeed130)) {
if (s130>0) { nsvet130beep(); s130=0; }};
lastspeed=sp;
delay(50);
//конец обработки превышения скорости
}//конец обработки при молчащем рчнике
// voltmeter();
//обработка очереди мр3
if (mp3stekpos != 0)
{ busy = digitalRead(7); // Получить состояние пина 7:
if (softbusy > 0) softbusy = softbusy-1;//предварительная задержка, т.к. busy возникает не сразу
if ((busy>0) && (softbusy ==0)) //если не занят мр3
{mp3stekpos = mp3stekpos-1;
nomer_mp3 = mp3stek[1];
if (cfg[15]==0) {mp3_play (mp3stek[1]);} else {mp3_play (mp3stek[1]+100);} //выбор голоса
softbusy = 25; delay(50);
for (int i=1; i < 9; i++){mp3stek[i]=mp3stek[i+1]; }
mp3stek[9]= 0; };}
//обработка ПДУ сигналов
/**/ if (irrecv.decode(&results))
{
Serial.println(results.value);
// lcd.setCursor(6, 1);
// lcd.print(results.value);
//проверяем кнопки
//кнопка повер или муте общий выкл звука 0-2
if ((results.value==2255209021)|| (results.value==2255218711))
{ cfg[0]=cfg[0]+1;
if (cfg[0]>2) { cfg[0]=0; }; EEPROM.write(5,cfg[0]);
if (cfg[0]==0) {add_mp3(5);}; //sound on
if (cfg[0]==1) {add_mp3(3);}; //sound off krome ruka
if (cfg[0]==2) {add_mp3(4);}; }//sound off all
//кнопка V+ - прибавить громкость мр3
if ((results.value==2255188111)||(results.value==2155866645))
{ cfg[1]=cfg[1]+1;
if (cfg[1]>4) {cfg[1]=4;add_mp3(41);}
if (cfg[1]==1) {add_mp3(38);}
if (cfg[1]==2) {add_mp3(39);}
if (cfg[1]==3) {add_mp3(40);}
if (cfg[1]==4) {add_mp3(41);}
mp3setvol(); EEPROM.write(6,cfg[1]); }
//кнопка V- - убавить громкость мр3
if ((results.value==2255210551)||(results.value==2155809015))
{ if (cfg[1]<1) {add_mp3(37); } else {cfg[1]=cfg[1]-1;}
if (cfg[1]==1) {add_mp3(38);}
if (cfg[1]==2) {add_mp3(39);}
if (cfg[1]==3) {add_mp3(40);}
mp3setvol(); EEPROM.write(6,cfg[1]); }
if (results.value==2255192191) //кнопка sourse - переключить голос на +100
{ if (cfg[15]==0){ cfg[15]=1;}
else { cfg[15]=0;} add_mp3(42);
EEPROM.write(20,cfg[15]); }
if (results.value==2255222791) //кнопка синяя - отключение д.свет
{ if (cfg[2]==0) { cfg[2]=1; add_mp3(18);} //no dsvet
else { cfg[2]=0; add_mp3(19); }//dsvet on
EEPROM.write(7,cfg[2]); }
if (results.value==2255220751) //кнопка 4 - отключение скорости 40
{ if (cfg[3]==0) { cfg[3]=1; add_mp3(36); }//40 off
else { cfg[3]=0; add_mp3(35); }//40 on
EEPROM.write(8,cfg[3]); }
if (results.value==2255200351) //кнопка 5 - отключение скорости 50
{ if (cfg[9]==0) { cfg[9]=1; add_mp3(65); } //50 off
else { cfg[9]=0; add_mp3(66); }//50 on
EEPROM.write(14,cfg[9]); }
if (results.value==2255184031) //кнопка 6 - отключение скорости 60
{ if (cfg[4]==0) { cfg[4]=1; add_mp3(12); }//60 off
else { cfg[4]=0; add_mp3(13); }//60 on
EEPROM.write(9,cfg[4]); }
if (results.value==2255171791) //кнопка 7 - отключение скорости 70
{ if (cfg[10]==0) {cfg[10]=1; add_mp3(45);} //70 off
else { cfg[10]=0; add_mp3(46); }//70 on
EEPROM.write(15,cfg[10]); }
if (results.value==2255204431) //кнопка 8 - отключение скорости 80
{ if (cfg[5]==0) { cfg[5]=1; add_mp3(14); }//80 off
else { cfg[5]=0; add_mp3(15); }//80 on
EEPROM.write(10,cfg[5]); }
if (results.value==2255179951) //кнопка 9 - отключение скорости 90
{ if (cfg[11]==0) {cfg[11]=1; add_mp3(49);} //90 off
else { cfg[11]=0; add_mp3(50);} //90 on
EEPROM.write(16,cfg[11]); }
if (results.value==2255194231) //кнопка 0 - отключение скорости 100
{ if (cfg[12]==0) {cfg[12]=1; add_mp3(53);} //100 off
else { cfg[12]=0; add_mp3(54);} //100 on
EEPROM.write(17,cfg[12]); }
if (results.value==2255167711) //кнопка 1 - отключение скорости 110
{ if (cfg[6]==0) { cfg[6]=1; add_mp3(16);} //110 off
else { cfg[6]=0; add_mp3(17);} //110 on
EEPROM.write(11,cfg[6]); }
if (results.value==2255163631) //кнопка 2 - отключение скорости 120
{ if (cfg[13]==0) { cfg[13]=1; add_mp3(57);} //120 off
else { cfg[13]=0; add_mp3(58);} //120 on
EEPROM.write(18,cfg[13]); }
if (results.value==2255175871) //кнопка 3 - отключение скорости 130
{ if (cfg[14]==0) { cfg[14]=1; add_mp3(61);} //130 off
else { cfg[14]=0; add_mp3(62);} //130 on
EEPROM.write(19,cfg[14]); }
if ((results.value==2255206471)||(results.value==2155829925)) //кнопка зеленая? - отключение вольтметра
{ if (cfg[7]==0) { cfg[7]=1; add_mp3(27);} //no Вольтметр
else { cfg[7]=0; add_mp3(28); voltmetertest(); }//Вольтметр on
EEPROM.write(12,cfg[7]); }
if (results.value==2255190151) //кнопка желтая - отключение DHO
{ if (cfg[8]==0) { cfg[8]=1; add_mp3(31);} //no DHO
else { cfg[8]=0; add_mp3(30);} //DHO on
EEPROM.write(13,cfg[8]); }
irrecv.resume(); // Receive the next value
}
}
//вывод в монитор порта текущих параметров
void sdisplay(){
if (ruka==1) { Serial.print("ruka=off ");} else{ Serial.print("RUKA=ON ");};
if (dsvet==1) { Serial.print("dsvet=off ");} else{ Serial.print("DSVET=ON ");};
if (gaba==1) { Serial.print("gaba=off ");} else{ Serial.print("GABA=ON ");};
Serial.println(" ");
Serial.print(" speed=");
Serial.println(sp);
Serial.println("++++++++++++++++++ END ++++++");
}
void speedometr(){ if (!st){micros_sp = micros();} else {sp20 = (12000000/(micros() - micros_sp));} sp=sp20/20; st = !st; sz=10;}
void rukabeep() { if (cfg[2]!=2) {mp3_play (1);} delay(1000);}
void svetbeep() { if ((cfg[2]==0)&&(cfg[0]==0)) {add_mp3(2);}}
void DHO_beep() { if ((cfg[8]==0)&&(cfg[0]==0)) {add_mp3(29);}}
void svet1beep() { if ((cfg[3]==0)&&(cfg[0]==0)) {add_mp3(33);}} //40
void nsvet1beep() { if ((cfg[3]==0)&&(cfg[0]==0)) {add_mp3(34);}} //n40
void svet50beep() { if ((cfg[9]==0)&&(cfg[0]==0)) {add_mp3(63);}} //50
void nsvet50beep() { if ((cfg[9]==0)&&(cfg[0]==0)) {add_mp3(64);}} //n50
void svet2beep() { if ((cfg[4]==0)&&(cfg[0]==0)) {add_mp3(6);}} //60
void nsvet2beep() { if ((cfg[4]==0)&&(cfg[0]==0)) {add_mp3(7);}} //n60
void svet70beep() { if ((cfg[10]==0)&&(cfg[0]==0)) {add_mp3(43);}} //70
void nsvet70beep() { if ((cfg[10]==0)&&(cfg[0]==0)) {add_mp3(44);}} //n70
void svet3beep() { if ((cfg[5]==0)&&(cfg[0]==0)) {add_mp3(8);}} //80
void nsvet3beep() { if ((cfg[5]==0)&&(cfg[0]==0)) {add_mp3(9);}} //n80
void svet90beep() { if ((cfg[11]==0)&&(cfg[0]==0)) {add_mp3(47);}} //90
void nsvet90beep() { if ((cfg[11]==0)&&(cfg[0]==0)) {add_mp3(48);}} //n90
void svet100beep() { if ((cfg[12]==0)&&(cfg[0]==0)) {add_mp3(51);}} //100
void nsvet100beep(){ if ((cfg[12]==0)&&(cfg[0]==0)) {add_mp3(52);}} //n100
void svet4beep() { if ((cfg[6]==0)&&(cfg[0]==0)) {add_mp3(10);}} //110
void nsvet4beep() { if ((cfg[6]==0)&&(cfg[0]==0)) {add_mp3(11);}} //n110
void svet120beep() { if ((cfg[13]==0)&&(cfg[0]==0)) {add_mp3(55);}} //120
void nsvet120beep(){ if ((cfg[13]==0)&&(cfg[0]==0)) {add_mp3(56);}} //n120
void svet130beep() { if ((cfg[14]==0)&&(cfg[0]==0)) {add_mp3(59);}} //130
void nsvet130beep(){ if ((cfg[14]==0)&&(cfg[0]==0)) {add_mp3(60);}} //n130
//void svet1unbeep(){ tone (17,1000); delay(200); noTone(17);}
void add_mp3(byte nomermp3)
{ if ((mp3stekpos > 8)&&(cfg[0]<2))//если переполнение очереди то пищалка
{ if (cfg[0]==0) { tone (17,1000); delay(200); tone (17,1400); delay(200); noTone(17); }}//пищалку не включать если все звуки отключены
else { mp3stekpos = mp3stekpos+1; mp3stek[mp3stekpos] = nomermp3; }} //собственно постановка в очередь
void mp3setvol() //перекодировка уровней громкости из 0-4 в 0-30
{if(cfg[1]==0){mp3_set_volume(10);}if(cfg[1]==1){mp3_set_volume(15);}if(cfg[1]==2){mp3_set_volume(20);}if(cfg[1]==3){mp3_set_volume(25);}if(cfg[1]>3){mp3_set_volume(30);}}
void voltmetertest()
{ outputValue = 0;
int u_x10 =0 ;
int u_x1 =0 ;
int u_x0 =0 ;
for (int iii=0; iii <10 ; iii++) { outputValue =outputValue + float(analogRead(A0)); delay(100); }//усреднение нескольких измерений
outputValue = outputValue/620;//коэффициент прямого пересчета в вольты
u_x10=round(outputValue*10); //напряжение х10
u_x1=floor(u_x10/10); //целая часть вольтов
add_mp3(70+u_x1);
u_x0=u_x10-(10*u_x1); //десятые = 10U-10Uокруг
add_mp3(90+u_x0);
}
void gabamute()
{ if (lastgabaonoff==gaba)
{//габариты не трогали
gabaonofftimer=gabaonofftimer+1;
if (gabaonofftimer>250 )
{//давно не трогали габариты - обнуляем ожидание
gabaonofftimer=250;
gabaonoffcounter=0;
}
}
else
{//габариты щелкнули
lastgabaonoff=gaba;
if (gabaonoffcounter==0) {gabaonofftimer=0;} //первый щелчок
// Serial.println(gabaonofftimer);
if (gabaonofftimer<25)
{//щелчок недавно был
gabaonoffcounter=gabaonoffcounter+1;
gabaonofftimer=0;
if (gabaonoffcounter>5)
{//блок отключения-включения звука по циклу
gabaonoffcounter=0;
cfg[0]=cfg[0]+1;
if (cfg[0]>2) { cfg[0]=0; };
EEPROM.write(5,cfg[0]);
if (cfg[0]==0) {add_mp3(5);}; //sound on
if (cfg[0]==1) {add_mp3(3);}; //sound off krome ruka
if (cfg[0]==2) {add_mp3(4);}; //sound off all
} }
else { gabaonoffcounter=0; gabaonofftimer=0; }
}}
Она умеет выдавать сигналы — габариты, дальний свет, ручник, и менять скорость с 0 до 150 примерно. Из недостатков — нет подавления дребезга контактов, но мне не особо мешает этот момент.
#include <Wire.h> // добавляем необходимые библиотеки
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );
const int rukaPin = 2; // пин = ручник
const int dsvetPin = 1; // пинт = д.свет
const int speedPin = 0; // пин = датчик скорости
const int gabaPin = 11; // пин6 = габариты
int rukaState = 0; // Переменная значения кнопки
int dsvetState = 0; // Переменная значения кнопки
int speedState = 0; // Переменная значения кнопки
int gabaState = 0; // Переменная значения кнопки
int speedkm = 0; // км/ч
int lowdelay = 250; // задержка генератора молой частоты
// Нажатые кнопки
int button;
const int BUTTON_NONE = 0;
const int BUTTON_RIGHT = 1;
const int BUTTON_UP = 2;
const int BUTTON_DOWN = 3;
const int BUTTON_LEFT = 4;
const int BUTTON_SELECT = 5;
int getPressedButton()
{
int buttonValue = analogRead(0); // считываем значения с аналогового входа(A0)
if (buttonValue < 60) {
return BUTTON_RIGHT;
}
else if (buttonValue < 200) {
return BUTTON_UP;
}
else if (buttonValue < 400){
return BUTTON_DOWN;
}
else if (buttonValue < 600){
return BUTTON_LEFT;
}
else if (buttonValue < 800){
return BUTTON_SELECT;
}
return BUTTON_NONE;
}
void setup()
{
pinMode(rukaPin, OUTPUT); // Настраиваем порт на выход
pinMode(dsvetPin, OUTPUT); // Настраиваем порт на выход
pinMode(speedPin, OUTPUT); // Настраиваем порт на выход
pinMode(gabaPin, OUTPUT); // Настраиваем порт на выход
lcd.begin(16, 2);
lcd.print("starting...");
delay (500);
lcd.clear();
lcd.setCursor(12, 0);
if(gabaState == 1){lcd.print("G_ON");}else{lcd.print("GOFF");}
digitalWrite(gabaPin,gabaState);
lcd.setCursor(6, 0);
if(dsvetState == 1){lcd.print("D__ON");}else{lcd.print("D_OFF");}
digitalWrite(dsvetPin,dsvetState);
lcd.setCursor(0, 0);
if(rukaState == 0){lcd.print("R__ON");}else{lcd.print("R_OFF");}
digitalWrite(rukaPin,rukaState);
}
void loop()
{
delay(50);
if ((speedState<=36)&(speedState>0))
{
lowdelay=500/speedState;
digitalWrite(speedPin,1);
delay(lowdelay);
digitalWrite(speedPin,0);
delay(lowdelay);
lcd.setCursor(12, 1);
lcd.print(lowdelay);
lcd.print(" ");
}
button = getPressedButton();
switch (button)
{
case BUTTON_RIGHT: // при нажатии кнопки выводим следующий текст
lcd.setCursor(12, 0);
if (gabaState == 0)
{
gabaState = 1;
lcd.print("G_ON ");
}
else
{
gabaState = 0;
lcd.print("GOFF ");
}
digitalWrite(gabaPin,gabaState);
break;
case BUTTON_LEFT:
lcd.setCursor(6, 0);
if (dsvetState == 0)
{
dsvetState = 1;
lcd.print("D__ON ");
}
else
{
dsvetState = 0;
lcd.print("D_OFF ");
}
digitalWrite(dsvetPin,dsvetState);
break;
case BUTTON_UP:
if (speedState<5){speedState=speedState+1;} else {if (speedState<250){speedState=speedState+5;};}
lcd.setCursor(0, 1);
lcd.print(speedState);
speedkm=speedState*0.6;
lcd.print(" ");
lcd.print(speedkm);
lcd.print("km/h ");
if (speedState>35){ tone(speedPin,speedState);}
else
{
noTone(speedPin);
};
break;
case BUTTON_DOWN:
if ((speedState<10)&(speedState>0)){speedState=speedState-1;}
else
{
if ((speedState<255)&(speedState>0)){speedState=speedState-5;}
} ;
lcd.setCursor(0, 1);
lcd.print(speedState);
speedkm=speedState*0.6;
lcd.print(" ");
lcd.print(speedkm);
lcd.print("km/h ");
// if (speedState==0){noTone(speedPin);} else {tone(speedPin,speedState);};
if (speedState>35){ tone(speedPin,speedState);}
else
{
noTone(speedPin);
};
break;
case BUTTON_SELECT:
// lcd.setCursor(0, 0);
// lcd.print(" ");
lcd.setCursor(0, 0);
if (rukaState == 0)
{
rukaState = 1;
lcd.print("R_OFF ");
}
else
{
rukaState = 0;
lcd.print("R__ON ");
}
digitalWrite(rukaPin,rukaState);
break;
}
}
Комментарии (15)
shtirlitsus
20.02.2017 14:16Посоветовал бы Вам озвучку взять с https://www.ivona.com
Повменяемей, на мой слух.
artskep
20.02.2017 18:52+1Это, конечно, круто, но зачем голосом? Ну, кроме очевидной причины «потому что могу»?
По большому счету — весь функционал — предупреждение об опасной или потенциально опасной ситуации. В таких случаях подключать голову, чтобы слушать женский или мужской голос — не самая хорошая идея.
Не лучше ли запилить разной степени «пикалки» в зависимости от проблемы.
К примеру, на движение с ручником, без включенных огней — резкую пищалку (ибо надо).
На дальний свет — че-то помягче (ибо, далеко не факт, что он просто так горит).
На напряжение бортовой сети… даже не знаю.
А для повышения/понижения порога скорости, я бы предложил посмотреть, как это сделано у вариометра у парапланеристов — не совсем хорошая аналогия, но все-таки, тон пикания при повышении, понижении скорости даст больше информации (особенно когда привыкнешь)
AlexKooper
20.02.2017 22:34Забыл добавить ссылку на голосовые и текстовые файлы. https://yadi.sk/d/Mk8eiMyP3Dwfv4
Насчет «пикалки» вместо звука — первые варианты были именно такие. От них и зуммер остался в плате. Но когда событий стало за десяток — сложно на слух воспринимать отличия между писками разной тональности и длительности. Заодно проговаривается изменение настроек — ПДУ может не всегда сработать.
Кстати, звуки воспроизводятся с ощутимой задержкой, поэтому немного нелитературно сделана озвучка вольтметра в плане десятых долей (Напряжение двенадцать вольт… И девять десятых.). Заказал на али голосовой модуль, который должен быть свободен от таких задержек, WT588D-U 32 М называется. Поэкспериментирую.
Ещё одна из проблем — неправильно измеряется скорость на скоростях выше 60 км/ч. В принципе, пороги забиты константами, и подобрать можно экспериментально, но я хочу разобраться, почему не подходят теоретические расчеты.
Да, панель приборов у меня блеклая, лампу дальнего света днем не видно, а лампа ручника ещё и закрыта рулем. Поэтому езда «на слух».
Несложно также вывести со свободной ноги сигнал включения ДХО (простая проверка скорости s>0), возможно комбинировать с проверкой включения габаритов.
bigbrotherwatchingyou
20.02.2017 22:35Эммм… Это для тех, кто управляет автомобилем, закрыв глаза?
artskep
21.02.2017 16:41Я полагаю, для тех, кто предпочитает управлять автомобилем смотря на дорогу, а не на панель управления.
AlexKooper
20.02.2017 23:44Ссылка на голосовые файлы битая, вот правильная https://yadi.sk/d/3xnPrad-3EKGjy
AlexKooper
21.02.2017 20:37Ещё у меня изменена библиотека ИК-датчика, с целью использовать другой таймер, вот только не помню, для этого проекта или другого менял. В общем, если будет на таймеры ругаться — надо в файле IRremoteInt.h найти и поменять:
было:
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
#else
//#define IR_USE_TIMER1 // tx = pin 9
#define IR_USE_TIMER2 // tx = pin 3
стало:
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
#else
#define IR_USE_TIMER1 // tx = pin 9
//#define IR_USE_TIMER2 // tx = pin 3
AlexKooper
22.02.2017 19:10В нексии есть ODBII разъем, там у меня иногда живет elm327 адаптер. Других шин нет.
serafims
А сигнал о скорости откуда брался? с OBD2 разъема?
Urvin
mefiato
К основному аккумулятору подключать или нужен съемный типа такой батарейки?
AlexKooper
В машине использует бортовую сеть, при отладке на столе питается от usb, при отладке вольтметра питался от внешнего блока питания с регулируемым выходом. Я ответил на Ваш вопрос?
mefiato
Спасибо, очень интересно)