26.03.2009

Arduino Mega выпущен официально

Сегодня на официальном сайте arduino.cc появилась ссылка на новую плату Arduino Mega, а также на новую Arduino IDE 0015, которая будет ее поддерживать. Как я уже писал, плата базируется на ATmega1280 (datasheet), и совместима с предыдущими Shield-платами по расположению контактных колодок, которых стало заметно больше ;)

Итак, вот что мы имеем:

MicrocontrollerATmega1280
Operating Voltage5V
Input Voltage (recommended)7-12V
Input Voltage (limits)6-20V
Digital I/O Pins54 (of which 14 provide PWM output)
Analog Input Pins16
DC Current per I/O Pin40 mA
DC Current for 3.3V Pin50 mA
Flash Memory128 KB of which 4 KB used by bootloader
SRAM8 KB
EEPROM4 KB
Clock Speed16 MHz

Основные изменения такие:
  1. Теперь есть четрые последовательных порта: Serial, Serial1, Serial2, Serial3.
  2. Можно повесить пять обработчиков прерываний на пины 2, 3, 18, 19, 20, 21.
  3. 14 каналов ШИМ (PWM)
  4. Поддержка I2C сохранилась, но переехала на другие пины - 20 и 21 (а была на analog 4 и 5).
Начаты продажи через официальный международный сайт команды Arduino, стоит 49 EUR.

24.03.2009

REPEATED START в Arduino

На досуге разбирался с библиотекой Wire на предмет возможности работать по I2C в режиме REPEATED START. Вроде бы, разобрался ;)

I2C привлекательна тем, что в ней всего два сигнальных провода, на которые вешается произвольное количество устройств. Операцию обмена начинает и заканчивает ведущее устройство (Master). Ведомое (Slave) устройство выдает данные на шину только тогда, когда этого хочет Master.

Пример записи:



Пример чтения:



В начале любой операции Master выставляет START CONDITION, передает 7-битный адрес устройства (на одной шине их может быть несколько, и все с разными адресами), а также бит операции (чтение или запись).

В режиме Master Transfer следом передается серия байт согласно протоколу общения с устройством. Например, если Slave - это AT24C512 (EEPROM 512Кбит), то следующие два байта трактуются как адрес ячейки, куда дальше пойдет чтение/запись. Но это не догма: DS1307 (часы реального времени) нужен всего один байт (внутри 64 ячейки, и одного байта с запасом хватает для их адресации). Для некоторых устройств может идти код команды, и так далее.

Все передаваемые байты подтверждаются встречной стороной через ACK (может быть как позитивный ACK, так и негативный NACK). По завершении приема или передачи Master выставляет STOP CONDITION и освобождает шину.

В Arduino запись со сторны Master программируется так:

Wire.beginTransmission(address)
Wire.send(data);
Wire.send(data);
...
Wire.endTransmission();

Пусть вас не вводят в заблуждение "интуитивные" названия функций! ;)

beginTransmission не начинает передачу, а просто запоминает адрес устройства и инициализирует буфер передачи, send ничего в линию не передает, а добавляет в этот буфер байтики (следите, чтобы не было больше 32 байт, именно такого размера буфер в Arduino), и только endTransmission() дает команду аппаратной части TWI (так ATMEL назвал поддержку I2C в своих МК) передать скопившийся буфер на шину. Учтите, что передача будет "блокирующей", т.е. пока она не закончится, управление не перейдет на следующую строку вашего sketch-а.

В режиме приема со стороны Master достаточно одного вызова (также блокирующего):

Wire.requestFrom(address,quantity);

Функция очистит буфер приема, даст команду МК в режиме Master выставить START CONDITION, передать адрес и бит-флаг "чтение", затем будет ждать получения указанного числа байт; Получив их, МК "успокоится", выставит шину в STOP CONDITION и освободит ее.

В sketch-е можно получить данные побайтно Wire.receive(), на всякий случай осведомившись методом Wire.available() о размере приемного буфера.

Вроде бы все логично, но, как я говорил - Slave-устройства бывают разные. Иногда они используют режим REPEATED START:



