Устройство на 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,0xAC}, {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 = (1<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 & (1<> 8; char_address_lo = linepos; settings = B00000001; if (blink) { settings |= (1 << 4); } if (invert){ settings |= (1 << 3); } 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 > 0 && results.value < 0xFFFFFFFF) { ir_dt = results.value; ir_time2=millis(); if (ir_time2-ir_time1>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;i<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]<1); MENU1.pos1=newpos;} else if(kod==B_RIGHT1 || kod==B_RIGHT2) // увеличить звуко { do { newpos=min(MENU1.pos1+dd,26);dd++; } while(MENU1.activ[newpos]<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;i<27;i++) {MENU1.activ[i]=0; for(int j=2;j<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_ud<0 && MENU1.activ[2]==1) {OSD_write_to_screen(c1,2,2,0,0);} else if(MYDATA1.servo_ud>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_lr<0 && MENU1.activ[2]==1) {OSD_write_to_screen(c1,2,3,0,0);} else if(MYDATA1.servo_lr>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 < 9; i++) { // we need 9 bytes data[i] = ds.read(); } Temp=(data[1]<<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, открываетcя в редакторе Paint и редактируется (я копипастил из файла custom.png и вставлял, где необходимо). Получившийся png файл преобразовывается в файл .mcm на ресурсе http://www.mylifesucks.de/tools/max7456/ (там же доступно и обратное преобразование mcm->png).
Этот набор символов я залил в max7456.
Окончательный монтаж уже после прихода всех датчиков
Список радиоэлементов
Обозначение | Тип | Номинал | Количество | Примечание | Магазин | Мой блокнот |
---|---|---|---|---|---|---|
Плата Arduino | Arduino Uno | 1 | Поиск в магазине Отрон | |||
Инфракрасный приемник | TSOP-3128 | 1 | Поиск в магазине Отрон | |||
Датчик температуры | DS18B20 | 2 | Поиск в магазине Отрон | |||
Датчик температуры | DHT11 | 1 | Поиск в магазине Отрон | |||
Датчик давления | BMP085 | 1 | Поиск в магазине Отрон | |||
OSD-контроллер | MAX7456 | 1 | Поиск в магазине Отрон | |||
VT1 | Транзистор | 1 | Поиск в магазине Отрон | |||
D-ir1 | Светодиод | 1 | Поиск в магазине Отрон | |||
Z1 | Кварцевый резонатор | 1 | Поиск в магазине Отрон | |||
R1, R2 | Резистор | 2 | Поиск в магазине Отрон | |||
R3, R4 | Резистор | 2 | Поиск в магазине Отрон | |||
R5 | Резистор | 1 | Поиск в магазине Отрон | |||
R6 | Резистор | 1 | Поиск в магазине Отрон | |||
R7 | Резистор | 1 | Поиск в магазине Отрон | |||
C5, C8 | Конденсатор | 2 | Поиск в магазине Отрон | |||
C6, C7 | Электролитический конденсатор | 2 | Поиск в магазине Отрон | |||
Servo | Сервопривод | 2 | Поиск в магазине Отрон | |||
Скачать список элементов (PDF)
Прикрепленные файлы:
- osd9.zip (206 Кб)
Комментарии (5) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
[Автор]
[Автор]