Увидев статью о том, как один человек использовал клавиатуру в качестве программатора AVR-микроконтроллеров, я воскликнул: «Да он безумец!». А потом подумал, а чем же я хуже?.. И решил написать эту статейку о безумном способе передачи информации из ПК в микроконтроллер.
Вся суть состоит в том, что на экран выводятся квадраты, которые могут быть окрашены в белый, либо чёрный цвет, то есть иметь два состояния. Как биты. И их восемь штук. Как байт.
Чем отличается чёрный цвет от белого? Забавно, но не цветом, а яркостью, интенсивностью света. Интенсивность белого много больше интенсивности чёрного. В качестве регистратора интенсивности я использовал самое простое специально предназначенное для этого устройство — фоторезистор. Фоторезисторами называют полупроводниковые приборы, проводимость которых меняется под действием света. В моём случае проводимость затемнённого фоторезистора много меньше проводимости освещённого. Подключение фоторезистора к микроконтроллеру выбрал самое простое — между пином и землёй, включив встроенную подтяжку к питанию. Проверил напряжение, которое получает АЦП МК ATMega8: слева фоторезистор смотрит на белый фон, справа на чёрный. Напряжение в вольтах.
Да, да — Arduino IDE. Потому-что там я могу быстро набросать код и сразу залить его в плату нажатием одной кнопки, использовать обкатанные и растолкованные до безумия библиотеки.
Как видно, при считывании в цифровом режиме, мы получим 0 на белом и 1 на чёрном, что несколько идёт в разрез с моими шаблонами (чёрный ноль и белая единица), зададим чёрную единицу в программе на ПК.
Для вывода информации на монитор в необходимом нам представлении была написана простая программа на Си — Opto_Байт. Написал её по моей просьбе сосед по общежитию — kinetik161, за что ему большое спасибо и литр пива молока. Программа имеет ввод значения в десятичной системе счисления от 0 до 255 ( (2^8)-1 ) через поле ввода и через текстовый файл TEXT.txt. Текстовый файл располагается в том же каталоге, что и исполняемый файл, каждое значение вводится с новой строки, при достижении конца списка вывод значений останавливается. Интервал — 1 секунда. Имеется кнопка инверсии.
Использовал микроконтроллер ATMega8, который в DIP28 корпусе имеет два полноценных (8 битных) порта — порт B и порт D. На порте B висит кварцевый резонатор, на D — UART. В итоге, я использовал безумную солянку портов, из которых потом составлял один байт. Подключение фоторезисторов от старшего разряда к младшему, слева направо: PC3, PC2, PC1, PC0, PB2, PB1, PB0, PD7.
Быстренько собрал всё на макетной плате и окончательно проверив работу с отправкой данных обратно по com-порту, я решил подключить знакосинтезирующий ЖК экран для вывода информации. Прилагаю код для Arduino IDE.
#include <Wire.h> // Подключаем библиотеки
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x20, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE); // Настройка подключения дисплея(есть разные)
int led = 2; // Указываем пин светодиода
byte data = 0; // Полученный байт
byte dataold = 170; // Предыдущий байт
byte k=0; // Переменная для красивого форматирования байта на LCD
void setup() {
lcd.begin (16,2); // Инициализация экрана
lcd.setBacklight(1); // Включить подсветку
lcd.print("Hello, Geektimes"); // Приветствие
lcd.setCursor(2, 1); // Сдвиг курсора
lcd.print("from NikitosZs");
// Serial.begin(9600); // Инициализация UART
DDRC = DDRC & 0b11110000; // Задаём порты ввода/вывода
DDRB = DDRB & 0b11111000;
DDRD = DDRD & 0b01111111;
PORTC = PORTC | 0b00001111; // Включаем подтяжку фоторезисторов
PORTB = PORTB | 0b00000111;
PORTD = PORTD | 0b10000000;
pinMode(led, OUTPUT); // Индикатор приветствия
digitalWrite(led, 1);
delay(2000); // Держим приветствие на экране
lcd.clear(); // Очищаем экран
digitalWrite(led, 0); // Индикатор приветствия выключен
}
void loop() {
data = get(); // Присваиваем переменной data текущий байт
if(data!=dataold) // Перерисовываем информацию на экране, если байт изменился
{
// Serial.println(data); // Отправляем байт в терминал
lcd.setCursor(1, 0);
lcd.print("DEC:");
lcd.setCursor(6, 0);
lcd.print(" "); // Очищаем локальную область
lcd.setCursor(6, 0);
lcd.print(data);
lcd.setCursor(1, 1);
lcd.print("BIN:");
lcd.setCursor(6, 1);
lcd.print("00000000"); // Создаём правильную подложку
if(data>127) k=0; // Определяем старший бит для сдвига
else if(data>63) k=1;
else if(data>31) k=2;
else if(data>15) k=3;
else if(data>7) k=4;
else if(data>3) k=5;
else if(data>1) k=6;
else k=7;
lcd.setCursor(6+k, 1);
lcd.print(data, BIN);
dataold=data; // Присваеваем значение байта переменной хранящей предыдущее значение
}
}
byte get(){
byte raw=1, rawold=0; // Локальные переменные raw и rawold
while(raw != rawold) // Выполняется, пока не равны (для устойчивости значения)
{
rawold = raw; // Сохраняем старое значение
byte data1 = 0b10000000 & PIND; // Считываем солянку из пинов
byte data2 = 0b00000111 & PINB;
byte data3 = 0b00001111 & PINC;
raw = data3 << 4; // Сдвигаем, создаём целый байт
raw = raw + (data2 << 1);
raw = raw + (data1 >> 7);
}
return raw; // Возвращаем готовый байт
}
Выполним проверку правильной адресации фоторезисторов с битами, закрывая источник света пальцем. Должно получиться следующее:
И так-как всё получилось, то можно прислонять макетную плату с фоторезисторами к экрану компьютера. Длинноногие фоторезисторы, воткнутые в макетную плату, нехотя, но всё же согласились никуда не убегать на время съёмки видео, хотя позиционировать их было не очень просто.
Теперь немного занудства… По сути монитор это управляемый транспарант (матрица световых вентилей, возбуждаемых некоторыми внешними сигналами: электрическими, акустическими, оптическими, магнитными). Каждый квадратик — бит — занимает площадь 60*60 пикселей (50 — сторона квадрата и 10 — промежуток). Я имею монитор с разрешением 1920*1080 пикс, частота 60Гц. 1920/60=32 квадрата по ширине, 1080/60=18 квадратов по высоте, 32*18=576 бит на кадр. Не вдаваясь в тонкости, в секунду мы сможем рисовать 60 кадров, а это 576*60=34560 бит/с или 4320 Байта/с. Сократив размер квадратов до 30 пикселей по стороне, получим четырёхкратный прирост скорости (17280Б/с). К сожалению, если уменьшать дальше, то наши каналы будут засвечивать друг друга.
Конечно же я не собираюсь использовать этот оптоэлектронный канал связи, так-как есть куда более удобные, быстрые и менее затратные способы коммуникации, не занимающие рабочее место на мониторе. Однако, не стоит забывать, что самые обыденные вещи можно использовать совсем непривычным для нас способом.
Автор: NikitosZs