Показаны сообщения с ярлыком управление с компьютера. Показать все сообщения
Показаны сообщения с ярлыком управление с компьютера. Показать все сообщения

суббота, 10 февраля 2024 г.

Переделка дальта 3D принтера в лазерный ЧПУ гравер

 FDM 3D принтеры стали популярными ЧПУ станками для изготовления прототипов а также даже производства настоящих полнофункциональных изделий и деталей в основном из пластмассы. Чаще всего 3D принтеры делают детали из PLA или ABS пластиков которые весьма дорогие (на момент написания данной стати) в состоянии прутка пригодного для FDM 3D принтера. Большинство FDM 3D принтеров легко переделать в лазерный гравер путем замены экструдера пластика на лазер. Для лазера (в отличии от например фрезера) не нужна жесткая конструкция + 3D принтер может менять фокусировку лазера в процессе работы, чего не могут даже некоторые лазерные граверы. Чтобы переделать 3D принтер в лазерный гравер нужно заменить хотенд принтера на лазерный модуль. Лазерные модули бывают разные. Лазеры бывают разных типов и мощностей. Самые дешёвые, компактые и легкие - это полупроводниковые лазеры они также уступают по мощности например CO2 лазерам но зато + к меньшим габаритам они имеют меньшую стоимость и могут быть установлены на дельта 3D принтеры типа Rostock mini. Обычно дельта на дельта принтеры не устанавливаются тяжелые головки но практика показала лазерный модуль оптической мощностью 5Вт (потребляемая мощность 40Вт) способный резать фанеру и пластик а также гравировать большинство материалов может работать с принтером Rostock mini.

Данный лазерный модуль имеет радиатор, вентилятор для охлаждения и одновременно сдувания дыма от разрезаемой поверхности для улучшения прохождения лазера до этой самой поверхности а также есть сопло которое направляет поток воздуха в разрезаемую точку чтобы лучше сдувать дым. Также есть защитная красная насадка для защиты глаз (на которую не стоит сильно полагаться) и плата управления с тремя выводами. Один вывод питания +12В, второй - земля GND 0В и вывод управления на который подается ШИМ с уровнями напряжения 0В и +5В. В комплекте шел кабель с разъемами. В кабеле 3 провода: красный +12В питания, черный 0В, желтый - ШИМ 0...+5В. Питание подключается к источнику от которого питается принтер. А желтый провод к одному из пинов контроллера RAMPS но только не к тому с которого выходит 12В например стола или вентилятора т.к. эти пины сожгут испортят плату. Нужен именно управляющий пин. Это может быть например свободный пин D4


 который предназначен для подключения сервомотора но также его можно использовать как обычный свободный GPIO командой например M42:

M42 P4 S150 ; включить пин D4 на гребенке с сервами с краю с ШИМом 150

Где M42 - это название команды, P4 - номер пина, S150 - уровень шима который м.б. от 0 (лазер полностью выключен и не работает) до 255 (лазер полностью включен и работает на пределе). К сожалению в прошивке Мерлина данная команда не синхронизированна с командой G1 перемещения головки в пространстве, поэтому резка и гравировка не будут точными а также в варианте прошивки для дельта принтера вообще нет команды с синхронизированной работой лазера и перемещением головки. К счастью данная прошивка является скетчем для ардуины Меги который можно подправить. Можно например добавить собственный нестандартный G код с синхронизацией лазера и перемещения головки в пространстве. Что и было сделано. В прошивке Мерлина есть файл "Configuration.h" в который вносятся изменения для настройки принтера. В данном файле изменяются специальные константы которые специально вынесены в данный файл для пользователя чтобы было удобнее и безопаснее чтобы не испортить случайно всю прошивку но добавить новую команду через этот файл нельзя. Добавить её можно в файле "Marlin_main.cpp". В данном файле есть функция "void process_commands()" внутри которой есть ветвление "switch((int)code_value())" внутри которого есть команды. Было замечено что в прошивке для дельта принтера Rostock mini G команды заканчиваются на G4 потом идет перерыв и начинаются с G10 которые заканчиваются на M командах. Для G команд и M команд существует какой общепринятый то стандарт и команда с синхронизацией должна иметь специальное обозначение что возможно позволит использовать для генерации кодов какую либо готовую программу. Однако поскольку для полного понимания прошивки и изучения стандарта нужно тратить время то для ускорения и упрощения можно просто добавить новую команду по аналогии с какой либо имеющейся и написать генератор G кодов самостоятельно. Чтобы добавить новую команду G5 нужно скопировать код:

и вставить после обработчика команды G4. Пример использования новой самодельной команды
 G5 X0 Y0 Z73 F300 P4 S150
означает переместиться в точку X0 Y0 Z73 со скоростью 300 и включить пин D4 с шимом 150.

Адрес биткоин кошелька для поддержки канала - bc1qlhrmmkh77x2lzhqe4lt9qwkglswj64tsqt2l5g

среда, 12 августа 2020 г.

Прием по uart на ассемблере для ATtiny2313

 Интерфейс uart (универсальный асинхронный приемник передатчик) часто используется для связи разных устройств друг с другом. Например для связи компьютера с микроконтроллером или микроконтроллера с например радиомодулем или другим микроконтроллером, модулем или микросхемой. Изучив uart микроконтроллера ATtiny2313 можно будет заменить Ардуино, в некоторых случаях, этим микроконтроллером. Чтобы изучить uart можно например поставить какую нибудь задачу например зажечь светодиод подключенный к микроконтроллеру передав ему какой либо код по uartу тогда в процессе решения этой задачи придет понимание того как использовать этот интерфейс. Светодиод, в таком случае, нельзя подключить к нулевому или первому пину порта D т.к. эти пины являются пинами uartа микроконтроллера ATtiny2313. Его можно подключить например к нулевому пину порта B


Рисунок 1 - Схема

В схему добавлены разъемы для того чтобы микроконтроллер можно было соединить с программатором чтобы зампрограммировать а потом отсоединить от программатора и соединить с usb-uart переходником для передачи информации на микроконтроллер от компьютера. Кварцевого резонатора в схеме нет. Практика показала что uart может работать и без него. uart - это асинхронный интерфейс т.е. передатчик передает биты через какие то определенные промежутки времени а приемник должен принимать биты через промежутки времени такие же. Иначе приемник будет принимать не то что нужно. К счастью некотарая доля синхронности в этом интерфейсе есть т.к. запускается прием только после возникновения запускающего импульса и асинхронность присутствует только в течении приема одного байта информации (если uart настроен на один байт т.е. 8 бит). Поэтому uart может работать при некотором небольшом несовпадении частот. Чем меньше скорость передачи тем больше может быть это несовпадение. Чтобы это несовпадение было почти нулевым и микроконтроллер мог работать по uartу на очень больших скоростях и очень стабильно и наверняка надежно, нужны специальные кварцевые резонаторы, например не на 1 или 2 МГц а на 1.8432 МГц для того чтобы время тактового импульса было кратным времени одного импульса по стандартам для uart. Естественно uart будет работать и при обычных кварцевых резонаторах (на Ардуине же он как то работает при кварцевых резонаторах с резонансной частотой 16 МГц). В данном случае для простоты мы не будем использовать такие редкие кварцевые резонаторы а используем внутренний rc генератор микроконтроллера с установленной по умолчанию на заводе частотой 1 МГц. Практика показала что uart при этом работает а также при такой частоте микроконтроллер может работать и при пониженном напряжении что позволяет его использовать например при питании от одной ячейки LiFePO4 аккумулятора что удобно для изготовления каких нибудь маленьких радиоуправляемых игрушек или роботов. Рассмотрим ассемблерный код программы:



