..." />

Управління камерою, приладами і дані з датчиків на екрані телевізора

  • Час 16-12-2014, 19:16
  • Автор admin
  • Коментарів 0 Комент.
  • Силка url

Пристрій на Arduino, використовується мікросхема max7456.

Це OSD (on screen display) монохромний
256 зарезервованих символів 
TSSOP 28 - корпус
Підключається до телевізора по входах "тюльпан". 

Управління камерою, приладами і дані з датчиків на екрані телевізора

Можливості:
 - перегляд зображення з камери
 - управління камерою (вгору-вниз, вліво-вправо)
 - відображення даних з датчиків (температура, вологість повітря, тиск)
 - управління приладами (RGB стрічка, новорічна лампа-нічник RGB, прожектор на вході, управління відкриттям вхідних дверей)
- за спрацьовування датчика руху - перемикання телевізора на зображення з відеокамери

Управляється все пультом із телевізора. Спочатку передмова, чому виникла необхідність даного пристрою. На лампу і RGB-стрічку постійно невідомо де пульт, до камери доступ з компа на WEB-інтерфейсу, що не дуже зручно, якщо хочеш подивитися, хто прийшов. Якщо все буде на екрані телевізора і управлятися пультом з цього ж телевізора, звичайно ж спростить користування цими приладами. Звичайно і пульт від телевізора втрачається, але набагато рідше.

Мікросхема max7456 була зайва (купував для плати OSD для радіокерованого автомобіля, але прийшла бракована плата GPS і поки проект відкладається)

Ось схема пристрою (немає поки датчика руху і мікросхеми годин D1307)

Управління камерою, приладами і дані з датчиків на екрані телевізора

І скетч для Arduino (неповний - ще не прийшли датчик руху і мікросхема годин DS1307)

Використовуються бібліотеки

MAX7456 -  висновок символів через max7456;

IRremote - одержання і відправлення ІК;

Servo - для управління сервоприводами повороту камери;

OneWire - для роботи з датчиками температури DS18B20; 

DHT - для роботи з датчиком DH11 (вимірювання вологості повітря)

BMP085 - для роботи з датчиком BMP085 (атмосферний тиск)