Как видите, все начинается как обычная операция записи, но вместо того, чтобы перевести шину в состояние STOP CONDITION, Master повторно командует START (это называется REPEATED START) и продолжает чтением.

Получается, что сначала передается адрес или команда устройству, а затем устройство отвечает, так сказать "не отходя от кассы". Проблема Arduino заключается в том, что стандартная библиотека этого не умеет, и по завершению передачи данных она переведет шину в состояние STOP CONDITION, а затем и вообще освободит её. Дальше все зависит от устройства: оно может как запомнить полученную информацию (так часто и бывает - EEPROM заносит обновляет внутренний счетчик адреса, который использует в последующих операциях чтения), так и сброситься, оставив вас "с носом". Я уже не говорю о ситуациях, когда на шине несколько Master-устройств, и "коллега" может успеть захватить шину межу записью и чтением.

Что же делать?

Выхода два: отказаться напрочь от использования стандартной библиотеки Wire, например, в пользу либы Peter Fleury, либо модифицировать стандартную.

В результате изучения кода и медитаций над общей схемой построения библиотеки Wire, родилась дополнительная функция:

uint8_t TwoWire::transmitAndRequest(uint8_t quantity)

ее надо использовать вместо endTransmission():

Wire.beginTransmission(address)
Wire.send(data);
Wire.send(data);
...
Wire.transmitAndRequest(quantity);

Эта комбинация передаст накопившееся в буфере передачи, а затем будет запущен прием через REPEATED START.

Вернется число прочитанных байт. Об ошибке будет сигнализировать значение > 127, тогда надо сбросить старший бит (0x80) и трактовать код ошибки идентично коду возврата endTransmission().

Предлагаю заценить результат (модификация библиотеки Wire из Arduino IDE 0014), его надо распаковать в Arduino/hardware/libraries (я исключил examples): Wire.zip.

К сожалению, под рукой нет устройства, которое бы строго требовало REPEATED START, буду благодарен добровольцам, которые не поленятся проверить ;) Для микросхемы часов DS1307 - работает.

20.03.2009

Arduino MEGA

Через один итальянский сайт просочилось первое фото нового Arduino:



Пока официальный сайт сохраняет молчание, можно ориентировочно предположить, что:
  • главный чип - ATmega1280
  • память программ - 128 Кб
  • оперативная память - 4 Кб
  • EEPROM - 4 Кб
  • 53 пина ввода-вывода
  • 4 аппаратных UART
  • 15 ШИМ-выводов (PWM)
  • поддержка I2C
  • 16 аналоговых входов
Некоторые (вероятно, близкие к разработчикам) товарищи уже клепают для этой платы MEGA-Shield-ы, собирая их в подобие древних пирамид:









От себя добавлю: кажется, эта плата будет совместима с предыдущими модификациями Shield-плат, т.е. авторы сохранили расположение колодок на старых Arduino.

Следите за новостями!

19.03.2009

Реакции

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

Включается через "Макет" (Layout), потом тыкаете в блок "Сообщения блога" и настраиваете нужный набор реакций на свой вкус.

17.03.2009

ArduinoIDE 0014

В прошлую среду был выпущен новый Arduino IDE 0014, в основном - мелкие багфиксы:
  • пофиксили баг с исходящими соединениями Client в библиотеке Ethernet;
  • слегка модифицировали меню Tools|Boards;
  • обновили AVR MacPack до 20081213, включающий avr-gcc 4.3.2, для корректной работы функций, вызываемых из обработчиков прерываний.
Мака у меня нет, поэтому последний пункт проверить не могу. Второй пункт - тут проще картинку показать:
  • Arduino IDE 0013

  • Arduino IDE 0014


Улавливаете? Лично я понял так: Diecimila с ATmega328 в природе не бывает.

Тем не менее, я прямо сейчас созерцаю ее на своем столе. Оставим размышлять над этим наших итальянских товарищей по оружию.

И, наконец, о главном. Не знаю, поверите ли вы мне, но не так давно я писал поддержку UDP и очень долго втыкался в такой вот код в Client::connect:

_srcport++;

// XXX: what port should we connect from?
socket(_sock, Sn_MR_TCP, _port, 1024 + _srcport);

