Показаны сообщения с ярлыком Arduino 1.0 libs. Показать все сообщения
Показаны сообщения с ярлыком Arduino 1.0 libs. Показать все сообщения

01.03.2021

LiquidCrystalRus - небольшое обновление

Недавно в проект LiquidCrystalRus на GitHub пришло issue по поводу того, что функция print при попытке выводить некоторые неалфавитно-цифровые символы из знакогенератора дисплеев на основе HD44780U, несправедливо их калечит. И я решил скорректировать алгоритм трансляции - чтобы он применялся строго к символам русского алфавита. Чуть больше кода из-за проверок, но зато можно так:

lcd.print("Дисковод 5\xf0");

На экране мы увидим:  Дисковод 5¼

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

Надеюсь, кому-то пригодится )

30.12.2013

Freeduino wireless (2)

Сегодня я хочу описать очередной способ беспроводного общения для Arduino. В предыдущий статье я рассказывал о простейших аналоговых модулях с амплитудной (ASK) модуляцией и библиотеке VirtualWire. Из плюсов - спартанская простота, из минусов - необходимость добавления антенн для устойчивой работы даже в пределах комнаты.

Довольно давно на рынке существует микросхема nRF24L01+, выпускаемая фирмой Nordic Semiconductors. Она обеспечивает возможность приема или передачи информации на несущей 2,4 ГГц (полоса ISM), методом частотной манипуляции GFSK. Для Arduino это решение удобно не только в силу низкой стоимости чипа, но и по причине подключения через SPI.

Для экспериментов нам понадобится какой-либо беспроводной модуль на основе nRF24L01+, например такой:



Его можно купить практически где угодно, стоить больше 160 рублей он не должен. Следует заметить, что 90% таких модулей ничем друг от друга не отличаются - схема скопирована из реф-дизайна evolution-кита к nRF24L01+, опубликованному производителем. Антенна расположена прямо на печатной плате, что при такой длине волны вполне допустимо и обещает максимальное расстояние до 100 метров (разумеется, с оговоркой про "идеальные условия", в реальности оно будет меньше - сколько именно, придется проверять экспериментально). К слову, существует две версии чипа - nRF24L01 и nRF24L01+, отличающиеся совсем ненамного и совместимые друг с другом (просто имейте ввиду, что если ваш модуль с nRF24L01 - к нему эта статья применима в полном объеме).

Назначение контактов на вилке должно быть следующим (вид сверху):



У модулей с вилкой 2x4 есть одно существенное неудобство - невозможно воткнуть в беспаечную макетку: расположенные в два ряда контакты, увы, будут закорочены попарно. Остается только позавидовать счастливым обладателям модуля от SparkFun, не поскупившимся отдать за это чудо 19.95 USD:

Посмотрим, какие выводы и куда подключать:
  • GND - земля, соединяем с одним из пинов GND на Arduino;
  • VCC - питание модуля,  внимательно - соединяем с пином 3.3В - модуль питается от напряжений 1,9..3,6В, хотя при этом отлично умеет работать с логическими уровнями +5В;
  • CE - расшифровывается как Chip Enable, но речь не про работу всего чипа, а лишь про его радиоинтерфейс - в режиме приема заставляет модуль "прослушивать" эфир в поисках предназначенного ему пакета, в режиме передачи кратковременный импульс CE передает в эфир содержимое буфера FIFO.  Подключим его к пину D8;
  • CSN - SPI: Chip select not, выбор Slave-устройства на шине SPI низким уровнем, подключаем к пину D7;
  • SCK - SPI: Clock, подключаем к пину D13;
  • MOSI - SPI: Master Out, Slave In - подключаем к пину D11;
  • MISO - SPI: Master In, Slave Out - подключаем к пину D12;
  • IRQ - прерывание, пока никуда не подключаем :(
Пины с аппаратной поддержкой SPI (SCK, MOSI, MISO) гарантированно можно найти на шестиконтактной ISP-вилке Arduino:


Если же будете подключаться к боковым гребенкам, учитывайте, что аппаратная поддержка SPI у Mega находится на пинах 50 (MISO), 51 (MOSI), 52 (SCK) и 53 (SS).

Переходник для установки в беспаечную макетку можно соорудить из разъемов PBD08 и PLS8, на кусочке обрезка обычной макетной платы (под пайку):



Итак, паяльник можно откладывать в сторону. Однако прежде чем приступать к написанию скетчей, познакомимся с документацией на чип и поподробней разберемся в том, что он умеет (и что не умеет - разумеется, тоже).

nRF24L01+ способен работать приемником или передатчиком на частотах 2400..2525 МГц, конкретная частота определяется номером частотного канала от 1 до 126, задаваемым через регистр RF_CH. Чтобы приемник и передатчик смогли обмениваться между собой, они обязательно должны быть сконфигурированы для одного и того же канала. Скорость обмена по умолчанию - 2 Мбит/с, но при необходимости ее можно снизить до 1 Мбит/с - в основном это делается для совместимости с ранними версиями чипов Nordec (вот одно из отличий nRF24L01 от nRF24L01+: последний умеет работать еще и на пониженной скорости 250 Кбит/с).

Данные передаются пакетами. Пользовательская часть (в документации называется "Payload") может занимать до 32 байт, остальные поля - служебные:


В одном частотном канале могут обмениваться довольно много устройств - для их идентификации предусмотрено поле адреса (от 3 до 5 байт). Таким образом, каждый передатчик отправляет сообщение конкретному приемнику, указывая адрес получателя; приемник, в свою очередь, прослушивает эфир и отбрасывает все сообщения, адрес которых не совпадает с его собственным.

В какой-то конкретный момент времени чип может быть либо передатчиком, либо приемником - либо передавать, либо принимать: по-очереди, но не одновременно. Для контроля можно организовать смену режимов - одной стороне даете команду передать сообщение и перейти в режим приема, другой - принять сообщение, проверить его корректность с помощью поля CRC, затем перейти в режим передачи и "отстучать" передавшему подтверждение.

Но, к счастью, существует специальный встроенный протокол Enhanced Shockburst (tm), который берет на себя все заботы о гарантированной доставке сообщения между двумя nRF24L01+. Это включает в себя не только прием, проверку правильности и отсылку подтверждающего пакета приемником, но и повторную перепосылку пакета передатчиком. Не правда ли, инженеры Nordic Semiconductors поработали на славу? ;) Для работы протокол использует поле управления пакетом.

В довершение существует специальный режим Multiceiver, в котором приемник может быть настроен на получение данных от шести передатчиков, и опять же, с возможностью работы по Enhanced Shockburst. Иными словами - один приемник может "тянуть" данные из шести передатчиков с аппаратным подтверждением и перепосылкой. Правда, есть некоторые ограничения - все устройства надо сконфигурировать на работу в одном частотном канале, с одинаковой скоростью,  длиной адреса и способом формирования CRC. Один адрес передатчика можно выбрать произвольно, а вот остальные пять должны совпадать во всех байтах адреса, кроме последнего (например, 0x1234567801, 0x12345678D5, 0x12345678AA, 0x1234567855, и так далее).

Адрес задает пользователь, и, строго говоря, он может быть произвольным. Но располагается он в самом начале пакета, сразу после преамбулы, которая выглядит в двоичном представлении как 01010101 или 10101010 - такая комбинация не случайна и нужна для правильного пробуждения приемника и его подстройки к частоте передатчика. Чтобы было меньше ложных "отбраковываний" пакетов приемной частью, надо стараться избегать как адресов, похожих на преамбулу (например - 0xAAAAAA или 0x555555), так и адресов, состоящих из вообще одних нулей и единиц (еще два плохих примера - 0xFFFFFF или 0x000000).

Пример схемы (допустим, Freeduino Nano):



Какие библиотеки  для Arduino существуют для работы с nRF24L01+?


Самый простой вариант - библиотека Mirf, которая предоставляет минимальную обвязку (её даже адаптировали для ATtiny). Скачайте последнюю версию библиотеки:
  • на странице Arduino playground, посвященной nRF24L01+;
  • непосредственно из gitHub.