Первые 4 команды а также инициализация стека, настройка пина на выход были рассмотрены в предыдущих уроках. Адрес ячейки памяти на которую переводиться выполнение программы после того как сработало прерывание по приему байта называется URXCaddr. После того как это прерывание возникло команда RJMP переводит выполнение программы на подпрограмму обработки прерывания. Но чтобы это смогло произойти сначала нужно настроить uart микроконтроллера для этого (а точнее для нашей текущей задачи) есть 5 регистров. Причем в данном случае 2 из них можно даже не трогать. Для начала можно настроить скорость. Слишком большую выбирать нельзя чтобы uart нормально работал. Можно выбрать например 9600 - эта скорость часто используется и подходит во многих случаях. Настраивается скорость через регистры UBRRL и UBRRH. В эти регистры нужно записать число соответствующее нужной нам скорости. Если это число больше 255 то надо младшие разряды этого числа записать в регистр UBRRL а старшие в UBRRH. Если меньше то можно это число записать в UBRRL а UBRRH не трогать вообще т.к. там нули по умолчанию. Чтобы определить это число не обязательно его рассчитывать по формулам. Можно просто найти его из таблицы в документации на микроконтроллер:

Также из этой таблицы видно что в нашем случае можно получить меньшую ошибку если установить бит удвоения скорости в единицу. Находиться этот бит в регистре UCSRA там он под номером 1 (самый первый это нулевой). После того как 3 регистра настроены осталось ещё 2. Разрешить прием байта и прерывание по завершению приема можно настройкой UCSRB. Чтобы разрешить прием, в единицу устанавливается бит 4 этого регистра, чтобы разрешить прерывание по приему, в единицу устанавливается бит 7 этого регистра. Последний регистр UCSRC надо настроить так чтобы принимать по 8 бит. Обычно так всегда и делается но в некоторых случая можно сделать по другому. Чтобы настроить прием 8ми бит нужно в записать единицы в бит 1 и бит 2 регистра UCSRC. Хотя этого можно было бы и не делать т.к. там по умолчанию и так имеются единицы:

Но зато теперь если вдруг понадобиться изменить количество принимаемых бит известно как это сделать. Далее в программе настраивается пин к которому подключен светодиод и разрешаются все прерывания. В основном цикле опять ничего интересного (хотя можно его заполнить например динамической индикацией или ещё чем нибудь). Когда бит приходит по uartу и возникает прерывание нужно вытащить из регистра UDR этот бит и поместить в какой либо регистр общего назначения например R18. Далее командой сравнения CPI и командой условного перехода если не равно BRNE сделать ветвление и организовать зажигание светодиода когда пришел ASCII код символа "a" и гашение светодиода когда пришел ASCII код символа "b". ASCII коды всех символов можно узнать из таблицы ASCII кодов всех символов:

Команда RETI делает выход из подпрограммы обработки прерывания. О том как откомпилировать программы и загрузить её в микроконтроллер можно узнать из предыдущих уроков. Если компиляция и загрузка прошли успешно то можно подключить микроконтроллер к компьютеру через usb-uart переходник и попробовать зажечь светодиод. Отправить какой либо символ с компьютера через переходник можно используя например Arduino IDE или же это можно сделать через командную строку. Если на компьютере обычная ОС Winows напр. 7 то например командой 

mode COM3 BAUD=9600 PARITY=n DATA=8

Можно настроить этот переходник на нужную скорость и количество бит. Вместо COM3 нужно вписать название своего com порта который появляется после втыкания переходника в usb разъем. Отправить символ а можно командой

echo a > COM3

символ b соответственно командой

echo b > COM3

Вместо COM3 нужно вписать название своего com порта который появляется после втыкания переходника в usb разъем. После написания команды надо нажимать Enter чтобы символ отправился. В моем случае всё сработало, можно убедиться в этом посмотрев видео:


воскресенье, 5 ноября 2017 г.

3D сканер пространства ультразвуковой на ардуино своими руками