Смысл вроде бы как простой: _scrport - это инкриментируемое при каждом коннекте значение исходящего порта (именно при выпуске 0013 это инкремент и добавили, собственно ;). Но прототип socket выглядит так:

uint8 socket( SOCKET s, uint8 protocol, uint16 port, uint8 flag)

Получается, что агрумент port - это значение _port (порт назначения, заметьте!), а flag - это 1024+_srcport. А меж тем flag - это флаги, которые засылаются в регистр MR чипа Wiznet. Признаюсь, эта конструкция сильно сбила меня с толку: немного потупив, написал свой код - правильный, но для UDP. Помню, мелькнула мысль - "на форуме спросить, что ли?".

Так вот, они его поправили! Теперь это выглядит так:

_srcport++;

socket(_sock, Sn_MR_TCP, 1024 + _srcport, 0);

Я-то думал, что только у нас в конторе код правильно пишут с 10-го релиза ;) ан - нет.

13.03.2009

AVR910 на макетке

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


Единственный программатор, который у меня есть - это Parallel Programmer, он экстремально дешев, но требует для работы машину с LPT-портом. Давно уже присматриваю что-то более человеческое, но не подступиться по цене. И дело даже не в том, что "мы бедные студенты" (с), просто отдавать за программатор 1000 рублей немного жалко: он же не универсальный. А универсальный стоит уже больше 5000 рублей, что опять дорого, потому что он каждый день не нужен. Ну и так далее ;)

Вот бы самому что-то смастерить! Чтобы для более распространенных шин, хотя бы и для USB. Схемы есть, но, как правило, на чипе FTDI232 (который, кстати, стоит и на Arduino), у него единственный минус: шаг ножек 0,65 мм и неизбежная необходимость в печатной плате (и в развлекательной пайке с лупой, разумеется).

Но не все так плохо, как кажется с первого взгляда. На просторах интернета выложен проект Андрея Рыжкова под названием "Программатор микроконтроллеров AVR / 89S совместимый с AVR910". Андрей обошелся без отдельного USB-чипа и выполнил схему на единственной ATmega8-16PI, интегрировав в микропрограмму код драйвера USB от Objective Development. Схема получилась такая:


Роль драйвера заключается в следующем: при условии тактирования МК от 12 МГц, этот фрагмент кода эмулирует протокол обмена USB "low speed device" (ровно в восемь раз медленнее - 1,5 МГц, не путать с FullSpeed и HiSpeed скоростями). Далее, Андрей добавил в микропрограмму протокол AVR910, и... получился полноценный программатор, который можно собрать за час на любой макетной плате, а комплект деталей ну никак не будет стоить больше 300 рублей (исключая покупку в Чип и Дип, в плане цены они способны на многое ;)

И главное - заметьте - макетная плата может быть беспаечной. Чем я и решил воспользоваться, чтобы обкатать свой экземпляр.

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


Ради справедливости стоит отметить, что без паяльника все-таки не обойтись. Поскольку контакты соединены в рядах группами по пять, установить на эту макетку разъем USB-B-1J нельзя: четыре контакта хоть и на расстоянии 2,54мм, но собраны "в кучку", т.е. неизбежно будут замкнуты, куда не поставь. Тоже самое касается и ICSP-разъема PBS-06, а вот ATmega, как и все микросхемы в PDIP, устанавливается над желобком, по центру.

Светодиоды калечить не хотелось, поэтому некоторые детальки сильно приподняты над платой (что не сказывается на контакте, надо заметить):


Некоторые соединения вообще выглядят как "взрыв на макаронной фабрике":


Для токоограничительных резисторов 330 Ом не удержался и попробовал сделать "красиво" - благо, это не трудно:


Дальше аппаратная история как бы заканчивается, и начинается программная. В качестве испытуемого выступил все тот же Arduino Diecimila с ATmega328 на борту:


Для работы приложений надо установить драйвер виртуального COM-порта, причем некоторые приложения, типа AVRProg будут искать его исключительно в диапазоне COM1..COM4. Но это еще полбеды, на странице проекта упоминаются Windows XP и 2000, а вот про Vista - нет. Что неудевительно: по давней традиции Microsoft, в новой версии ОС поддержку bulk-transfer для lowspeed USB было решено упразднить. Понятно, что не по стандарту, но ведь работало же, зачем? (еще один риторический вопрос к Micro$oft).

После подключения программатора к Vista устройство опознается (если нет, то вы просто неверно собрали плату), но процесс инсталляции закончится полным провалом. Если вы уже наступили на эти грабли (как я), не расстраивайтесь, выход есть. Первым делом, надо снести под корень установленные inf-файлы для Windows XP (если вы все-таки решили попробовать их установить, см. выше). Под корень - это зайти в диспетчер устройств, отыскать там подключенный программатор и по правой кнопке "Удалить", не забыв поставить галочку про удаление драйверов:


Теперь надо вооружиться драйвером для Vista. Это будет именно драйвер, смотрите здесь для Vista 32. Повторите процесс установки, указав в качестве драйвера для "страшного и непонятного" винде устройства AVR910 каталог с распакованным драйвером для Vista. Может появиться сообщение:


Надо развеять сомнения винды и продолжать до победного конца, он выглядит так:


Победить COM19 довольно просто: идем в диспетчер устройств, находим наше устройство "USB SerialPort COMXX" (удобно искать, переключившись в режим просмотра "по подключению"), затем "свойства", "параметры порта", "дополнительно". Дальше можно выбрать любой номер, даже уже занятый.

В результате, у меня программа ChipBlasterAVR v.1.07 Evaluation благополучно заработала, правильно прочитав всю память ATmega328. Правда, происходило это небыстро, я даже успел выпить стакан чая ;)

Ссылки по теме:
  • prottoss.com - описание программатора AVR910 от Андрея Рыжкова aka prottoss
  • Objective Development - проект драйвера low-speed USB для avr
  • Osamu Tamura - Using Low-speed Bulk Transfer on Windows Vista
  • Arduino - решение для быстрой прототипизации электронных схем

03.03.2009

Часы на Arduino

Недавно гуглил ответ на вопрос о том, не прикрутил ли кто-то к Arduino NTP-клиент для синхронизации времени в по сети, и наткнулся на проект 3MeterClock:



Идея простая: берется Arduino, Ethernet Shield с модулем XPort, макетная плата, три вольтметра.



Далее, у вольтметров меняется табло - дабы можно было читать минуты, секунды и часы; по сети через Simple NTP запрашивается текущее время, затем выводится через PWM-выходы Arduino на эти самые вольтметры. Правда, их надо откалибровать (выставить ноль и максимум), поэтому на прото-шилде можно разглядеть шесть потенциометров:


Идея, конечно, красивая ;), хотя не знаю, насколько ценная с практической точки зрения.

С другой стороны, ответ на вопрос "а пробовал ли кто-то прикрутить к Arduino NTP" - получен.

01.03.2009

MotorShield от Adafruit

В свое время заказал в Adafruit плату Motor Shield. Трудно, конечно, признаваться в этом, но я почему-то решил, что в комплекте будут моторчики. Но, увы - когда посылка пришла, там была только печатная плата и комплект деталей. Но постепенно руки у меня до нее все-таки дошли.



Отправная точка для изучения - страница на сайте ladyada.

На картинке наглядно видно, что и как можно подключать к этому Motor Shield:



  • Моторы постоянного тока с потреблением 600 мА, 4,5...36В, до 4-х штук.
  • Шаговые двигатели разных типов (неполярные, двуполярные и т.п), до 2-х штук
  • Хобби-серво 5В - 2 штуки.

В схеме ничего сверхъестественного нет (хотя, на мой вкус, она ужасна - какой-то винегрет из отдельных частей, как они взаимосвязаны - на первый взгляд неясно):



Arduino в основном управляет микросхемой 74HC595N - это 8-битный сдвиговый регистр с последовательным входом и параллельным выходом, а также защелкой и возможностью поставить эти самые выходы в состояние высокого импенданса.

Насколько я понял, Arduino должен последовательно загружать в этот регистр код(ы), которые в параллельном виде поступают на две микросхемы L293D - а вот это уже обычные H-мосты для управления моторами.

