Почему лазерный луч, а не радиосвязь? Ради фана. С целью обеспечения секретности, радиопередачи перехватывают все кому не лень, а перехватывать вспышки света не догадаются, к тому же нужно встать в направлении передачи луча. Возможно использовать там, где радиосвязь невозможна из-за сильных помех.
Для эксперимента нам потребуется:
- 2 Arduino;
- 1 Фоторезистор (или LDR) VT90N — компонент, меняющий сопротивление в зависимости от количества света падающего на него. В полной темноте он имеет максимальное сопротивление в сотни килоом, а по мере роста освещённости сопротивление уменьшается до десятков килоом:
- 1 лазерный модуль KY-008:
- 2 сопротивления: 220 Ом для передатчика,10 кОм для приемника.
Передатчик
Передатчик подключается как самая простая схема в Ардуине (Blink), можно поморгать код Морзе и обычным светодиодом, но на небольшое расстояние, для передачи на метровые расстояния придется воспользоваться лазером. Лазер можно взять или из лазерной указки или купить в магазине специальный модуль для Ардуино с 3 контактами:
Схема подключения лазера к Ардуино:
Так как KY-008 part не нашлась в fritzing на схеме пришлось использовать RGB светодиод, подписав ноги S и “-“, S пин подключаем к 13 ноге, минус к GND (земле).
Для передачи данных воспользуемся кодом Морзе — способ представления букв алфавита последовательностью длинных («тире») и коротких («точка») сигналов. Конечно, при передаче кодом Морзе нет коррекции ошибок, но для тестовой передачи можно обойтись и без нее. Так как мы все равно знаем последовательность передаваемых символов.
В коде скетча указываем на каком контакте будет подаваться морзянка, 13 нога (как для большинства blink.ino скетчей моргания светодиодом), второй параметр отвечает за скорость передачи (24 слов в минуту), 3 параметр 1 для beep звукового сигнала и 0 для PTT (переключение пина в HIGH и LOW). Если заглянуть в код Morse.cpp то увидим что для третьего параметра 1 – beep используется как аналоговый выход запись на пин:
analogWrite(_pin, 128);
delay(_dashlen);
analogWrite(_pin, 0);
delay(_dotlen);
а для 0 – используется как цифровой выход
digitalWrite(_pin, HIGH);
delay(_dashlen);
digitalWrite(_pin, LOW);
delay(_dotlen);
В нашем случае используем код: Morse morse(13, 24, 0);
Для работы скетча необходима библиотекой morze.zip автора Erik Linder. Скетч передатчика простой:
// Author Erik Linder
// Released 2011 under GNU GPLv3
//
// Usage: morse( <pin number>, <speed WPM>, <1=beep, 0=PTT> )
// sendmsg( "<text-to-send>" )
//
#include <Morse.h>
// Use pin 13 (built-in LED of Arduino 2009)
Morse morse(13, 24, 1);
void setup()
{
}
void loop()
{
morse.sendmsg("HELLO WORLD!");
delay (2000);
}
Заливаем скетч, система готова к передаче данных.
Приемник
Собираем схему приемника, ничего сложного, фоторезистор одна нога с 5V вторая нога аналоговый порт A0, резистор 10 кОм — одна нога GND («земля»), вторая нога A0:
int LDR_Pin = A0; //analog pin 0
int led = 13;
// 10k between GND and A0
// LDR between 5V and A0
#define MORSE_EMPTY 0
// Этими символами мы будем обозначать точки и тире.
#define MORSE_DOT '*'
#define MORSE_DOT2 '+'
#define MORSE_TIRE '-'
// Максимальная длина символа азбуки Морзе (в точках и тире)
#define MAX_MORSE_SYMBOL_LENGTH 8
char* morseSymbol[MAX_MORSE_SYMBOL_LENGTH];
unsigned int morseSymbolLen;
char* newMorseSignal; // Новый введенный сигнал - точка или тире.
// Таблица кодов Морзе. N-ный элемент кода соответствует n-ному символу раскладки.
char* code[] = {
"*-","-***","*--","--*","-**","*","***-","--**","**","*---",
"-*-","*-**","--","-*","---","*--*","*-*","***","-","**-",
"**-*","****","-*-*","---*","----","--*-","-*--","-**-","**-**","**--",
"*-*-",
"*----","**---","***--","****-","*****","-****","--***","---**","----*","-----",
"......","*-*-*-","---***","-*-*-","-*--*-","*----*","*-**-*","-****-","-**-*","**--**","--**--",
"-***-","********","*--*-*","**-*-",
""
};
// Кириллическая раскладка.
char* layoutCyrillic[] = {
"а","б","в","г","д","е","ж","з","и","й",
"к","л","м","н","о","п","р","с","т","у",
"ф","х","ц","ч","ш","щ","ы","ь","э","ю",
"я",
"1","2","3","4","5","6","7","8","9","0",
".",",",":",";","(","'",""","-","/","?","!",
" *DELIMITER* "," *ERR* ","@"," *END* ",
""
};
// Латинская раскладка.
char* layoutLatin[] = {
"a","b","w","g","d","e","v","z","i","j",
"k","l","m","n","o","p","r","s","t","u",
"f","h","c","ö","ch","q","y","x","é","ü",
"ä",
"1","2","3","4","5","6","7","8","9","0",
".",",",":",";","(","'",""","-","/","?","!",
" *DELIMITER* "," *ERR* ","@"," *END* ",
""
};
char** currentLayout;
char** newLayout;
void setup(){
Serial.begin(9600);
pinMode(led, OUTPUT);
morseSymbolLen = 0;
newMorseSignal = MORSE_EMPTY;
}
int counter_high = 0;
int counter_low = 0;
int i;
void loop(){
int LDRReading = analogRead(LDR_Pin);
if (LDRReading >= 800){
counter_high++ ;
if ( counter_low > 0 ){
// Serial.print("Lowt");
// Serial.print(counter_low);
// Serial.print("n");
}
if ( counter_low > 1200) {
// for (i = 0; i< morseSymbolLen; i++) {
// Serial.print( currentLayout[i]);
// }
sendMorseSymbol();
morseSymbolLen=0;
Serial.println();
//currentLayout[0]=" ";
//currentLayout[1]=" ";
//currentLayout[2]=" ";
//currentLayout[3]=" ";
//currentLayout[4]=" ";
//currentLayout[5]=" ";
//currentLayout[6]=" ";
//currentLayout[7]=" ";
//currentLayout[8]=" ";
//morseSymbolLen=0;
}
counter_low=0;
digitalWrite(led, HIGH);
} else {
// Serial.print(".");
counter_low++;
if ( counter_high > 0 ){
// Serial.print("Hight");
// Serial.print(counter_high);
}
if ( (counter_high < 1200 ) &&( counter_high >350)){
// Serial.print(counter_high);
Serial.print(".");
newMorseSignal="*";
morseSymbol[morseSymbolLen++] = newMorseSignal;
// currentLayout[morseSymbolLen]=".";
// morseSymbolLen=morseSymbolLen+1;
}
if ( counter_high > 1200 ){
// Serial.print(counter_high);
Serial.print("-");
newMorseSignal="-";
morseSymbol[morseSymbolLen++] = newMorseSignal;
// currentLayout[morseSymbolLen]="-";
// morseSymbolLen=morseSymbolLen+1;
}
counter_high=0;
digitalWrite(led, LOW);
}
}
void sendMorseSymbol() {
boolean est;
int i, j;
est=-1;
if (morseSymbolLen < 1) {
return;
}
Serial.print(morseSymbolLen);
// Символ из таблицы кодов Морзе соответствует введенному символу.
// Отправим символ на компьютер.
String str1;
String strm;
str1="";
for (i=0;i<morseSymbolLen;i++){
str1=str1+morseSymbol[i];
}
// Serial.print(code[6]);
for (i=0;i<56;i++){
String str2(code[i]);
if (str1.compareTo(str2)==0){
//Serial.print(str1);
// Serial.print("est");
Serial.print(str2);
est=true;
break;
}
}
if (est!=-1){
Serial.print(layoutLatin[i]);
}
morseSymbolLen = 0;
return;
}
Приемник с LCD экраном
Полученные данные выводятся в COM порт, это конечно здорово, но не наглядно и требует наличие включенного компьютера. Поэтому подключаем 2 строчный экран с I2C подключением:
Для экрана SDA подключаем ногу arduino UNO A5, SCL – A4, VCC экрана к 5V, GND к GND:
Добавляем в скетче приемника receiver.ino строки отвечающие за вывод на 2 строчный LCD экран. Можно теперь уйти в поле с компактным приемником и прочитать сообщение прямо с LCD экрана.
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
// Define I2C Address where the PCF8574* is
#define I2C_ADDR 0x27
// Define LCD Pins
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
// Initialize LiquadCrystal with pin setup
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
int pos_lcd,pos_lcd2;
int LDR_Pin = A0; //analog pin 0
int led = 13;
// 10k between GND and A0
// LDR between 5V and A0
// настроить чувствительность фотоэлемента
#define LEVEL_LDR 800
#define MORSE_EMPTY 0
// Этими символами мы будем обозначать точки и тире.
#define MORSE_DOT '*'
#define MORSE_DASH '-'
//Длина точки и тире для 24 слов в минуту (wpm) = 150 мс и 700 мс,
// Для 12 wpm = 700 и 1200
#define MORSE_TIME_DOT 150
#define MORSE_TIME_DASH 700
// Максимальная длина символа азбуки Морзе (в точках и тире)
#define MAX_MORSE_SYMBOL_LENGTH 8
char* morseSymbol[MAX_MORSE_SYMBOL_LENGTH];
unsigned int morseSymbolLen;
char* newMorseSignal; // Новый введенный сигнал - точка или тире.
// Таблица кодов Морзе. N-ный элемент кода соответствует n-ному символу раскладки.
char* code[] = {
"*-","-***","*--","--*","-**","*","***-","--**","**","*---",
"-*-","*-**","--","-*","---","*--*","*-*","***","-","**-",
"**-*","****","-*-*","---*","----","--*-","-*--","-**-","**-**","**--",
"*-*-",
"*----","**---","***--","****-","*****","-****","--***","---**","----*","-----",
"......","*-*-*-","---***","-*-*-","-*--*-","*----*","*-**-*","-****-","-**-*","**--**","--**--",
"-***-","********","*--*-*","**-*-",
""
};
// Кириллическая раскладка.
char* layoutCyrillic[] = {
"а","б","в","г","д","е","ж","з","и","й",
"к","л","м","н","о","п","р","с","т","у",
"ф","х","ц","ч","ш","щ","ы","ь","э","ю",
"я",
"1","2","3","4","5","6","7","8","9","0",
".",",",":",";","(","'",""","-","/","?","!",
" *DELIMITER* "," *ERR* ","@"," *END* ",
""
};
// Латинская раскладка.
char* layoutLatin[] = {
"a","b","w","g","d","e","v","z","i","j",
"k","l","m","n","o","p","r","s","t","u",
"f","h","c","ö","ch","q","y","x","é","ü",
"ä",
"1","2","3","4","5","6","7","8","9","0",
".",",",":",";","(","'",""","-","/","?","!",
" *DELIMITER* "," *ERR* ","@"," *END* ",
""
};
void setup(){
Serial.begin(9600);
pos_lcd=0;
lcd.begin (16,2);
// Switch on the backlight
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
lcd.setBacklight(HIGH);
// Reset cursor to home
lcd.home ();
// Print Hello World
// lcd.print("GOTOV priem");
pinMode(led, OUTPUT);
morseSymbolLen = 0;
newMorseSignal = MORSE_EMPTY;
}
int counter_high = 0;
int counter_low = 0;
int i;
void loop(){
int LDRReading = analogRead(LDR_Pin);
if (LDRReading >= LEVEL_LDR){
counter_high++ ;
if ( counter_low > MORSE_TIME_DASH) {
sendMorseSymbol();
morseSymbolLen=0;
}
counter_low=0;
digitalWrite(led, HIGH);
} else {
counter_low++;
if ( (counter_high < MORSE_TIME_DASH ) &&( counter_high >MORSE_TIME_DOT)){
Serial.print(".");
newMorseSignal="*";
morseSymbol[morseSymbolLen++] = newMorseSignal;
}
if ( counter_high > MORSE_TIME_DASH ){
Serial.print("-");
newMorseSignal="-";
morseSymbol[morseSymbolLen++] = newMorseSignal;
}
counter_high=0;
digitalWrite(led, LOW);
}
}
void sendMorseSymbol()
{
boolean est;
int i, j;
est=-1;
if (morseSymbolLen < 1)
{
return;
}
// Символ из таблицы кодов Морзе соответствует введенному символу.
// Отправим символ на компьютер.
String str1;
str1="";
for (i=0;i<morseSymbolLen;i++)
{
str1=str1+morseSymbol[i];
}
for (i=0;i<56;i++)
{
String str2(code[i]);
if (str1.compareTo(str2)==0)
{
Serial.print(str2);
est=true;
break;
}
}
if (est!=-1)
{
Serial.print(layoutLatin[i]);
// Вывод символа на LCD экран
if (pos_lcd>16 )
{
Serial.print("vtorayStroka");
pos_lcd2=pos_lcd-17;
Serial.print(pos_lcd);
lcd.setCursor(pos_lcd2,1 ); //Пишем в LCD на 2 строк
}
pos_lcd=pos_lcd+1;
if (pos_lcd>32)
{
lcd.clear();
pos_lcd=0;
}
lcd.print(layoutLatin[i]);
lcd.setBacklight(HIGH); // Backlight on
}
morseSymbolLen = 0;
return;
}
Итоги
Данный способ передачи успешно работал у меня как и в комнате вечером на расстоянии 0,5–3 метра, так и вечером на улице на расстоянии 7–14 м. Большие расстояния пока не были опробованы. Передача днем потребует светозащищенной трубы чтобы на фотоэлемент не падал солнечный и дневной свет, а только свет от лазера или нужно поиграться параметром LEVEL_LDR отвечающий за чувствительность к свету в скетче приемника.
Источники
- Arduino Morse Code Sender/Receiver pair using lasers
- Знакомство с Arduino, часть 2. Морзе-клавиатура: альфа-версия
- Знакомство с Arduino, часть 3. Морзе-клавиатура: бета-версия
- Фонарик Морзе
- Morse Code Laser Transceiver
- Send Your Secret Spy Messages Wirelessly Through Light with This DIY Laser Audio Transmitter
- Laser Transceiver (laser data link)
- Raspberry Pi & Arduino: a laser pointer communication and a LDR voltage sigmoid
Автор: Syzd