3D сканеры пространства могут использоваться например в роботах. Такие сканеры создают 3D карту пространства для того чтобы робот мог ориентироваться в нём. Робота способного ориентироваться в пространстве и имеющего 3D сканер сделать гораздо проще чем робота способного ориентироваться в пространстве и имеющего только видеокамеру т.к. видеокамера, сама по себе, не даёт готовую информацию о расположении объектов пространства относительно робота. Обычно в 3D сканерах для роботов используются лазерные дальномеры. 3D сканеры с лазерными дальномерами называются ЛИДАРами. Лазерные дальномеры очень дорогие и поэтому самостоятельное изготовление ЛИДАРа, в домашних условиях, является большой проблемой. В качестве альтернативы можно попробовать использовать ультразвуковой дальномер который гораздо хуже лазерного но зато гораздо дешевле него. Вращая дальномер и делая замеры расстояний при разных углах можно составить 3D карту пространства. Для вращения дальномера можно использовать сервомоторы. Сделать такой сканер можно на ардуино (http://ali.pub/1zj4xl, http://ali.pub/1zj4xl), двух сервомоторах SG90 (http://ali.pub/1zj4ag, http://ali.pub/1zj3nw) и одном датчике hc-sr04 (http://ali.pub/1zj2ph, http://ali.pub/1zizvz)
Рисунок 1 - 3D сканер ультразвуковой

Ардуино имеет небольшую встроенную память для хранения информации поэтому целесообразно передавать отсканированные расстояния сразу на компьютер. Скетчь:
Скачать скетч можно по ссылке https://yadi.sk/d/-Ulj_ggR3PRjje
Для того чтобы использовать данный скетч нужно сначала подключить библиотеку new ping, о том как это сделать можно посмотреть на странице http://electe.blogspot.ru/2015/07/arduino.html

 Программа для вывода графики:

цифры с монитора последовательного порта
BEGIN_H_ANGLE
END_H_ANGLE
BEGIN_V_ANGLE
END_V_ANGLE


КАРТА БЛОГА (содержание)

суббота, 12 августа 2017 г.

ЧПУ пенопласторез

Дельта 3D принтер например Rostock mini или др. подобный можно переделать для выполнения других действий заменив экструдер другим инструментом. Потом инструмент можно снять и экструдер установить обратно. Обычно конструкция 3D принтера недостаточно прочная для того чтобы его можно было переделать принтер например во фрезерный станок но для работ не требующих большой прочности 3D принтер может подойти. Для резки пенопласта прочности будет вполне достаточно. Пенопласт сам по себе не очень прочный материал и мало где может быть применён но можно использовать пенопластовые формы для изготовления металлических изделий, для этого пенопластовая форма с двумя пенопластовыми цилиндрами прикреплёнными к ней покрывается глиной так чтобы цилиндры немного торчали наружу. Если заливать расплавленный метал в один из цилиндров то пенопласт будет плавиться. Расплавленный пенопласт с газами выйдет через отверстие оставленное вторым цилиндром а металл заполнит пространство которое ранее занимал пенопласт. Эта технология называется "литьё по газифицируемым моделям". Сделать инструмент для резки пенопласта не трудно. Для этого например можно вырезать из деревяшки форму ввиде русской буквы "П", после чего прикрутить к двум её концам винты между которыми можно протянуть проволоку из нихрома. Если на проволоку подать напряжение то она нагреется и ей можно будет резать пенопласт. Такой инструмент можно приделать к 3D принтеру вместо экструдера. Кое что ещё посмотреть про ЧПУ пенопласторез и увидеть как он работает можно на видео:

Про источник питания для нихромовой проволоки на странице: http://electe.blogspot.com/2015/03/top243.html
Если делать источник питания самому не хочется а пенопласторез нужен то можно подобрать и за недорого купить готовый по на сайте по ссылке -> http://alii.pub/6cpxhd

КАРТА БЛОГА (содержание)

воскресенье, 18 сентября 2016 г.

Как печатать на 3D принтере.

3D принтеры печатающие пластиковые изделия методом послойного наплавления (FDM или FFF) являются станками с ЧПУ (числовым программным управлением). Как и для всех остальных станков с ЧПУ для 3D принтеров существует специальный язык программирования, в большинстве случаев это G-код. Контроллер почти любого 3D принтера распознаёт и выполняет G-коды. G-коды занимают большой объём в памяти компьютера и слишком сложны для того чтобы создавать ими инструкции принтеру для печати изделий поэтому обычно форма будущего изделия создаётся в каком либо графическом редакторе (например Blender) после чего сохраняется в формате STL в котором храниться, передаётся и.д. а если возникает необходимость напечатать изделие то специальные программы слайсеры (например Slic3r) создают G-коды по этой модели непосредственно перед печатью. Не смотря на это знание G-кода всё таки может пригодится человеку использующему 3D принтер т.к. возможности слайсеров ограничены. Необходимо также учитывать то что для 3D принтеров наборы выполняемых ими команд, в большинстве случаев, различаются между собой. Например дельта принтеры с прошивкой Marlin не могут выполнять команду G2 т.е. нет специальной команды для того чтобы делать круги поэтому их, в таком случае, необходимо делать линиями используя команду G1 для рисования линий. Список всех команд поддерживаемых принтерами RepRap можно посмотреть на странице http://reprap.org/wiki/G-code. Теперь давайте рассмотрим простейший набор команд для печати пластиковой полоски длинной 10 мм:

M104 S220 ;установить температуру экструдера 220 градусов цельсия
M109 S220 ;не делать ничего пока не установиться температура 220 градусов
G28 ;вернуть сопло в исходное положение
G1 X0 Y0 Z0 E0 F500 ;опустить сопло к центру поверхности печати
G1 X10 Y0 Z0 E5 F200 ;напечатать полоску
M104 S220 ;отключить нагреватель экструдера
G28

В данном языке как и в большинстве остальных имеется возможность делать комментарии - надписи игнорируемые транслятором и предназначенные для пояснений. Комментарии пишутся после точки с запятой (т.е. это не конец команды а начало комментария (концом является перевод строки (как в питоне))). Назначение первых трёх команд понятно из комментариев. 
M104 -установить температуру экструдера,
M109 -не делать ничего пока не установиться температура написанная после знака "S",
S28 -возврат в исходное положение,
Четвёртую команду рассмотрим подробнее. G1 - это команда для создания линий (наиболее часто используемая). После надписи "G1", через пробелы, задаются координаты точки в которую необходимо переместить сопло из которого будет выходить пластик. В большинстве принтеров используется декартова система координат знакомая всем из школьного курса математики. Координата Z используется для вертикального перемещения, остальные две X и Y -для горизонтального. Числа стоящие после знаков X,Y или Z в миллиметрах и могут быть десятичными и/или отрицательными, при этом необходимо учитывать то что сопло может переместиться не в любую точку пространства и в случае неправильного задания координат можно сломать принтер поэтому необходимо следить за тем чтобы значения не выходили за допустимые пределы области печати и всегда держать "под рукой" кнопку аварийной остановки. После знака "E" пишется то на сколько миллиметров втянется пластиковый шнур в экструдер. Если например надо втянуть сначала 10 мм и потом тоже 10 мм то в первый раз пишется E10 а во второй E20 т.е. Е - это как ещё одна координата которая как бы указывает на то на сколько миллиметров надо переместить пластиковый шнур. После знака "F" указывается скорость перемещения сопла и втягивания шнура в миллиметрах в минуту.
По аналогии с данным простым примером G-кодами можно создавать и более сложные изделия. Также знание G кодов будет полезно для настройки 3D принтера.
Видео для данной статьи:
Проверка проводилась на 3D дельта принтере Rostock mini самостоятельного изготовления.
Пластиковые детали для были заказаны на странице http://ali.pub/py0zf
линейные подшипники
http://ali.pub/pq6m3
радиальные подшипники
http://ali.pub/uzqx3
шкивы с ремнём
http://ali.pub/hal0p
http://ali.pub/mcfve (докуплено немного ремня)
хотэнд
http://ali.pub/lhvc3
боуден экструдера (толкатель пластмассы без двигателя)
http://ali.pub/ax7ts
PLA пластик
http://ali.pub/tkpyd
Про источник питания и контроллер смотрите видео:
Как показала практика, самостоятельная сборка 3d принтера -это увлекательное и интересное занятие но оно отнимает много времени и к тому же не даёт (если вообще даёт) сколько нибудь значимого выигрыша в цене т.к. готовые 3d принтеры (на момент написания данной статьи) имеют небольшую цену а запчасти к ним высокую, поэтому покупка готового 3d принтера избавит от множества проблем. Если выбрать более простой путь то можно приобрести такой же RepRap 3d принтер как и Rostock mini, такие принтеры дёшевы (возможно из за того что их многие собирают самостоятельно) и если с ним случиться поломка то его легко можно будет отремонтировать по доступным и многочисленным инструкциям из интернета а часть деталей вообще можно напечатать на нём самом пока он работает.

 http://ali.pub/grkhq


КАРТА БЛОГА (содержание)

четверг, 5 мая 2016 г.

USB клавиатура из обычной PS2 (ps/2 to usb converter).

Порт PS/2, до широкого распространения USB, устанавливался в большинстве системных боков компьютеров для взаимодействия этого блока с клавиатурой. После широкого распространения USB, порт PS/2 стал очень редко использоваться и в современных ноутбуках и компьютерах таких портов почти не осталось поэтому, в большинстве случаев, использовать клавиатуру со старым разъёмом PS/2 можно только применяя специальный переходник PS/2 - USB. Протокол PS/2 сильно отличается от протокола USB поэтому нельзя так просто взять и перепаять с разъёма PS/2 на USB и надеяться что это сработает. PS/2 - это простой синхронный последовательный интерфейс не имеющий больших вступительных и заключительных данных, можно даже сказать (не сильно ошибившись) что передача по PS/2 - это просто поток битов (примерно как по SPI). Частота импульсов синхронизации невелика с составляет несколько десятков килогерц. Уровень логической единицы в PS/2 равен 5В, логического нуля 0В. В общем интерфейс PS/2 достаточно прост для того чтобы его можно было самостоятельно реализовать программно на микроконтроллере. Интерфейс USB гораздо сложнее и его программная реализация - это задача очень нетривиальная и требующая большого объёма работы но к счастью для нас одна Австрийская фирма (Objective Development) выпустила библиотеку v-usb с лицензией GNU GPL т.е. бесплатной для коммерческого и некоммерческого использования, а это значит что библиотекой v-usb можно пользоваться бесплатно. Также существует вариант данной библиотеки для Arduino а это значит что написать код для взаимодействия с компьютером по USB можно буквально в несколько строк что сильно упрощает жизнь. Для клавиатуры PS/2 также существует библиотека и при том не одна и использовать их можно на Arduino. Одной из таких библиотек является библиотека PS2KeyAdvanced которую написал Paul Carpenter. По идее всё должно быть просто но использовать две библиотеке в одном скетче для Arduino не получается т.к. они обе используют внешние прерывания. Переделать библиотеку PS2KeyAdvanced для работы без прерываний можно но при этом коды нажатых клавиш будут определяться не всегда поэтому самым простым выходом в данном случае является использование 2х плат Arduno каждая из которых будет "заниматься своим делом" т.е. одна Arduino будет принимать данные с клавиатуры, перерабатывать их (т.к. PS/2 гораздо проще и меньше грузит микроконтроллер) и отсылать на другую которая будет отсылать коды нажатых клавиш по USB на компьютер. Теперь давайте рассмотрим схему:
Рисунок 1 - Переходник PS/2 - USB

С подключением PS/2 клавиатуры нет никаких проблем, она подключается напрямую к Arduino по стандартной схеме. Подключить USB разъём к Arduino можно двумя способами:
1) через стабилитроны,
2) с понижением питания.
Я выбрал вариант 2 т.к. при подключении через стабилитроны могут возникать и возникают часто (судя по переписках в форумах) проблемы. Стабилитроны д.б. маломощными и быстрыми и когда я ранее пытался реализовать данный способ связи то у меня ничего не вышло, пришлось использовать понижение питания диодами и всё заработало (см. статью включение светодиода через usb)! Если Arduino 3х вольтовое то никаких дополнительных мер по снижению напряжения его питания применять не надо, в противном же случае придётся "влезть" в плату паяльником и внеси необходимые изменения. В моём случае изменений вносить не пришлось т.к. я использовал самодельную Arduino на микроконтроллере ATmega8 и питание мог делать любое которое возможно с таким микроконтроллером. Для того чтобы связать две Arduino с разными логическими уровнями по последовательному интерфейсу UART пришлось использовать резисторы с большим сопротивлением т.к. это не не позволит портам микроконтроллеров перегореть.
Теперь давайте рассмотрим скетч для Ардуино работающего с клавиатурой:
#include "PS2KeyAdvanced.h"