#define DATAOUT 11//MOSI #define DATAIN 12//MISO #define SPICLOCK 13//sck #define MAX7456SELECT 10//ss #define VSYNC 0x02// INT0 #define DMM_reg 0x04 #define DMAH_reg 0x05 #define DMAL_reg 0x06 #define DMDI_reg 0x07 #define VM0_reg 0x00 #define VM1_reg 0x01 #define VIDEO_BUFFER_DISABLE 0x01 #define MAX7456_RESET 0x02 #define VERTICAL_SYNC_NEXT_VSYNC 0x04 #define OSD_ENABLE 0x08 #define SYNC_MODE_AUTO 0x00 #define SYNC_MODE_INTERNAL 0x30 #define SYNC_MODE_EXTERNAL 0x20 #define VIDEO_MODE_PAL 0x40 #define VIDEO_MODE_NTSC 0x00 #define BLINK_DUTY_CYCLE_50_50 0x00 #define BLINK_DUTY_CYCLE_33_66 0x01 #define BLINK_DUTY_CYCLE_25_75 0x02 #define BLINK_DUTY_CYCLE_75_25 0x03 #define BLINK_TIME_0 0x00 #define BLINK_TIME_1 0x04 #define BLINK_TIME_2 0x08 #define BLINK_TIME_3 0x0C #define BACKGROUND_BRIGHTNESS_0 0x00 #define BACKGROUND_BRIGHTNESS_7 0x10 #define BACKGROUND_BRIGHTNESS_14 0x20 #define BACKGROUND_BRIGHTNESS_21 0x30 #define BACKGROUND_BRIGHTNESS_28 0x40 #define BACKGROUND_BRIGHTNESS_35 0x50 #define BACKGROUND_BRIGHTNESS_42 0x60 #define BACKGROUND_BRIGHTNESS_49 0x70 #define BACKGROUND_MODE_GRAY 0x40 #define CLEAR_display 0x04 #define CLEAR_display_vert 0x06 #define END_string 0xff #define ENABLE_display 0x08 #define ENABLE_display_vert 0x0c #define MAX7456_reset 0x02 #define DISABLE_display 0x00 #define WHITE_level_80 0x03 #define WHITE_level_90 0x02 #define WHITE_level_100 0x01 #define WHITE_level_120 0x00 #define MAX_screen_size 390 #define MAX_screen_rows 16 byte spi_junk, eeprom_junk; int x; //*************************** struct MENU // структура меню { char* name1[27]; // найменування int y[27]; int x[27]; int activ[27]; int pos1; // позиція меню char bottom2[100]; int offbottom2; }; MENU MENU1={ {"Камера","\xD6","\xD2","\xD5","\xD7","00", "Датчики","Викл", "Прилад","Ч","Б","К","О","С","Р","З","Б", "Г","Б","К","О","С","Р","З","Б", "Вимкн.","00:00" }, {2,4,5,4,5,4,10,13,19,19,20,21,22,23,24,25,26,19,20,21,22,23,24,25,26,19,22}, {1,2,2,3,3,4,1, 6, 1, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 7, 13}, {1,0,0,0,0,0,1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 0," ",0}; struct MYDATA // структура меню { int servo_ud; // положення камери up-down int servo_lr; // положення камери left-right float t1; // значення t1 float t2; // значення t2 float h1; // значення h1 - відносна вологість float p1; // значення p1 - тиск int dd; // датчик руху Викл-Вкл int posl1; // лампа (0-7) int posl2; // стрічка (0-7) int posp1; // прожектор }; MYDATA MYDATA1={0,0,0.0,0.0,0.0,0.0,0,0,0,0}; #include "IRremote.h int RECV_PIN=2; IRrecv irrecv(RECV_PIN); IRsend irsend; //decode_results results; unsigned long ir_dt, old_ir; long ir_kod; unsigned long ir_time1, ir_time2; #define B_LEFT1 0x11 #define B_LEFT2 0x811 #define B_RIGHT1 0x10 #define B_RIGHT2 0x810 #define B_OK1 0x25 #define B_OK2 0x825 #define B_CLEARMENU1 0x37 #define B_CLEARMENU2 0x837 #include "Servo.h" Servo camera_hor,camera_vert; #include "OneWire.h" OneWire ds(8); // on pin 8 byte my_addr[3][8]={{0x28,0x67,0xE5,0xC7,2,0,0,0xA0}, {0x28,0x94,0xB4,0x65,4,0,0,0 xAC}, {0x28,0xF6,0x98,0xBA,2,0,0,0x92}}; #include "Wire.h" #include "BMP085.h" BMP085 dps = BMP085(); long Pressure085 = 0, Altitude085 = 0; #include "DHT.h" #define DHTTYPE DHT11 // DHT 11 DHT dht(7, DHTTYPE); float dh1; ////////////////////////////////////////////////////////////// void setup() { Serial.begin(9600); Serial.flush(); Serial.println("setup"); pinMode(MAX7456SELECT,OUTPUT); digitalWrite(MAX7456SELECT,HIGH); pinMode(DATAOUT, OUTPUT); pinMode(DATAIN, INPUT); pinMode(SPICLOCK,OUTPUT); pinMode(VSYNC, INPUT); SPCR = (1lt;0) { Serial.println(ir_kod,HEX); change_pos_menu(ir_kod); ir_kod=0; } delay(100); } ////////////////////////////////////////////////////////////// byte spi_transfer(volatile byte data) { SPDR = data; while (!(SPSR & (1lt;gt; 8; char_address_lo = linepos; settings = B00000001; if (blink) if (invert) digitalWrite(MAX7456SELECT,LOW); spi_transfer(DMM_reg); spi_transfer(settings); spi_transfer(DMAH_reg); spi_transfer(char_address_hi); spi_transfer(DMAL_reg); spi_transfer(char_address_lo); while(s[local_count]!='\0') { screen_char = s[local_count]; if(screen_char != 208 && screen_char != 209) { spi_transfer(DMDI_reg); spi_transfer(screen_char); } local_count++; } spi_transfer(DMDI_reg); spi_transfer(END_string); spi_transfer(DMM_reg); spi_transfer(B00000000); digitalWrite(MAX7456SELECT,HIGH); } // отримати код переданий з ІЧ пульта void get_ir_kod() { decode_results results; detachInterrupt(0); // відключити переривання 0 if (irrecv.decode(&results)) { if (results.value gt; 0 && results.value lt; 0xFFFFFFFF) { ir_dt = results.value; ir_time2=millis(); if (ir_time2-ir_time1gt;400) {ir_kod = ir_dt;ir_time1=ir_time2;} else ir_kod = 0; } irrecv.resume(); } attachInterrupt(0, get_ir_kod, FALLING); } // void show_menu() { for(int i=0;ilt;27;i++) { if(i==MENU1.pos1 && MENU1.activ[i]==1) OSD_write_to_screen(MENU1.name1[i],MENU1.y[i],MENU1.x[i], 1,1); else if(MENU1.activ[i]==1) OSD_write_to_screen(MENU1.name1[i],MENU1.y[i],MENU1.x[i], 0,0); } } // перевірка на визначені для дій клавіші void change_pos_menu(long kod) { int newpos=0;int dd=1; if(kod==B_LEFT1 || kod==B_LEFT2) // зменшити звуко { do { newpos=max(MENU1.pos1-dd,0);dd++; } while(MENU1.activ[newpos]lt;1); MENU1.pos1=newpos;} else if(kod==B_RIGHT1 || kod==B_RIGHT2) // збільшити звуко { do { newpos=min(MENU1.pos1+dd,26);dd++; } while(MENU1.activ[newpos]lt;1); MENU1.pos1=newpos;} else if(kod==B_OK1 || kod==B_OK2) // ok prg_ok(); else if(kod==B_CLEARMENU1 || kod==B_CLEARMENU2) // ok clear_menu2(); else ; Serial.println(MENU1.pos1); } // очищення всіх підменю void clear_menu2() { MENU1.pos1=0; for(int i=0;ilt;27;i++) {MENU1.activ[i]=0; for(int j=2;jlt;8;j++) OSD_write_to_screen(" ", i, j, 0,0); } MENU1.activ[0]=1;MENU1.activ[6]=1; MENU1.activ[8]=1;MENU1.activ[26]=1; } // клавіша ok void prg_ok() {char c1[4];char dd[7]; switch(MENU1.pos1) { case 0 : // меню камера if(MENU1.activ[2]==1) { OSD_write_to_screen(" ",2,2,0,0); OSD_write_to_screen(" ",2,3,0,0); OSD_write_to_screen(" ",2,4,0,0); MENU1.activ[1]=0;MENU1.activ[2]=0;MENU1.activ[3]=0; MENU1.activ[4]=0;MENU1.activ[5]=0; } else { MENU1.activ[1]=1;MENU1.activ[2]=1;MENU1.activ[3]=1; MENU1.activ[4]=1;MENU1.activ[5]=1; } break; case 1 : // камера вниз MYDATA1.servo_ud=max(MYDATA1.servo_ud-10,-90); camera_vert.attach(5); camera_vert.write(MYDATA1.servo_ud+90); delay(500); camera_vert.detach(); Serial.print("down=");Serial.println(MYDATA1.servo_ud); break; case 2 : // камера вгору MYDATA1.servo_ud=min(MYDATA1.servo_ud+10,90); camera_vert.attach(5); camera_vert.write(MYDATA1.servo_ud+90); delay(500); camera_vert.detach(); Serial.print("up=");Serial.println(MYDATA1.servo_ud); break; case 3 : // камера вліво MYDATA1.servo_lr=max(MYDATA1.servo_lr-10,-90); camera_hor.attach(4); camera_hor.write(MYDATA1.servo_lr+90); delay(500); camera_hor.detach(); Serial.print("left=");Serial.println(MYDATA1.servo_lr); break; case 4 : // "камера вправо" MYDATA1.servo_lr=min(MYDATA1.servo_lr+10,90); camera_hor.attach(4); camera_hor.write(MYDATA1.servo_lr+90); delay(500); Serial.print("right=");Serial.println(MYDATA1.servo_lr); camera_hor.detach(); break; case 5 : // "камера в 0" MYDATA1.servo_ud=0;MYDATA1.servo_lr=0; camera_hor.attach(4);camera_vert.attach(5); camera_hor.write(90);camera_vert.write(90); delay(500); camera_hor.detach();camera_vert.detach(); break; case 6 : // меню датчики if(MENU1.activ[7]==1) { OSD_write_to_screen(" ",10,2,0,0); OSD_write_to_screen(" ",10,3,0,0); OSD_write_to_screen(" ",10,4,0,0); OSD_write_to_screen(" ",10,5,0,0); OSD_write_to_screen(" ",10,6,0,0); MENU1.activ[7]=0; } else { MENU1.activ[7]=1; dtostrf(getMeteoData(2),0,2,dd); OSD_write_to_screen(dd,10,2,0,0); //sprintf(dd,"%f",getMeteoData(1)); dtostrf(getMeteoData(1),0,2,dd); OSD_write_to_screen(dd,10,3,0,0); Serial.print("dht="); detachInterrupt(0); delay(100); irsend.sendRC5(0xff,12); delay(1000); attachInterrupt(0, get_ir_kod, FALLING); dh1=dht.readHumidity(); Serial.println(dh1); dtostrf(dht.readHumidity(),0,0,dd); dd[3]=0x25;dd[4]=' ';dd[2]=' '; OSD_write_to_screen(dd,10,4,0,0); dps.getPressure(&Pressure085); dtostrf(Pressure085/133.3,0,2,dd); OSD_write_to_screen(dd,10,5,0,0); OSD_write_to_screen("ДД",10,6,0,0); OSD_write_to_screen("Увімк",13,6,0,0); irrecv.enableIRIn(); } break; case 7 : // датчик руху MYDATA1.dd=1-MYDATA1.dd; if(MYDATA1.dd==0) MENU1.name1[7]="Викл"; else MENU1.name1[7]="Вкл "; send_ir_kod(0x01); send_ir_kod(0x838); break; case 8 : // меню прилади if(MENU1.activ[9]==1) { OSD_write_to_screen(" ",19,2,0,0); OSD_write_to_screen(" ",19,3,0,0); MENU1.activ[9]=0;MENU1.activ[10]=0; MENU1.activ[11]=0;MENU1.activ[12]=0;MENU1.activ[13]=0; MENU1.activ[14]=0;MENU1.activ[15]=0;MENU1.activ[16]=0; OSD_write_to_screen(" ",19,4,0,0); OSD_write_to_screen(" ",19,5,0,0); MENU1.activ[17]=0;MENU1.activ[18]=0; MENU1.activ[19]=0;MENU1.activ[20]=0;MENU1.activ[21]=0; MENU1.activ[22]=0;MENU1.activ[23]=0;MENU1.activ[24]=0; OSD_write_to_screen(" ",19,6,0,0); MENU1.activ[25]=0; OSD_write_to_screen(" ",19,7,0,0); } else { OSD_write_to_screen("Лампа",19,2,0,0); MENU1.activ[9]=1;MENU1.activ[10]=1; MENU1.activ[11]=1;MENU1.activ[12]=1;MENU1.activ[13]=1; MENU1.activ[14]=1;MENU1.activ[15]=1;MENU1.activ[16]=1; OSD_write_to_screen("Стрічка",19,4,0,0); MENU1.activ[17]=1;MENU1.activ[18]=1; MENU1.activ[19]=1;MENU1.activ[20]=1;MENU1.activ[21]=1; MENU1.activ[22]=1;MENU1.activ[23]=1;MENU1.activ[24]=1; OSD_write_to_screen("Прож",19,6,0,0); MENU1.activ[25]=1; OSD_write_to_screen(" ",19,7,0,0); } break; // лампа1 case 9 : // чорний MYDATA1.posl1=0;send_ir_kod(0x1);break; case 10 : // білий MYDATA1.posl1=1;send_ir_kod(0x2);break; case 11 : // MYDATA1.posl1=2;send_ir_kod(0x2);break; case 12 : // MYDATA1.posl1=3;send_ir_kod(0x2);break; case 13 : // MYDATA1.posl1=4;send_ir_kod(0x2);break; case 14 : // MYDATA1.posl1=5;send_ir_kod(0x2);break; case 15 : // MYDATA1.posl1=6;send_ir_kod(0x2);break; case 16 : // MYDATA1.posl1=7;send_ir_kod(0x2);break; // стрічка світлодіодна //0xDF,0x9F,0x5F,0xEF,0xAF,0x6F,0x1F,0xBF case 17 : // чорний MYDATA1.posl2=0;send_ir_kod(0xBF);break; case 18 : // білий MYDATA1.posl2=1;send_ir_kod(0x1F);break; case 19 : // R MYDATA1.posl2=2;send_ir_kod(0xDF);break; case 20 : // RB MYDATA1.posl2=3;send_ir_kod(0x2);break; case 21 : // B MYDATA1.posl2=4;send_ir_kod(0x5F);break; case 22 : // BG MYDATA1.posl2=5;send_ir_kod(0x2);break; case 23 : // G MYDATA1.posl2=6;send_ir_kod(0x9F);break; case 24 : // RG MYDATA1.posl2=7;send_ir_kod(0x2);break; // прожектор case 25 : MYDATA1.posp1=1-MYDATA1.posp1; if(MYDATA1.posp1==0) MENU1.name1[25]="Викл"; else MENU1.name1[25]="Вкл "; break; default: break; } sprintf(c1,"%d",abs(MYDATA1.servo_ud)); OSD_write_to_screen(" ",2,2,0,0);OSD_write_to_screen(" ",6,2,0,0); if(MYDATA1.servo_udlt;0 && MENU1.activ[2]==1) {OSD_write_to_screen(c1,2,2,0,0);} else if(MYDATA1.servo_udgt;0 && MENU1.activ[2]==1) {OSD_write_to_screen(c1,6,2,0,0);} else ; sprintf(c1,"%d",abs(MYDATA1.servo_lr)); OSD_write_to_screen(" ",2,3,0,0);OSD_write_to_screen(" ",6,3,0,0); if(MYDATA1.servo_lrlt;0 && MENU1.activ[2]==1) {OSD_write_to_screen(c1,2,3,0,0);} else if(MYDATA1.servo_lrgt;0 && MENU1.activ[2]==1) {OSD_write_to_screen(c1,6,3,0,0);} else ; } // Відправка ІЧ-коду void send_ir_kod(long sendkod) { detachInterrupt(0); delay(100); irsend.sendRC5(sendkod,12); delay(1000); attachInterrupt(0, get_ir_kod, FALLING); irrecv.enableIRIn(); Serial.print("sendkod=");Serial.println(sendkod,HEX); } // отримання температури датчика float getMeteoData(int nn) { byte i; byte present = 0; byte data[12]; byte addr[8]; int Temp; float fTemp; char m0[5]; String str1=""; ds.reset(); ds.select(my_addr[nn-1]); ds.write(0x44,1); // start conversion, with parasite power on at the end delay(1000); // maybe 750ms is enough, maybe not present = ds.reset(); ds.select(my_addr[nn-1]); ds.write(0xBE); // Read Scratchpad for ( i = 0; i lt; 9; i++) { // we need 9 bytes data[i] = ds.read(); } Temp=(data[1]lt;lt;8)+data[0];//take the two bytes from the response relating to temperature Temp=Temp;//divide by 16 to get pure celcius readout fTemp=Temp/16+(float(Temp%16))/16; MYDATA1.t2=fTemp; return fTemp; }