Чтобы не вникать во все тонкости, можно скачать библиотеки с сайта, затем распаковать их в Arduino/hardware/library. Как и в случае с любой другой библиотекой, она появится в подменю Arduino IDE "Import Library", а программировать после этого становится довольно просто.

Но, прежде чем начинать экспериментировать, есть один важный момент. На плате располагаются клеммники:



Слева - разъемы для подключения моторов M1,M2, справа - для M3,M4. И еще - обратите внимание, внизу: двухконтактный клеммник EXT_PWR, джампер соединения питания с Arduino JP1 и светодиод питания. Очень важно правильно подать питание на моторы, иначе в лучшем случае ничего не заработает.

Первым делом, вот более крупная схема питания при соединении Motor Shield с Arduino:



Напомню, что Arduino c USB питается либо от этого самого USB, либо от внешнего разъема (именно последний случай изображен на схеме). Варианты такие:
  1. Питаем Arduino и моторы от одного источника постоянного тока: подключаем этот источник к DC-входу Arduino или EXT_PWR на шилде, замыкаем джампер JP1; если у вас Diecimila, то на ней джампер выбора питания надо ставить в EXT. Вообще, питать моторы и Arduino от одного источника питания - плохая идея, Arduino может постоянного сбрасываться и вообще нестабильно работать.
  2. Питаем Arduino от USB, а моторы - от отдельного источника постоянного тока. На Diecimila джампер выбора питания ставим в USB, удаляем джампер JP1 на шилде, подключаем USB к Arduino, а питание моторов - на шилд в EXT_PWR. Если у вас Diecimila, можно альтернативно подавать питание моторов и через DC-разъем - тогда JP1 - напротив, надо замкнуть. А вот если вы - владелец Duemilanove, то последнее замечание явно не для вас, потому что на вашем Arduino нет джампера и выбор питания происходит автоматически.
  3. Питаем Arduino и моторы от двух независимых источников постоянного тока. Удаляем джампер JP1 на шилде, подключаем первый источник через DC-вход к Arduino, а второй - в EXT_PWR на шилде (ну и на Diecimila джампер выбора питания - выставляем в EXT).
Внимание: соблюдайте полярность на EXT_PWR: оно подается после высоковольтного защитного диода D1 на Arduino.

Учтите, если вы все правильно подключили - светодиод должен загореться! Если он не горит, перечитайте еще раз варианты выше или тоже самое на родном английском языке.

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

Что нужно для платформы робота? Мотор и трансмиссия, конечно же! И то, и другое там было, и я не долго думая водрузил Arduino, Motor Shield на основание:




Довольно быстро выяснилось, что на заднем мосту (классика) стоит мотор на 12 В, который надо отключить от исполнительной платы радиоуправления (рыжая справа на фото) и подключить к Motor Shield. Питается все это дело по варианту 3, поэтому слева можно разглядеть черный прямоугольник аккумулятора-"кроны". Очень рекомендую: стоит как две алкалиновых батарейки такого же типа, а служит намного дольше. Моторы питаются от батарейного отсека, который располагается по центру в днище платформы.

В качестве примера, я написал движение взад-вперед, вот как это выглядит:

#include ;

AF_DCMotor motor(2, MOTOR12_1KHZ); // create motor #2

void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Motor test!");
motor.setSpeed(160); // set the speed to 200/255
}

void loop() {
motor.run(FORWARD); // turn it on going forward
delay(1000);
motor.run(RELEASE); // stopped
delay(1000);
motor.run(BACKWARD); // the other way
delay(1000);
motor.run(RELEASE); // stopped
delay(1000);

}

Главное - не промахнуться со скоростью в setSpeed - если будет мало, платформа не тронется с места, много - улетит в стену. Увеличивая значение в setSpeed, скорость можно набирать и постепенно.

Таким образом, я минут 7 созерцал мой "шедевр", который дергался взад и вперед, раздумывая, как бы научить его еще и поворачивать. Но это - видимо уже в следующей статье ;)

Кстати, всех с первым днем весны!