Устройство на 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,0×92}};
#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]!=’�’)
{
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.
Окончательный монтаж уже после прихода всех датчиков
Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот
Плата ArduinoArduino Uno1
Инфракрасный приемникTSOP-31281
Датчик температурыDS18B202
Датчик температурыDHT111
Датчик давленияBMP0851
OSD-контроллерMAX74561
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 Кб)