Проблеми, які виникли при написанні скетчу:
DHT відмовлялася працювати з IRremote (функція enableIRIn() займає таймер, що використовується бібліотекою DHT), проблема вирішилася відключенням на час отримання з датчика DHT11 enableIRIn(), та включенням після отримання даних.

Управління за допомогою пульта телевізора. Навігація вліво-вправо (гучність), вибір (ОК), згорнути всі підменю -(EYE/*)

Необхідно розповісти про прошивці символів мікросхеми MAX7456. В пам'яті мікросхеми вже є прошиті символи

Управління камерою, приладами і дані з датчиків на екрані телевізора

Необхідно перепрошити, щоб були російські символи і деякі спеціальні (стрілки). 

Викачуємо бібліотеку MAX7456. В бібліотеці є приклад перепрошивки символів - UploadFont і кілька файлів .mcm з шрифтами для завантаження.

Запускаємо програму Hiper Terminal, вибираємо порт на якому сидить Ардуїнов, швидкість порту 9600, управління потоком xon-xoff. У меню програми гипертерминал вибираємо пункт send to file і вказуємо шлях до файлу зі шрифтом. Файл з російським шрифтом arduino1.mcm я взяв на форумі http://www.compcar.ru/forum/showthread.php?t=6064. Символи такі (arduino1.png)

Управління камерою, приладами і дані з датчиків на екрані телевізора
+
Управління камерою, приладами і дані з датчиків на екрані телевізора
=
Управління камерою, приладами і дані з датчиків на екрані телевізора

Я захотів додати ще символів. Береться файл arduino1.png, відкривається в редакторі Paint і редагується (я копипастил з файлу custom.png і вставляв, де необхідно). Одержаний png файл перетворюється в файл .mcm на ресурсі http://www.mylifesucks.de/tools/max7456/ (там же доступно і зворотне перетворення mcm-gt;png).

Цей набір символів я залив в max7456.

Остаточний монтаж вже після приходу всіх датчиків

Tags

Коментарі до новини