Перед началом работы надо задать пины, к которым подключены CE и CSN, собственный адрес как приемника, длину пользовательской части (payload) и вызывать пару функций. По умолчанию предполагается, что CE подключен к D8, CSN - к D7 (ровно так мы уже и сделали), работа будет идти по каналу 1, длина пакета - 16 байт. Если что-то из перечисленного не совпадает с вашими потребностями, необходимо установить соответствующие значения полей до вызова init() и config(), например: Mirf.cePIN = 10;  в случае, если CE подключен к D10.

В основном, последовательность инициализации выглядит так:
  1. Mirf.spi = &MirfHardwareSpi;
  2. Mirf.init();
  3. Mirf.setRADDR((byte *)"12345");
  4. Mirf.payload = 4;
  5. Mirf.config();

Первая строчка - установление "правильного" алгоритма работы с SPI, носит скорее исторический характер. Сейчас всё равно вся работа осуществляется через встроенную в ArduinoIDE библиотку SPI, но ведь не всегда было так ;) Второй строчкой происходит инициализация пинов и SPI, в третьей мы устанавливаем собственный адрес приемника, длиной 5 байт (символьная строка "12345" дана исключительно для наглядности, на самом деле это 0x3132333435 ;) В четвертой - мы устанавливаем длину пакета 4 байта, и, наконец-то, в пятой конфигурируем чип NRF24L01 и переводим его в режим приема.

Дальше можно принимать и передавать данные.

Прием:

 if(Mirf.dataReady()){
  Mirf.getData((byte *) &packet); 
}
Сначала дожидаемся прихода пакета в буфер, затем считываем его в переменную packet (ее размер должен соответствовать текущей длине payload).

Передача:

Mirf.setTADDR((byte *)"12345");
Mirf.send((byte *)&packet);
while(Mirf.isSending()){
}

Устанавливаем адрес получателя, затем отсылаем packet и при помощи isSending дожидаемся завершения отправки.

К библиотеке прилагаются примеры ping_client и ping_server, которые обмениваются пакетами друг с другом. Чуть интереснее изучить пример  ping_server_interrupt, демонстрирующий работу по прерыванию в режиме энергосбережения: пока нет данных, Arduino пребывает в режиме сна. Однако, как только фиксируется прием нового пакета, он просыпается, принимает пакет из nRF24L01+, отсылает ответный пакет и снова "засыпает". Для корректной работы потребуется подключить ранее неиспользованный пин IRQ на плате радиомодуля - к пину D2 Arduino.

В каких случаях генерируется прерывание от nRF24L01+?


Это происходит в трех ситуациях и отображается в регистре STATUS при помощи соответствующих битовых полей:
  1. TX_DS - передающая сторона получила от встречной стороны информацию (ACK-пакет), подтверждающую успешный прием;
  2. RX_DR - приемная сторона получила новый пакет данных (и с правильным CRC, и не дубль уже полученного ранее пакета);
  3. MAX_RT - передающая сторона попыталась передать пакет максимально разрешенное количество раз, но так и не получила подтверждения о приеме.  
И, самое важное - после того, как любой из перечисленных битов был установлен, для дальнейшей работы его необходимо сбросить - записать единицу. Обычно, об этом заботится библиотека ;)

Функция Mirf.isSending() как раз и проверяет факт завершения передачи по установке TX_DS или MAX_RT. Но имейте ввиду, что она не отвечает на вопрос о том, был ли пакет благополучно принят на противоположной стороне. После того, как Mirf.isSending() вернет true, чтение регистра STATUS становится бессмысленным - перед выходом функция сбрасывает биты TX_DS и MAX_RT. К счастью, при каждом возникновении MAX_RT увеличивается счетчик PLOS_CNT в специальном регистре OBSERVE_TX, поэтому проверку благополучной доставки можно организовать так:

int readPLOS_CNT() {
  byte reg;
  Mirf.readRegister(OBSERVE_TX,&reg,1);
  return (reg >> PLOS_CNT) & B1111;
}

void loop() {
  
  int prev_plos_cnt = readPLOS_CNT();

  /* ... */
  Mirf.send((byte *)&packet);
  while(Mirf.isSending()){
  }

  if (readPLOS_CNT() != prev_plos_cnt) {
   /* failed :( */
  } else {
   /* success! */
  }
}