#define DATAPIN 7
#define IRQPIN  3

uint16_t c;

PS2KeyAdvanced keyboard;

byte keys[1000];//convert ps2 to usb hid keyboard

void setup()
{
  for(byte i = 0;i<255 i="" p="">  {
    keys[i] = 0;
  }
keyboard.begin( DATAPIN, IRQPIN );
Serial.begin( 9600 );

//2ps to usb hid
keys[65]=0x4;//A
keys[66]=0x5;//B
keys[67]=0x6;//C
keys[68]=0x7;//D
keys[69]=0x8;//E
keys[70]=0x9;//F
keys[71]=0xa;//G
keys[72]=0xb;//H
keys[73]=0xc;//I
keys[74]=0xd;//J
keys[75]=0xe;//K
keys[76]=0xf;//L
keys[77]=0x10;//M
keys[78]=0x11;//N
keys[79]=0x12;//O
keys[80]=0x13;//P
keys[81]=0x14;//Q
keys[82]=0x15;//R
keys[83]=0x16;//S
keys[84]=0x17;//T
keys[85]=0x18;//U
keys[86]=0x19;//V
keys[87]=0x1a;//W
keys[88]=0x1b;//X
keys[89]=0x1c;//Y
keys[90]=0x1d;//Z
keys[49]=0x1e;//1 !
keys[50]=0x1f;//2 @
keys[51]=0x20;//3 #
keys[52]=0x21;//4 $
keys[53]=0x22;//5 %
keys[54]=0x23;//6 ^
keys[55]=0x24;//7 &
keys[56]=0x25;//8 *
keys[57]=0x26;//9 (
keys[48]=0x27;//0 )
keys[0x1e]=0x28;//Enter
keys[0x1b]=0x29;//Escape
keys[0x1c]=0x2a;//BackSpace
keys[0x1d]=0x2b;//Tab
keys[0x1f]=0x2c;//Space
keys[0x16]=0x4f;//Right Arrow
keys[0x15]=0x50;//Left Arrow
keys[0x18]=0x51;//Down Arrow
keys[0x17]=0x52;//Up Arrow
keys[0x9]=0xe4;//Right ctrl
keys[0x8]=0xe0;//Left ctrl
keys[0x7]=0xe5;//Right shift
keys[0x6]=0xe1;//Left shift
keys[0xb]=0xe6;//Right alt
keys[0xa]=0xe2;//Left alt
keys[0x61]=0x3a;//f1
keys[0x62]=0x3b;//f2
keys[0x63]=0x3c;//f3
keys[0x64]=0x3d;//f4
keys[0x65]=0x3e;//f5
keys[0x66]=0x3f;//f6
keys[0x67]=0x40;//f7
keys[0x68]=0x41;//f8
keys[0x69]=0x42;//f9
keys[0x6a]=0x43;//f10
keys[0x6b]=0x44;//f11
keys[0x6c]=0x45;//f12
keys[0x3c]=0x2d;//-_
keys[0x5f]=0x2e;//+=
keys[0x5d]=0x2f;//{[
keys[0x5e]=0x30;//}]
keys[0x5c]=0x31;//|\
keys[0x5b]=0x33;//:;
keys[0x3a]=0x34;//"'
keys[0x3b]=0x36;//<,
keys[0x3d]=0x37;//>.
keys[0x3e]=0x38;//?/
keys[0x4]=0x46;//Print Screen
keys[0x40]=0x35;//`ё
keys[0x19]=0x49;//insert
keys[0x11]=0x4a;//Home
keys[0x13]=0x4b;//Page Up
keys[0x1a]=0x4c;//Delete
keys[0x12]=0x4d;//End
keys[0x14]=0x4e;//Page Down
keys[0x3]=0x39;//Caps Lock
keys[0x2]=0x41;//Scroll Lock
keys[0x1]=0x41;//Num Lock
}


void loop()
{
  if( keyboard.available() )
  {
    c = keyboard.read();
    if( ((c >> 8) != 0x81) && ((c >> 8) != 0x80) && ((c >> 8) != 0xc0) && ((c >> 8) != 0x90) && ((c >> 8) != 0x91))
    {
      Serial.write(keys[c & 0xFF]);
    }
  }
}

Скетч получился довольно длинный т.к. для преобразования кодов клавиш с клавиатуры в коды для отправки по USB используется массив "keys". Это обычный массив который используется необычным способом а точнее как ассоциативный массив и из за этого он избыточен и занимает много места в и без того забитой памяти микроконтроллера но зато дальше можно написать только одну строку не длинного текста для преобразования кодов что очень удобно. В условии в основном цикле проверяется "не отпущена ли кнопка". В данный массив записаны не все коды клавиш, в скетче много "магических чисел" и вообще он далеко не идеален и клавиатура в конце концов не сможет делать всё что могла бы обычная usb клавиатура но данный скетч в открытом доступе и его может исправить и дополнить любой желающий который также может выложить свой скетч в открытый доступ поэтому давайте перейдём с следующему скетчу:

#include "UsbKeyboard.h"

void setup() {
  Serial.begin(9600);

  TIMSK &= !(1  cli();
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();
  sei();
}

void loop()
{
  UsbKeyboard.update();

  if (Serial.available() > 0)
  {
    UsbKeyboard.sendKeyStroke(Serial.read());
  }
}

// helper method for V-USB library
void delayMs(unsigned int ms)
{
  for( int i=0; i  {
    delayMicroseconds(1000);
  }
}

Этот скетч короче но совсем не проще. В главной функции настройка прерываний и всего остального, в основном цикле обязательная функция UsbKeyboard.update() которая должна вызываться не реже чем 20 раз в секунду (иначе всё работать не будет), поэтому микроконтроллер с v-usb сильно грузить не рекомендуется но, к счастью для нас (и для этого микроконтроллера), другую серьёзную задачу выполняет другой микроконтроллер который находится в другой Ардуине. После того как по UARTу принимается байт он сразу же отправляется по USB в компьютер и всё это происходит быстрее чем за 50мс судя по тому что всё работает (см. видео ниже). Т.к. данная библиотека реализует класс HID то на компьютер к которому будет подключён данный адаптер с клавиатурой не надо устанавливать никаких драйверов всё должно заработать и на Windows и на Linux. Я же делал данный переходник (адаптер) для Raspberry pi 3 с операционной системой Raspbain и клавиатура с ними работала замечательно (см. видео ниже), с Windows 7 были некоторые проблемы т.к. она решила что нужен драйвер к неизвестному устройству, решила его найти и установить но после того как не получилось вывелось сообщение об этом и дальше клавиатурой можно было спокойно пользоваться. Теперь можно посмотреть видео с испытаниями и некоторой другой полезной информацией:




Первый скетч (ps2) можно скачать по ссылке https://yadi.sk/d/7RgFtn9ErWkXm
Второй (usb hid) по ссылке https://yadi.sk/d/b5mNkEIarWkXn

КАРТА БЛОГА (содержание)

Arduino UNO можно заказать по ссылке http://ali.pub/1v22bh, Atmega8-pu которую (можно превратить в Arduino) по ссылке http://ali.pub/qgw75, Raspberry Pi 3 (на котором испытывалась клавиатура в видео) по ссылке http://ali.pub/91xb2.

четверг, 6 августа 2015 г.

Простое управление приборами с компьютера.

Имея плату Arduino (можно заказать по этой ссылке http://ali.pub/1v22bh), компьютер, некоторые детали, инструменты любой желающий сможет организовать простое управление бытовыми приборами с этого компьютера. Множество приборов используемых в быту имеют множество функций, например большинство современных телевизоров могут показывать некоторое количество разных каналов, у вентилятора м.б. некоторое количество разных режимов работы и т.д. Для того чтобы сделать такое сложное управление как например переключение каналов или режимов работы, помимо перечисленного выше понадобятся дополнительные знания, детали и инструменты но сделать простое включение и выключение под силу каждому кто это перечисленное имеет. Arduino связывается с компьютером через USB порт, передачу информации с компьютера на Arduino можно осуществлять через среду разработки для Arduino (называется Arduino IDE) которую можно скачать с страницы на официальном сайте Arduino. Существует множество разнообразных модулей для взаимодействия Arduino с внешним миром, например специальный модуль с блоком реле для коммутации нагрузок, при использовании таких модулей работа сильно упрощается, здесь же мы рассмотрим самостоятельное изготовление модуля с одним реле для включение/выключения бытовых приборов, при необходимости можно изготовить более одного такого модуля и использовать их с одним Arduino тем самым сделав возможным простое управление множеством бытовых приборов. Arduino (любое) имеет некоторое количество выводов общего назначения которые обозначаются, на плате, просто цифрами или цифрами с волнистым знаком "~". Подключив Arduino к компьютеру и записав в него (в Ардуино) специальный скетч (программа для Arduino) можно с этого компьютера через программу "Arduino IDE" управлять этими выводами делая на них высокое напряжение (примерно +5В (HIGH)) или низкое (примерно 0В (LOW)). Также на Arduino есть вывод "GND" (на плате так и обозначен). Если на одном из выводов общего назначения высокое напряжение то подключив что либо проводящее ток между этим выводом и выводом "GND" через то что подключено потечёт электрический ток и величина этого тока будет зависеть от сопротивления этого предмета и рассчитать её можно по закону Ома, т.е. чем меньше сопротивление том больше ток, но если сопротивление будет слишком низким то через Arduino потечёт слишком большой ток и оно перегорит. Максимальный ток который может выдать вывод общего назначения Arduino может быть разным в зависимости от используемого в нём микроконтроллера но обычно это 40мА = 0.04А - этого может быть недостаточно для того чтобы включить реле которое будет включать прибор (приборы) поэтому для усиления тока необходимо использовать дополнительный элемент например биполярный транзистор. Биполярный транзистор имеет три вывода: эмиттер, коллектор, база. Максимальный ток транзистора также ограничен как и у Ардуино и обычно он больше, например у популярного КТ315 максимальный ток равен 100мА = 0.1А. Биполярные транзисторы бывают двух типов n-p-n и p-n-p использовать можно оба типа но по разному и далее рассмотрим использование транзистора КТ315 тип которого n-p-n. Для того чтобы транзистор усилил ток из Ардуино необходимо соединить его базу с выводом Ардуино ЧЕРЕЗ РЕЗИСТОР сопротивлением 1кОм (на резисторе м.б. написано 1к), эмиттер этого транзистора соединить с "GND" Arduino и минусом питания или "GND" источника питания напряжение которого равно напряжению обмотки имеющегося реле (допустим 12В) один из выводов обмотки реле соединить с коллектором транзистора другой с плюсом источника питания (+12В допустим) и ещё одной не влияющей на усиление но ОЧЕНЬ важной деталью является диод который нужно соединить анодом с коллектором и катодом с плюсом источника питания (+12В). Если диод импортный то на скорее всего на его корпусе будет светлая полоса - она указывает на катод, другой вывод диода это анод. Оставшиеся выводы реле - это выводы его контактов, если их два и они не замкнуты то при подаче достаточного тока на обмотку реле эти контакты замкнуться, их нужно соединить последовательно с прибором и это последовательное соединение можно втыкать в розетку, тогда при замыкании контактов на прибор поступит 220В и он включиться. Описанное выше можно изобразить на картинке:
Рисунок 1 - Управление прибором с компьютера

Это нестандартная схема для лучшего понимания, обычно используют схемы такие:
Рисунок 2 - Управление прибором с компьютера 

Хотя в этой схеме тоже присутствует нестандартное обозначение платы Ардуино. На рисунке обозначено Arduino UNO (можно заказать по этой ссылке http://ali.pub/1v22bh) но можно использовать и любое другое. Соединения можно делать например на макетной плате и проводами или пайкой. После того как всё правильно соединено и проверено можно подключить Ардуино по USB к компьютеру и загрузить в неё скетч:

char pc_code=0;

void setup()
{
pinMode(2, OUTPUT);
Serial.begin(9600);
}

void loop()
{
  if (Serial.available() > 0)
  {
    pc_code = Serial.read();
    if(pc_code=='a')
    {
      digitalWrite(2, HIGH);
    }
    else if(pc_code=='b')
    {
      digitalWrite(2, LOW);
    }
  }
}

О том как правильно настроить Ардуино и загрузить в неё скетч уже описано на странице "Простое управление шаговым двигателем с компьютера через ардуино". Далее для включения прибора необходимо на Ардуино отослать символ "a" для выключения символ "b". Для того чтобы отослать символ на ардуино можно, в среде Arduino IDE, войти по вкладке Инструменты-Монитор последовательного порта и в появившемся окне в верхнем текстовом поле вписывать символы и отсылать нажатием кнопки "отправить" символ придёт на ардуино и для данного случая если отослать символ "a" то прибор включиться, если "b" то соответственно выключиться. Если Ардуино не принимает символы то нужно в правом нижнем углу окна монитора последовательного порта установить такую же скорость какая прописана в скетче т.е. 9600 бод. Для того чтобы включать 2 прибора можно немного изменить скетч:

char pc_code=0;

void setup()
{
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
Serial.begin(9600);
}

void loop()
{
  if (Serial.available() > 0)
  {
    pc_code = Serial.read();
    if(pc_code=='a')
    {
      digitalWrite(2, HIGH);
    }
    else if(pc_code=='b')
    {
      digitalWrite(2, LOW);
    }
    else if(pc_code=='c')
    {
      digitalWrite(3, HIGH);
    }
    else if(pc_code=='d')
    {
      digitalWrite(3, LOW);
    }
  }
}

Второй модуль с реле надо аналогично подключать к выводу 3 Ардуино а для его включения посылать "c" для выключения "d". Аналогично можно изменить скетч для управления большим количеством реле также можно через одно реле подключать параллельно несколько приборов но ток потребляемый всеми приборами не должен превышать максимальный ток контактов реле. Процесс сборки, демонстрацию работы и некоторые дополнительные рекомендации можно увидеть на видео:
Часть 2

Часть 3

Доработанная программа для управления приборами  UniversalRelay 2.
Часть 4 (создание программы)

Последняя часть



Итоговая версия программы : https://yadi.sk/d/1rN2Oghv3aLmh2

КАРТА БЛОГА (содержание)

пятница, 1 мая 2015 г.

Простое управление шаговым двигателем с компьютера через ардуино.

Используя плату ардуино (можно заказать по этой ссылке http://ali.pub/1v22bh) можно создать устройство для связи драйвера шагового двигателя с компьютером через USB порт. Причём это устройство в сборке будет достаточно простое для того чтобы его смог собрать любой не только радиолюбитель но и даже любой умеющий работать руками человек (при наличии готового драйвера и источника питания).

Если используется Arduino UNO R3 то его можно подключить к компьютеру через переходник для подключения принтера. Если в этом Arduino используется микросхема CH340G то на компьютер необходимо установить драйвер для этой микросхемы. После подключения ардуино надо зайти в диспетчер устройств (в windows7 - правой кнопкой мыши по компьютер(мой компьютер) - свойства - диспетчер устройств) потом кликнуть по появившемуся неизвестному устройству, выбрать - установить драйвер, выбрать ранее скачанный драйвер и установить. Среду Arduino IDE для закачивания в Arduino скетчей и взаимодействия с Arduino можно бесплатно скачать из интернета. После установки драйвера (если это было необходимо т.к. для большинства Arduino драйвер скачивается вместе со средой Arduino IDE) среду необходимо настроить для этого во вкладке инструменты-порт выбирается порт который появился после подключения ардуино, установки драйвера в диспетчере устройств а также во вкладке инструменты-плата выбрать название используемого ардуино (например если используется ардуино уно то выбирается Arduino Uno). После настройки можно писать скетчи и загружать их нажатием кнопки "Вгрузить" (если среда на русском) если в коде есть ошибка то среда сообщит об этом в нижнем поле. Если на компьютере установлен антивирус Avast то, перед загрузкой скетча, его необходимо отключить на некоторое время (в windows7 -правой кнопкой мыши на значке avast-управление экранами avast!-отключить на 10 минут-в появившемся окне нажать "да"). Если всё таки аваст добрался до ардуино в момент загрузки и удалил файл objcopy то его надо будет достать и снова поставить на то место откуда он исчез, среда об этом напомнит при следующей попытке загрузки. Скетчи пишуться на языке C++ (или C или С подобном языке) и обычно состоят из двух функций "setup" (для кода который выполняется в начале один раз где обычно происходит инициализация портов и всего прочего), "loop" (что то вроде основного цикла (или основной цикл и есть) который повторяется постоянно после выполнения функции "setup"), инициализации переменных и возможно заголовочных файлов.
Рассмотрим один из возможных скетчей для управления шаговым двигателем с компьютера:

int d = 8;
int c = 9;
int b = 10;
int a = 11;
int delay_for_speed = 1000;
int message_for_motor = 0;
int condition_rotate = 0;
void setup()
{
pinMode(a, OUTPUT);
pinMode(b, OUTPUT);
pinMode(c, OUTPUT);
pinMode(d, OUTPUT);
pinMode(e, OUTPUT);
Serial.begin(9600);
}
void loop()
{
  if (Serial.available() > 0) 
  {
    message_for_motor = Serial.read();
    Serial.println(message_for_motor);

      if(message_for_motor == 'l')
      {
        condition_rotate = 1;
      }
      else if(message_for_motor == 'r')
      {
        condition_rotate = 2;
      }
      else if(message_for_motor == 's')
      {
         condition_rotate = 0;
      }
      else if(message_for_motor == '1')
      {
        delay_for_speed=1000;
      }
      else if(message_for_motor == '2')
      {
        delay_for_speed=800;
      }
      else if(message_for_motor == '3')
      {
        delay_for_speed=400;
      }
      else if(message_for_motor == '4')
      {
        delay_for_speed=200;
      }
      else if(message_for_motor == '5')
      {
        delay_for_speed=100;
      }
      else if(message_for_motor == '6')
      {
        delay_for_speed=50;
      }
      else if(message_for_motor == '7')
      {
        delay_for_speed=20;
      }
      else if(message_for_motor == '8')
      {
        delay_for_speed=10;
      }
      else if(message_for_motor == '9')
      {
        delay_for_speed=5;
      }
  }
  
  if(condition_rotate == 0)
  {
    digitalWrite(a, LOW);
    digitalWrite(b, LOW);
    digitalWrite(c, LOW);
    digitalWrite(d, LOW);
    delay(delay_for_speed);
  }
  else if(condition_rotate == 1)
  {
    digitalWrite(a, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(a, LOW);
      delay(delay_for_speed);
    
    digitalWrite(c, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(c, LOW);
      delay(delay_for_speed);
    
    digitalWrite(b, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(b, LOW);
      delay(delay_for_speed);
    
    digitalWrite(d, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(d, LOW);
      delay(delay_for_speed);
  }
  else if(condition_rotate == 2)
  {
    digitalWrite(d, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(d, LOW);
      delay(delay_for_speed);
    
    digitalWrite(b, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(b, LOW);
      delay(delay_for_speed);
    
    digitalWrite(c, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(c, LOW);
      delay(delay_for_speed);
    
    digitalWrite(a, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(a, LOW);
      delay(delay_for_speed);
  }
}

Первые 7 строчек это инициализации переменных. Переменные a,b,c,d -это переменные соответствующие пинам 11,10,9,8 (соответственно). С этими пинами соединяются входы драйвера шагового двигателя выходы соединяются с обмотками шагового двигателя. Обмотки должны быть соединены правильно иначе ротор двигателя не будет крутиться. Пин 11 д.б. через драйвер управлять (подавать либо не нулевое напряжение либо нулевое) первым выводом первой обмотки, пин10 управлять вторым выводом первой обмотки, пин9 - первым выводом второй обмотки, пин8 - вторым выводом второй обмотки. Далее в коде следует функция "setup" в которой данные пины конфигурируются как выходы и устанавливается скорость приемопередатчика. Потом следует функция "loop" в которой при приёме символа 
if (Serial.available() > 0) 

выполняется запись этого символа

 message_for_motor = Serial.read();

 и далее в зависимости от того какой это символ либо устанавливается состояния вращения

       if(message_for_motor == 'l')//принят символ l (эл)
      {
        condition_rotate = 1; //остановка
      }
      else if(message_for_motor == 'r') 
      {
        condition_rotate = 2; //вращение в одну сторону
      }
      else if(message_for_motor == 's')
      {
         condition_rotate = 0;  //вращение в другую сторону
      }

либо устанавливается задержка соответствующая какой либо скорости вращения ротора:

      else if(message_for_motor == '1')
      {
        delay_for_speed=1000;
      }
      else if(message_for_motor == '2')
      {
        delay_for_speed=800;
      }
      else if(message_for_motor == '3')
      {
        delay_for_speed=400;
      }
      else if(message_for_motor == '4')
      {
        delay_for_speed=200;
      }
      else if(message_for_motor == '5')
      {
        delay_for_speed=100;
      }
      else if(message_for_motor == '6')
      {
        delay_for_speed=50;
      }
      else if(message_for_motor == '7')
      {
        delay_for_speed=20;
      }
      else if(message_for_motor == '8')
      {
        delay_for_speed=10;
      }
      else if(message_for_motor == '9')
      {
        delay_for_speed=5;
      }

После чего, в зависимости от состояния вращения в переменной condition_rotate , выполняется либо остановка либо вращение в одну сторону либо в другую

if(condition_rotate == 0) //остановка
  {
    digitalWrite(a, LOW);
    digitalWrite(b, LOW);
    digitalWrite(c, LOW);
    digitalWrite(d, LOW);
    delay(delay_for_speed);
  }
  else if(condition_rotate == 1) //вращение в одну сторону
  {
    digitalWrite(a, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(a, LOW);
      delay(delay_for_speed);
    
    digitalWrite(c, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(c, LOW);
      delay(delay_for_speed);
    
    digitalWrite(b, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(b, LOW);
      delay(delay_for_speed);
    
    digitalWrite(d, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(d, LOW);
      delay(delay_for_speed);
  }
  else if(condition_rotate == 2) //вращение в другую сторону
  {
    digitalWrite(d, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(d, LOW);
      delay(delay_for_speed);
    
    digitalWrite(b, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(b, LOW);
      delay(delay_for_speed);
    
    digitalWrite(c, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(c, LOW);
      delay(delay_for_speed);
    
    digitalWrite(a, HIGH);
    delay(delay_for_speed);
    
      digitalWrite(a, LOW);
      delay(delay_for_speed);
  }

Для того чтобы отослать сообщение на ардуино можно, в среде, войти по вкладке Инструменты-Монитор последовательного порта и в появившемся окне в верхнем текстовом поле вписывать символы и отсылать нажатием кнопки "отправить" символ придёт на ардуино и для данного случая если отослать символ l то ротор будет вращаться в одну сторону, если символ r то в другую, если цифру от 1 до 9 то будет изменена скорость вращения. Код можно изменять как угодно на своё усмотрение для конкретных задач управления двигателем, можно даже написать свою программу для отсылания символов в ардуино с компьютера. Но при этом важно помнить что для некоторых драйверов (например таких) необходимо правильное управление иначе они выходят из строя и при этом могут вывести что нибудь ещё например источник, поэтому очень важно позаботиться о правильном управлении и правильном подключении двигателя к драйверу и драйвера к ардуино.


КАРТА БЛОГА (содержание)

воскресенье, 12 октября 2014 г.

Ввод через usb.

Предыдущие статьи:
Включение светодиода через usb.
usb светофор.
Управление шаговыми двигателями через USB порт.
В этой статье рассмотрим пример передачи информации от микроконтроллера компьютеру через USB порт. Для передачи состояния кнопки можно использовать схему:
Рисунок 1 - Ввод через usb

Полный текст программы для микроконтроллера приведен в статье управление шаговыми двигателями через USB порт. Рассмотрим участок кода для передачи информации на компьютер:
if(rq->bRequest == CUSTOM_RQ_GET_STATUS){
            static uchar dataBuffer[1];     /* buffer must stay valid when usbFunctionSetup returns */
//отослать состояние 3го бита порта D

if(!(PIND & (1< {
dataBuffer[0] = 0;
}
else
{
dataBuffer[0] = 1;
}

usbMsgPtr = dataBuffer;         /* tell the driver which data to return */
            return 1;                       /* tell the driver to send 1 byte */
        }

Код может быть не понятен но нетрудно догадаться что передаваемый байт записывается в переменную usbMsgPtr. Из строки:
if(rq->bRequest == CUSTOM_RQ_GET_STATUS)
понятно что для передачи информации на ПК на микроконтроллер с этого ПК приходит запрос:
CUSTOM_RQ_GET_STATUS
Рассмотрим теперь код для ПК:

#include windows.h
#include stdio.h
#include stdlib.h
#include usb.h        /* this is libusb */
#include stdbool.h  //булева библиотека
#include GL/gl.h
#include GL/glext.h
#include GL/glu.h
#include "opendevice.h" /* common code moved to separate module */
#include "../firmware/requests.h"   /* custom request numbers */
#include "../firmware/usbconfig.h"  /* device's VID/PID and names */
#define USB_CFG_VENDOR_NAME     'e','l','e','c','t','e','.','b','l','o','g','s','p','o','t','.','c','o','m'
#define USB_CFG_VENDOR_NAME_LEN 19
#define USB_CFG_DEVICE_NAME     'm','y','u','s','b','d','e','v','i','c','e'
#define USB_CFG_DEVICE_NAME_LEN 11
#define NUMBER_TRANGLE     30
int i=0;
int j=0;

HDC hdc;
HGLRC hrc;

usb_dev_handle      *handle = NULL;
const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID};
char                vendor[] = {USB_CFG_VENDOR_NAME, 0}, product[] = {USB_CFG_DEVICE_NAME, 0};
char                buffer[4];
int                  vid, pid;

// Enable OpenGL
void EnableOpenGL( HWND hWnd, HDC * hDC, HGLRC * hRC )
{
  PIXELFORMATDESCRIPTOR pfd;
  int iFormat;

  // get the device context (DC)
  *hDC = GetDC( hWnd );

  // set the pixel format for the DC
  ZeroMemory( &pfd, sizeof( pfd ) );
  pfd.nSize = sizeof( pfd );
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = 24;
  pfd.cDepthBits = 16;
  pfd.iLayerType = PFD_MAIN_PLANE;
  iFormat = ChoosePixelFormat( *hDC, &pfd );
  SetPixelFormat( *hDC, iFormat, &pfd );

  // create and enable the render context (RC)
  *hRC = wglCreateContext( *hDC );
  wglMakeCurrent( *hDC, *hRC );
}

// Disable OpenGL
void DisableOpenGL( HWND hWnd, HDC hDC, HGLRC hRC )
{
  wglMakeCurrent( NULL, NULL );
  wglDeleteContext( hRC );
  ReleaseDC( hWnd, hDC );
}
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{

BOOL bQuit = FALSE;
float coords_trangles[NUMBER_TRANGLE];
float dcoords_trangles[NUMBER_TRANGLE];
float angles_trangles[NUMBER_TRANGLE];
float dangles_trangles[NUMBER_TRANGLE];

for (i=0;iNUMBER_TRANGLE;i++)
{
coords_trangles[i]=0;
dcoords_trangles[i]=0;
angles_trangles[i]=0;
dangles_trangles[i]=0;
}

    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */
    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);
    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;
    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           800,                 /* The programs width */
           600,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

usb_init();

// compute VID/PID from usbconfig.h so that there is a central source of information
    vid = rawVid[1] * 256 + rawVid[0];
    pid = rawPid[1] * 256 + rawPid[0];

    if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0){
MessageBox(hwnd, "Could not find USB device\n","error", 0);
        exit(1);
    }
else
{
MessageBox(hwnd, "Find USB device done!\n","Done!", 0);
}

    ShowWindow (hwnd, nFunsterStil);
EnableOpenGL( hwnd, &hdc, &hrc );

while (!bQuit)
{
if (PeekMessage(&messages, NULL, 0, 0, PM_REMOVE))
{
// handle or dispatch messages
if (messages.message == WM_QUIT)
            {
              bQuit = TRUE;
            }
else
            {
              TranslateMessage(&messages);
              DispatchMessage(&messages);
            }
}
else
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);

usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS,0,0, buffer, sizeof(buffer), 5000);
if(buffer[0]==0)
{

SetWindowText(hwnd, "Button on");
}
else
{
SetWindowText(hwnd, "Button off");
}

for(i=0;iNUMBER_TRANGLE/3;i++)
{
if(buffer[0]==0)
{
coords_trangles[i*3]=0.0f;
coords_trangles[i*3+1]=0.0f;
coords_trangles[i*3+2]=0.0f;

dcoords_trangles[i*3]=((float)rand())/(100*(float) RAND_MAX)-((float)rand())/(100*(float) RAND_MAX);
dcoords_trangles[i*3+1]=((float)rand())/(100*(float) RAND_MAX)-((float)rand())/(100*(float) RAND_MAX);
dangles_trangles[i*3+2]=((float)rand())/((float) RAND_MAX)-((float)rand())/((float) RAND_MAX);
}

glPushMatrix();
glTranslatef(coords_trangles[i*3],coords_trangles[i*3+1],coords_trangles[i*3+2]);
glRotatef(angles_trangles[i*3+2], 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3f( 1.0f, 0.0f, 0.0f ); glVertex2f( 0.0f, 0.20f );
glColor3f( 0.0f, 1.0f, 0.0f ); glVertex2f( 0.287f, -0.25f );
glColor3f( 0.0f, 0.0f, 1.0f ); glVertex2f( -0.287f, -0.25f );
glEnd();
glPopMatrix();

coords_trangles[i*3]+=dcoords_trangles[i*3];
coords_trangles[i*3+1]+=dcoords_trangles[i*3+1];
coords_trangles[i*3+2]+=dcoords_trangles[i*3+2];

angles_trangles[i*3+2]+=dangles_trangles[i*3+2];

dcoords_trangles[i*3]*=0.9965f;
dcoords_trangles[i*3+1]*=0.9965f;

}
SwapBuffers( hdc );
}
}

usb_close(handle);
DisableOpenGL( hwnd, hdc, hrc );
    return messages.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                
    {
        case WM_DESTROY:
            PostQuitMessage (0);    
        break;
        default:                    
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
    return 0;
}

Приём байта осуществляет функция:
usb_control_msg
Рассмотрим пример использования этой функции для передачи:
usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, out_conditions[dt_count], 0, buffer, sizeof(buffer), 5000);
Четвёртым параметром является передаваемая информация, шестым-буфер для приёма информации, седьмым- размер этого буфера.
Для приёма информации нужно изменить второй и третий параметры:
usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS,0,0, buffer, sizeof(buffer), 5000);
Для того чтобы использовать OpenGL пришлось внести изменения в Makefile.
строку:
USBLIBS = -L"c:/Program Files/LibUSB-Win32/lib/gcc" -lusb
заменить на (т.е. немного дописать):
USBLIBS = -L"c:/Program Files/LibUSB-Win32/lib/gcc" -lusb -lopengl32 -lglu32 -mwindows
и в папку
c:/Program Files/LibUSB-Win32/lib/gcc
добавить файлы:
libopengl32.a
libglu32.a
Также необходимо добавить заголовочные файлы:
#include GL/gl.h
#include GL/glext.h
#include GL/glu.h


И добавить эти заголовочные файлы в папку GL (в папке include (в папке MinGW)) если их там нет.
Скачать программу для микроконтроллера можно по ссылке:https://yadi.sk/d/EJJiYBuRbxEXB
Программу для ПК по ссылке:https://yadi.sk/d/ZDdoRYtObxEfe


КАРТА БЛОГА (содержание)

Подходящие микроконтроллеры ATmega8a-pu (можно заказать по ссылке).