Еще можно вообще отказаться от использования Mirf.isSending(), и проверять биты TX_DS и MSX_RT непосредственно чтением регистра STATUS. Но тогда не забывайте сбрасывать их после установки, иначе процесс передачи встанет после первого же пакета.

Как я уже упоминал в самом начале - библиотека реализует действительно минимально необходимый набор функционала. За это приходится расплатиться следующим:
  • длина адресного поля - всегда 5 байт;
  • CRC всегда однобайтовый;
  • длина payload всегда фиксирована;
  • нет поддержки режима multiceiver (прием данных от шести передатчиков).
Что-то решается простейшим исправлением кода библиотеки, что-то можно сделать через запись и чтение управляющих регистров nRF24L01+, что-то (multiceiver или динамическая длина payload) добавить уже и вовсе непросто.

Однако, если у вас возникает слишком много претензий к функционалу Mirf, можно попробовать альтернативу - RF24. В ней конфигурируется буквально всё, в том числе автоматически учитываются различия между nRF24L01 и nRF24L01+. Идеологически библиотека ближе к стандартам Arduino и интуитивно понятнее, особенно начинающим. Например, по аналогии с Mirf есть функция RF24::startWrite, а в дополнение к ней - RF24::send, которая блокирует ход скетча до завершения процесса передачи, чтобы стало понятно - передан пакет успешно или нет, что и сообщается в возвращаемом значении типа bool (прямая замена вышеприведенному коду, который пришлось добавлять для аналогичного контроля в Mirf). 

В комплекте с библиотекой RF24 много полезных примеров, которые демонстрируют использование irq, отправку пользовательских данных в ACK-пакете и прочее. Есть даже примитивный сканер эфира ;)

Куда двигаться дальше? 


Например, по каким-то причинам не устраивает дальность приема: то ли расстояние велико, то ли стен многовато. В этом случае надо брать модуль nRF24L01+ с PA/LNA (Power Amplifier и Low Noise Amplifier):


Этот модуль будет стоить чуть дороже, около 10 USD. В его основе nRF24L01+ с точно такой же вилкой, но у него непосредственно к выходным каскадам вместо антенны подключен усилитель, повышающий мощность передатчика и чувствительность приемника. К SMA-коннектору необходимо подключить стандартную антенну для диапазона 2,4 ГГц (можно скрутить с нерабочего WiFi роутера) и правильно сориентировать - получите диапазон до 1000 метров. Правда, сразу вырастут запросы по питанию: модулю потребуются не десятки, а сотни mA, напряжение питания должно быть в диапазоне 3,0..3,6В. В этом случае может уже не получиться питать его от Arduino - если не помогает конденсатор 10 мкФ между 3,3В и землей, просто подключите модуль к отдельному источнику питания.

Да, и еще одно: не исключено пересечение по частотным каналам с другими беспроводными устройствами. Если у вас есть беспроводная клавиатура или мышь на 2,4 ГГц, с очень большой долей вероятности есть шанс разобрав ее увидеть нашего старого знакомого ;) 

Ссылки по теме:



25.12.2012

IR-приемник на Arduino

Когда ваше устройство на основе Arduino переходит из фазы прототипизации в реальную жизнь, часто возникают вопросы типа "надо делать корпус" - и все из-за того, что отлично работающие под уютной настольной лампой, от лабораторного источника питания устройства могут не пережить и одной попытки использования в руках ребенка или "отчаянной" домохозяйки. Да я уж и не говорю о рассеянных авторах! ;)

Один из таких аспектов - дистанционный пульт для исполнительного устройства на основе Arduino. Изготавливать его самостоятельно может оказаться довольно муторным делом - во времена первых советских бытовых компьютеров, например, можно было изготовить самостоятельно пленочную клавиатуру или разобрать калькулятор с шикарными герконовыми клавишами. Но теперь, стоит нам оглянуться по сторонам - и на глаза обязательно должен попасться ИК-пульт от какой-то бытовой техники (телевизора, музыкального центра, кондиционера). Если управляемое устройство находится в прямой видимости управляющего - это определенно возможность схалявить наш вариант:


Как грамотно построить схему ИК-приемника? Начнем с краткой справки по структуре сигнала: обычно, это серия световых импульсов определенной частоты - что-то около 38 кГц. Импульсы по специальным правилам образуют посылки, в которых кодируются команды (проще говоря - каждой кнопке соответствует свой код). Для передачи используется инфракрасный светодиод, для получения - инфракрасный приемник.


В основе приемника обязательно лежит фотодиод: полупроводниковое устройство, реагирующее на свет небольшой ЭДС. Для использования получаемый сигнал надо немного усилить, очистить от помех и демодулировать. Стоит ли говорить, что намного практичнее использовать готовую схему - фотоприемник, который уже включает в себя перечисленные узлы:




Стоит запомнить, пожалуй, единственный принципиальный момент - от того, насколько соответствуют частоты пульта и приемника, зависит дальность приема. Иными словами, если излучение модулировано частотой 38 кГц, а фотоприемник по спецификации рассчитан на 36 кГц - все равно будет работать, только придется ближе подходить ;) Выглядят подобные устройства, например, так:



Подключить фотоприемник к Arduino можно с минимальным комплектом деталей:



Резистор R1 и емкость C1 нужны для стабилизации питания, подтягивающий резистор опционален (хотя, как вы понимаете, подтягивающий резистор уже есть в Arduino и использовать можно его).

В качестве библиотеки можно взять вариант от Ken Shirriff,  который не только поддерживает форматы NEC, SIRC, RC5, RC6, но и может принимать вообще "сырые" посылки, ни к одному известному коду не относящиеся (и умеет еще много другого, конечно же ;)

Первым делом надо загрузить в Arduino тестовый скетч IRecvDemo и решительно испытать на нем все необходимые кнопки вашего ИК-пульта, просматривая результат в окне Serial Monitor-а:

/*
 * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

int RECV_PIN = 11;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value
  }
}


В результате вы получите некоторую таблицу значений, которую можно использовать уже в скетче исполнительного устройства.

И, кстати, вызов decode  неблокирующийся. После его вызова управление сразу же возвращается и, таким образом, скетч может работать и "заниматься своими делами", принимая команды от пульта в фоновом режиме.

Не забудьте также посмотреть самое лучшее в инете описание IR-кодов на страницах SB Projects.

04.04.2012

Freeduino wireless (1)

Однажды мне повезло выкроить время на посещение мероприятия Hard StartUp в рамках нашего провинциального hackspace. Сам я от выступления категорически отказался под предлогом бессистемного расстройства вокабулярия к концу рабочего дня, но послушал выступающих с интересом; явно бросалось в глаза, что докладчики испытывали недостаток в пульте дистанционного управления презентацией: приходилось просить листать слайды сидящего за ноутбуком человека.

Ясно, что радиокружок хакспейс выруливает в основном за счет энтузиазма его активистов и базы ИТМО, и у ребят просто могло отсутствовать нужное оборудование. Уверен, что это было не последнее их мероприятие с проведением презентаций, поэтому предлагаю свой Arduino-вариант аналогичного устройства - надеюсь, оно пригодится не только им.

Ингредиенты

Сначала создадим прототип - из того, что найдется под рукой. Мне всегда несколько проще, потому что у меня под рукой целый mk90.ru/store ;)

1. Плата Freeduino32u4 - содержит единственный чип ATmega32u4, который может изображать из себя клавиатуру, и поэтому именно ее мы будем подключать к компьютеру с презентацией;
2. Плата Freeduino Nano - будет находиться в руке у докладчика, считывая нажатия на кнопки прокрутки и передавая их Freeduino 32u4;
3. Кнопки, проводки и пара беспаечных макеток, чтобы не хвататься за паяльник по пустякам.
4. Комплект модулей беспроводной связи - наверное, самые дешевые устройства для передачи низкоскоростного информационного потока через эфир для небольших расстояний.


Немного теории

Прежде всего, вот заранее мой ответ фанатикам  IEEE 802.11, на вопрос "почему в списке нет wifi?!": не палите из пушки по микробам! В нашей задаче не нужна маршрутизация, одновременная коммуникация между несколькими устройствами и повышенная проникающая способность радиоизлучения. Нас устроят гораздо более простые устройства  - т.н. RF-трансиверы. В основном, они отличаются мощностью, несущей частотой и способом модуляции. Возьмем недорогой маломощный модуль, используемый в самоходных радиоуправляемых игрушках и работающий на нелицензируемой в России частоте 433 МГц, с модуляцией ASK.

"ASK" означает, что частота и фаза сигнала остаются постоянными, а для кодирования единицы и нуля варьируется амплитуда. Подобные приемники и передатчики можно собрать и самостоятельно, подробнее об этом можно прочесть, например у Алексея Кравченко в книге "10 практических устройств на  AVR, книга 2".

Однако, слабые места такого решения тоже выглядят внушительно:
  • два передатчика, работающие на одной несущей частоте, будут конфликтовать, мешая друг другу;
  • приемник не имеет возможности отличить посылку от одного передатчика от посылки другого - надо позаботиться об идентификации программным способом; 
  • сильная подверженность помехам, радиус действия зависит от питающего напряжения; 
  • практически нулевая безопасность, шифрование аппаратно не поддерживается.

Что-то решается программно, что-то - схемотехнически, но самое главное - такие приемопередатчики поддерживаются ArduinoIDE с помощью специальной библиотеки VirtualWire.

Схема

Рисуем схему, которая будет подключаться к USB:


И ту, которая в руке у лектора (с кнопочками):


Предполагаем пока, что обе платы питаются от компьютера, через USB.

Макет

Как бы не ругали беспаечную макетку за надежность контактов, на несложных схемах работать с ней весьма удобно. Я использую сочетание жестких и гибких проводов (вообще, это дело вкуса - гибкими быстрее, но менее наглядно). С платой 32u4:


С платой Freeduino Nano:


Кнопки устанавливать я поленился, выбрав в качестве имитации их нажатия втыкание проводка в дырочку рядом с соответствующим контактом Nano (естественно, другим концом провод воткнут в GND).

Скетчи

Как уже упоминалось, существует библиотека VirtualWire. Она будет делать за нас всю нудную работу - не только управлять приемником и передатчиком, но и кодировать наше сообщение помехоустойчивым кодом, а также считать/проверять контрольную сумму всего сообщения. Выбирая пины Arduino-совместимой платы для подключения приемника и передатчика, я вполне сознательно выбрал те, с которыми библиотека работает по умолчанию (помните об этом, если будете менять схему - не забудьте передать соответствующие параметры библиотеке).

Скетч передатчика:

#include <VirtualWire.h>

#define buttonsCount  3
int bState[buttonsCount];
int bNum[buttonsCount] = {2,3,4};

void setup() {
  // buttons
  for (byte i=0;i<buttonsCount;i++) {
    bState[i] = HIGH;
    pinMode(bNum[i],INPUT); // для ясности, после сброса все пины и так уже входы
    digitalWrite(bNum[i],HIGH); // pullup
  }
  // инициализируем последовательный порт - только для отладки
  Serial.begin(9600);
  // инициализируем библиотеку VirtualWire
  vw_setup(2000);      // скорость обмена в бит/сек
}

void loop() {
   for  (byte i=0;i<buttonsCount;i++) {
     if (digitalRead(bNum[i])!=bState[i]) {
       if (bState[i] == HIGH) {
         char key[2] = {i+1,'\0'}; 
         vw_send((uint8_t *)key, strlen(key));
         vw_wait_tx();
         bState[i] = LOW;
       } else bState[i] = HIGH;
     }
   }
   delay(100);
}

Перед началом использования кнопок, в setup включаем подтягивающие резисторы (зачем нужны подтягивающие резисторы, я уже писал). Далее, сканируем изменение состояния кнопки и, если она перешла из состояния "свободна" в "нажато", генерируем и передаем через беспроводной модуль сообщение с номером кнопки (единственный байт со значением 1, 2 или 3). Задержка в конце - примитивная борьба с дребезгом.

Скетч приемника:

#include <VirtualWire.h>

#define KEY_LEFT 80
#define KEY_RIGHT 79
#define KEY_ESC 41
#define KEY_F5 62


void setup() {
  pinMode(13, OUTPUT); // для индикации приема
  vw_setup(2000); // скорость обмена в бит/сек 
  vw_rx_start();  // инициализация и запуск приемника
}

void loop() {  
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;

  if (vw_get_message(buf, &buflen)) // неблокирующее чтение
  {
     digitalWrite(13, HIGH); // Зажигаем светодиод L - принято сообщение  
     byte key = buf[0];
     
     if (key==1) Keyboard.print(' ');
     else {
      { 
        KeyReport kbd = {0};
        if (key==2) kbd.keys[0] = KEY_LEFT;
         else kbd.keys[0] = KEY_RIGHT;
        Keyboard.sendReport(&kbd);
      }
      {
        KeyReport kbd = {0};
        Keyboard.sendReport(&kbd);
      }                        
     }     
     digitalWrite(13, LOW);
   }
   delay(200); 
}


Этот скетч будет корректно работать (и вообще скомпилируется) только с последним пропатченным ядром ArduinoIDE для Freeduino 32u4 - там функция sendReport сделана публичной, чтобы скетч был способен генерировать нажатия не только на символьные клавиши (буква 'A', цифра '8' или пробел), но и управляющие коды - (стрелки, F-клавиши и т.п.). После вызова sendReport с кодом нажатой клавиши, нужно всегда делать еще один, чтобы сообщить о ее отпускании, в противном случае через некоторое время получим режим повтора.

В данном скетче кнопка №1 транслируется в пробел, кнопка №2 - стрелка влево, кнопка №3 - стрелка вправо. Функция vw_get_message вернет нам полученное сообщение только в том случае, если совпала подсчитанная контрольная сумма - но для нас это полностью прозрачно, просто учитывайте, что она избавляет нас от необходимости проверять достоверность принятой информации с точки зрения эфирных искажений нашего примитивного ASK-сигнала ;)

Roadmap

Итак, макет завелся. Что дальше?

Устройства для реальной жизни можно делать и на основе готовых плат Freeduino, и с помощью ЛУТ-а. Но имейте ввиду, что ATmega32u4 выпускается только в SMD (в отличие от ATmega328P).

По питанию приемника все понятно - экономить не надо. А вот с передатчиком придется повозиться - продумать батарейную схему питания, позаботиться об экономном расходовании ее ресурса.

Наконец, если будут донимать помехи, можно попробовать улучшить помехоустойчивость (повторять сообщение о нажатии в эфир несколько раз или припаять антеннки).

Все это вы уже можете начинать самостоятельно или же подождать моего продолжения, если когда оно появится ;)

14.02.2012

Проблемы Ethernet в ArduinoIDE 1.0

Только что столкнулся с проблемами использования Ethernet Shield на W5100 в рамках ArduinoIDE 1.0. Великолепно до этого работавшие скетчи решительно отказались работать, что меня привело в панику слегка озадачило.

Формально, чтобы перенести скетч со "старых" ArduinoIDE 0022/0023 под 1.0, надо исправить названия классов "Server" и "Client" на "EthernetServer" и "EthernetClient" соответственно. Идеологически, классы Server и Client теперь сделаны полностью абстрактными и перенесены в ядро Arduino. И поскольку они не имеют ни одной реальной функции, библиотека должна  породить от них свой класс, "наполнив" его реальным содержимым. Думаю, делается это с прицелом на будущее, но предсказывать его пока не берусь ;)

К сожалению, даже после успешной компиляции, надо обязательно залить скетч и проверить его работу. Скорее всего, проблемы (если они действительно есть) вскроются сразу же - речь идет о неверном обмене с  Ethernet-чипом Wiznet W5100. Первым делом, открывайте файл arduino-1.0/libraries/Ethernet/utility/w5100.h и ищите в нем строки:

#define __SOCKET_REGISTER16(name, address)                   \
  static void write##name(SOCKET _s, uint16_t _data) {       \
    writeSn(_s, address,   _data >> 8);                      \
    writeSn(_s, address+1, _data & 0xFF);                    \
  }                                                          \
  static uint16_t read##name(SOCKET _s) {                    \
    uint16_t res = readSn(_s, address);                      \
    res = (res << 8) + readSn(_s, address + 1);              \
    return res;                                              \
  }

Вместо них поставьте полностью аналогичные (но, удивительным образом - работающие):

#define __SOCKET_REGISTER16(name, address)                   \
  static void write##name(SOCKET _s, uint16_t _data) {       \
    writeSn(_s, address,   _data >> 8);                      \
    writeSn(_s, address+1, _data & 0xFF);                    \
  }                                                          \
  static uint16_t read##name(SOCKET _s) {                    \
    uint16_t res = readSn(_s, address);                      \
    uint16_t res2 = readSn(_s,address + 1);                     \
    res = res << 8;                                             \
    res2 = res2 & 0xFF;                                         \
    res = res | res2;                                           \
    return res;                                              \
  }

(это исправление взято отсюда: http://code.google.com/p/arduino/issues/detail?id=605)

В большинстве случаев это помогает; мало того - говорят, что некоторые PPA в Ubuntu уже содержат пакет "arduino" с этим патчем, но давать на них ссылки не буду - я не понимаю смысл создания пакета для программы, которая великолепно работает, будучи распакована в одну папку. Гораздо удобнее качать и ставить дистро непосредственно с arduino.cc, не мучаясь вопросами "а чой-то они там наменяли-то?!"

Тем, у кого после вышеописанного патча все равно не заработает - рекомендую посмотреть на версию кросс-компилятора gcc-avr в составе вашего дистрибутива Linux. Если это, например, 4.5.3 - причина может быть в этом, и стоит позаботиться об откате на 4.3.2 или создании собственного окружения. Возможны разные варианты действий, но я пока выбрал наиболее тупой простой - развернул в виртуальную машину под Windows дистрибутив 0023 и временно работаю в нем. И вообще - пользователям Windows в этом плане проще, поскольку хоть их дистрибутив ArduinoIDE и выглядит чрезмерно "пухленьким", в него уже включен порт avrgcc - WinAVR, что драматически повышает стабильность по сравнению с Linux, где пакет gcc-avr "приходит" вместе с дистрибутивом ОС.

Тем, кто уже начал использовать включенные в состав ArduinoIDE библиотеки DHCP, стоит обратить внимание на другой патч: http://code.google.com/p/arduino/issues/detail?id=742

Сейчас при формировании DHCP-запроса, код из библиотеки Ethernet не совсем корректно формирует уникальное имя хоста, генерируя псевдослучайный суффикс в том числе и из "непечатных" символов: это может создавать потенциальные проблемы при работе DNS.


12.01.2012

LolShieldRus для 1.0

Библиотека LoLShieldRus, адаптированная для ArduinoIDE 1.0: LoLShieldRus.tar.gz

Ссылка на github (модификация, кстати, несложная - как и в случае с LiquidCrystalRus - сводится к замене инклуда WProgram.h на Arduino.h). 

Напоминаю, что это за зверь: библиотека поддержки шилд-платы LoLShield, представляющей из себя матрицу светодиодов 9х14, соединенных методом хексиплексирования таким образом, что можно управлять засветкой каждого отдельно взятого светодиода. Поддерживаются все полноразмерные Arduino-совместимые платы, включая Mega, а также - русский язык. 

См. также все статьи про LoL-shield в моем блоге.

02.01.2012

LiquidCrystalRus для 1.0

По многочисленным заявкам телезрителей пользователей, выкладываю под тегом Arduino 1.0 libs адаптированные для Arduino 1.0 библиотеки.

Начинаю с LiquidCrystalRus: скачать LiquidCrystalRus-1.0.zip.

Это копия оригинальной библиотеки LiquidCrystal с поддержкой русского языка. Добавленный код трансформирует русские символы UTF8 в правильные коды для HD44780U. 

Этот вариант будет одинаково нормально работать и с arduino-0023, и с arduino-1.0. Основная причина несовместимости - класс LiquidCrystalRus (как и оригинальный LiquidCrystal) порожден от стандартного Print, у которого поменялся прототип виртуальной функции write: если раньше возвращаемое значение было void, то теперь - size_t.

Проект также доступен на GitHub: https://github.com/mk90/LiquidCrystalRus.