27.01.2009

Arduino и Serial Flash

На днях прикрутил к Arduino флешку (микросхема AT24C512 от все того же ATMEL - емкость 65 Кбайт или 512Кбит). В принципе, с аппаратной библиотекой I2C получилось более чем тривиально.

Выводы микросхемы : A0,A1 сажаем на GND, за компанию с WP. SCL и SDA подключаем к аналоговым выводам Arduino (a4,a5) и притягиваем каждый через 5,1К к VCC.

Скетч:

/* 
   Подключение AT2424C15 по I2C
*/ 

#define ADDR  0x50

void setup() {
  Wire.begin();
  Serial.begin(38400);
  randomSeed(analogRead(0));  
}

void readByte(unsigned int addr) {
  Wire.beginTransmission(ADDR);
  Wire.send( (byte) addr >> 8 );
  Wire.send( (byte) addr & 0xff );
  Wire.endTransmission();
  Wire.requestFrom(ADDR, 1);
}

void writeByte(unsigned int addr, byte b) {
  Wire.beginTransmission(ADDR);
  Wire.send( (byte) addr >> 8 );
  Wire.send( (byte) addr & 0xff );
  Wire.send ( b );
  Wire.endTransmission();
}

void loop() {
  if (Wire.available()) {
    Serial.println(Wire.receive(),HEX);
  }
  int cmd = Serial.read();
  if (cmd != -1) {
    if (cmd == 'R') {
      readByte(0);
    }
    if (cmd == 'W') {
      long b = random(0,255);
      writeByte(0,b);
      Serial.println(b,HEX);
    }
  }  
}


Запускаем консольку на 38400, по команде W пишется случайное значение в нулевой адрес, по команде R его можно оттуда же прочитать. Адрес чипа - 0x50, если A0 и A1 притянуты к GND. Если подать на них одну из четырех комбинаций адреса, можно общаться с четырьмя разными чипами, "сидящими" на одной I2C, только надо правильно учитывать адрес (50,51,52,53).

19.01.2009

Ethernet Shield для Arduino (2)

На досуге немного покопался в схемотехническом решении этого Shield-а. На моем варианте Shield-а отсутствует разъем SD (не используется в Arduino):



W5100 подключен в режиме последовательного интерфейса (конечно же: экономим pin-ы).
  • MISO (27) - digital 12
  • MOSI (28) - digital 11
  • SS (29 или SCS) - digital 10
  • SCK (39 или SLCK) - digital 13, на нем же дублирующий светодиод L на Arduino
Если пользоваться разъемом SD, то получается, что:
  • CLK (5) - digital 9
  • DAT0 (7) - digital 3
  • DAT1 (8) - digital 4
  • DAT2 (9) - digital 5
  • DAT3 (1) - digital 6
  • CMD (2) - digital 8
  • WP - analog 0
  • DETECT - analog 1
Теперь по поводу "джамперов":


  • вверху - INT. это не джампер, а посадочное место для SMD резистора-нулевки. Он пропускает сигнал прерывания на digital 2;
  • внизу слева - PROG. это пустое место для 2-х пиновой гребенки. Судя по схеме, ее замыкание сажает ногу SEN (SErial Enable) на землю, запрещая таким образом обмен по последовательному интерфейсу для чипа W5100. Практического смысла в этом крайне мало, поскольку при этом должны использоваться шина данных и адреса (A0-A14, D0-D7), но они победно висят в воздухе.
  • внизу справа - WP - это еще одно место для нулевки. Сажает вывод "WRITE_PROTECT" (а вместе с ним и analog 0) на землю.
Сам по себе W5100 держит все-таки 4 сокета, прерывания Arduino не поддерживаются. Было бы интересно запаять разъем для SD, но его еще надо поискать. Беглый просмотр Инетрнета показал, что есть и отдельные решения на этот счет (автор делал для wireless-сенсора, который пишет туда данные про обнаруженный сигнал).

15.01.2009

Сборка Arduino Serial

В отличие от первой моей попытки, эта обещала быть простой и приятной (так оно в итоге и получилось).

Отправная точка - двусторонняя печатная плата Arduino Serial 2.0a, на которой нанесена маркировка компонентов:


Понадобится паяльник (желательно с конусообразным жалом, некоторые контактные площадки довольно маленькие), припой (например, ПОС-61), канифоль (я использую жидкую ЛТИ-120, для ее удаления потребуется немного спирта, зато качество пайки на порядок круче, чем с помощью обычной сосновой).

Собираем комплектацию в кучку (здесь и далее я буду ссылаться на этот список элементов).

Первым делом, установим резисторы R5, R6, R7, R8, R9, номинал 10 КОм:


(для красоты сделаем так, чтобы они были ориентированы золотой полоской в одну сторону). Далее, перевернем печатную плату, слегка отогнем ножки в сторону и аккуратно запаяем:


Теперь ставим R1 (снизу, 4К7), R2 (выше, 220):


(аналогично, надо ними располагаются R3, R4 - по каждый).

Теперь установим диоды, соблюдая полярность - риска на корпусе диода соответствует риске на печатной плате:


Вверху стоят два 1N4148 - D2, D3:


А внизу - высоковольтный 1N4004 - D1 (у меня был 1N4007):


Паяем элементы тактового генератора - кварц Q1 на 16МГц плюс С2, С3 - емкости по 22пФ. Заодно можно установить и фильтр по питанию C1 - также пленочный конденсатор 100мкФ (на нем может быть написано "104"):


Постепенно начинаем поднимать высоту устанавливаемых элементов. Светодиод LED1 устанавливается длинной ножкой в дырочку "+". Транзисторы T1 и T2 (BC547C и BC557C соответственно) безошибочно устанавливаются по профилю корпуса (он нарисован). У 557-го, возможно, придется отогнуть ножки, чтобы они выстроились в линию:


Устанавливаем стабилизатор +5В IC2 7805 таким образом, чтобы первая ножка на корпусе TO-220 соответствовала дырке с точкой на плате. Электролиты C6, C7 - 100мкФ х 16В устанавливаются, так же как и светодиод, длинной ножкой в положительную дырку. Если в комплекте C8 (10 мкФ х 16В) неполярный - написано NP, то его "ориентация" не имеет значения. В противном случае, если он полярный, его тоже надо длинной ножкой в плюс.


Последний радиоэлемент на плате - пленочный конденсатор C5 - 100нФ:


Теперь можно аккуратно установить все разъемы.

Панелька для ATmega - X3 SCS28S (на фото цанговая панелька - она дороже, но дольше служит) - согласно ориентации на плате, гребенка ICSP (2x6, PBS06 - ориентация безразлична) и тактовая кнопка S1. У тактовой кнопки две группы замыкающих контактов, расположенные с двух сторон. Ее надо расположить так, чтобы стороны с лапками смотрели влево и вправо (в сторону кварца и гребенки ICSP):



Далее, устанавливаем разъем X1 - DB09:


После установки, можно аккуратно раздвинуть лепестки-лапки креплений по бокам - паять их бесполезно, т.к. нет контактных площадок.

Далее, устанавливаем разъем X2 - гнездо питания 2,1мм. Вот тут, возможно, надо заменить жало паяльника на "лопатку" и душевно залить олова в три посадочные дырочки.

Последними идут розетки PLD - POWER, J1, J2, J3. Старайтесь паять их аккуратно, чтобы получилось ровно.

Готово? Не совсем. Берем ATmega8P-16PU, слегка подгибаем ножки, чтобы он залез в пенельку:


Устанавливаем ATMEGA в панельку (опять-таки, следите за положением ключа - на микросхеме, панельке и плате оно должно совпадать).

Если ATMEGA еще не прошита, то берем Parallel Programmer, машину с LPT-портом и запускаем на ней Arduino IDE. Выбираем тип платы: "Tools | Board | Arduino NG or older w/ATmega8".

Подключаем питание к плате (можно даже через батарейку) - на Arduino должен загореться LED1, подключаем шлейф Parallel Programmer к пинам ICSP (следите за положением пина 1), наконец запускаем в Arduino IDE "Tools | Burn Bootloader | w/Parallel Programmer".

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


Подключите COM-порт компьютера к разъему X1 Arduino, выберите подключенный COM в ArduinoIDE: "Tools | Serial Port | ... ". Загрузите исходник тестового sketch-а из комплекта: "File | Sketchbook | Examples | Digital | Blink".

Откомпилируйте программу (Ctrl+R, круглая кнопка со стрелкой, "Sketch | Verify/Compile"), нажмите кнопку сброса S1 на плате Arduino, затем "залейте" sketch (Ctrl+U, квадратная кнопка со стрелкой вправо, "File | Upload to I/O board"). Операция завершится довольно быстро, о чем напишет IDE в строке статуса.

Подождите 15-20 секунд, светодиод должен начать мигать. Если нет, проверьте, хорошо ли вставлен светодиод, при необходимости переверните его ;)

На этом - все. Спаять и запустить можно за 1 вечер, как видите ничего сложного даже для начинающего.

13.01.2009

Ethernet Shield для Arduino

Итак, как я уже писал, ко мне приехала посылка из SmartProjects. Половина стоимости пришлась на Ethernet Shield:



... который я тут же начал испытывать со своим Arduino Diecimila:



Удобнее всего его подключать на работе к локалке, благо она под рукой в невероятных количествах ;)



Три коробочки вверху - это мегаизвращение, к которому я прибег при отсутствии под рукой блока питания 9В: берется источник DC 48В (от ~220В), втыкается в PoE-инжектор DLink DWL-P200, который вводит его в кабель Ethernet, затем в PoE-сплиттер, который, наоборот, отделяет питание, но попутно он умеет преобразовывать его при помощи DC-DC в 5 или 12 вольт, как раз под разъем питания для Arduino (2,1 мм, в центре - плюс).

Не пытайтесь повторить ;) лучше купите БП на 9В (от 12В стабилизатор на Arduino довольно сильно греется).

Что дальше?

Запускаем Arduino 0012, говорим "New", затем "Import Library | Ethernet". Появляются инклудники. Можно добавить пустые setup и loop и компильнуть: как видите, sketch занял около 8 Кбайт! (в память ATMEGA8 это уже точно не влезет).

Вернемся к Ethernet. Первым делом, можно попробовать пример Telnet, который есть в дистрибутиве Arduino.

#include <Ethernet.h>

// network configuration.  gateway and subnet are optional.
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 10, 0, 0, 177 };
byte gateway[] = { 10, 0, 0, 1 };
byte subnet[] = { 255, 255, 0, 0 };

// telnet defaults to port 23
Server server = Server(23);

void setup()
{
  // initialize the ethernet device
  Ethernet.begin(mac, ip, gateway, subnet);

  // start listening for clients
  server.begin();
}

void loop()
{
  Client client = server.available();
  if (client) {
    server.write(client.read());
  }
}

Суть примера - после подключения по порту telnet (команда telnet arduino_ip), любой вводимый символ возвращается обратно.

Для того, чтобы попугать коллег, я решил переделать этот пример в имитацию веб-сервера. Поскольку TCP-соединение устанавливается совершенно прозрачно, то меняем порт с 23 на 80, а в обработчике добавляем считывание запроса и вывод HTML-странички.

Поскольку мне было лень считать количество информации на выходе, я ограничился только строкой Content-Type, а Content-Length посылать не стал. Браузеры у коллег наивно пытались дождаться завершения принимаемой информации, но навсегда повисали в этом состоянии. Пришлось добавить несколько команд, чтобы разрушить соединение:

#include <Client.h>
#include <Ethernet.h>
#include <Print.h>
#include <Server.h>

byte mac[] = { 0x00, 0x1D, 0x60, 0xAF, 0x03, 0x30 };
byte ip[] = { 10, 57, 3, 1 };
byte gw[] = { 10, 57, 0, 1 };
byte subnet[] = { 255, 255, 0, 0 };

//Server server = Server(23);
Server server = Server(80);

void setup() {
  Ethernet.begin(mac, ip, gw, subnet);
  server.begin();
  Serial.begin(38400);
}

void loop() {
  Client client = server.available();
  if (client) {
    while (client.available()) {
      Serial.print(client.read(),BYTE);
    }
    client.println("HTTP/1.1 200 OK");
    client.println("Content-type: text/html");
    client.println("");
    client.println("&lt;html&gt;&lt;title&gt;Arduino Ethernet&lt;/title&gt;&lt;body&gt;&lt;h1&gt;Hello, I'm Arduino Ethernet Shield!&lt;/h1&gt;Version 0001 with disconnect!&lt;/body&gt;&lt;/html&gt;");
    client.flush();
    client.stop();
  }
}

На все эксперименты ушло около 15 минут, включая подключение и короткое обдумывание "чего бы такого наваять". Я писал эту статью в блог и делал картинки гораздо дольше ;)

31.12.2008

Семисегментный индикатор для Arduino (4)

Часть IV

(окончание, см. Часть III, Часть II и Часть I)


Итак, время брать в руки паяльник. Используем стандартную макетную плату для пайки с шагом 2,54мм (шаг важен, поскольку надо установить вилку PLS, чтобы попасть ей в розетку PBS на Arduino - а там именно такое расстояние между контактами). Выбираем размер так, чтобы она не закрывала второй ряд колодок с цифровыми pin-ами, например, у меня получился размер 96 x 52 мм.

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




Чтобы не паять лишний разъем ICSP для ATMEGA8, я поставил панельку. Кнопка сброса - чисто декоративная, и на самом деле, ее можно и не ставить вовсе. Длинная гребенка голубого цвета - это резисторная сборка (6 резисторов по 330 Ом). Вещь удобная, но, будучи поставлено вертикально, постоянно гнется при неосторожном обращении с бескорпусным изделием. Зато - опять-таки - экономия места.

Паяем проводники, глядя в принципиальную схему. Поскольку LED-ы индикаторов соединены в шину, напрашивается тривиальное решение по расположению:



Конденсатор по питанию довольно компактно влез между вилкой PLS и панелькой:



Если вы попробуете сразу запустить плату после пайки - у вас ничего не выйдет. Причина - отсутствие кварца, на который рассчитывает ATMEGA. Если вы уже отлаживались с ним в составе Arduino, программатор вместе с bootloader-ом прошил весьма определенные FUSE-биты, в том числе отвечающие за выбор схемы тактирования: внешний кварц на 16 МГц. У нас используется внутренний на 8 МГц, поэтому FUSE-биты надо изменить.

Поместите ATMEGA8 в устройство с ICSP-гребенкой (тот же Arduino), подключитесь к ней с помощью программатора и поменяйте fuses следующим образом (подробное описание битов - в документации):

Fuse High Byte: SPIEN=0, CKOPT = 1, BOOTSZ = 01, BOOTRST = 0;
Fuse Low Byte: SUT = 01, CKSEL = 0100;

Остальные биты стоит оставить незапрограммированными, получаем шестнадцатиричные значения: hfuse = 0xda, lfuse = 0xd4.

Например, если вы используете Parallel Programmer и Arduino IDE, надо запустить avrdude со следующими параметрами:

avrdude -p m8 -c dapa -t

где m8 - это тип контроллера, ATMEGA8; dapa - это тип программатора, а -t - войти в терминальный режим. Находясь в оном (avrdude> - это приглашение), набираем:

avrdude> write hfuse 0 0xda
avrdude> write lfuse 0 0xd4
avrdude> q

Вот теперь - точно должно заработать! Но будьте терпеливы: Arduino bootloader понятия не имеет, что теперь его тактовая частота понизилась в 2 раза. Его алгоритм предполагает ожидание около 10 секунд после старта (мало ли - думает он - может новый sketch сейчас зальют?!). Теперь же, после подачи питания, bootloader будет ждать 20 секунд. Дальше на экране появится три минуса, затем будет отображаться то, что передается по TWI.

Если ничего не отобразилось, то надо смотреть, правильно ли собрана схема. Например, я умудрился инвертировать сброс, в итоге он работал только при нажатой кнопке ;)

Последние штрихи: вернемся к fuse-битам. Наверное, стоит сделать так, чтобы bootloader не запускался вовсе, а сразу стартовал наш sketch. Это довольно просто: достаточно сообщить об этом ATMEGA через hfuse: установить флаг BOOTRST в 1. Проделываем всё тоже самое, что и выше, только вместо 0xda пишем 0xdb.

Конечно же, первым делом я соорудил градусник. Датчик подключается к цифровым pin-ам, которые не перекрыты макетной платой:






Подведем итоги.
  1. Контроллером дисплея служит ATMEGA8, как и хотелось;
  2. Программа написана на Wiring-е, отлажена в Arduino, легко менятеся, расширяется по числу индикаторов, а также типу (переделывается под общий анод).
  3. Число деталей минимизировано - кроме контроллера восемь резисторов 330 Ом и один - 10К, а также сами индикаторы.
  4. Интерфейс взаимодействия по TWI (I2C) получился относительно простым, хотя и пришлось в итоге поставить задержку 100 мс между посылками информационных блоков. Для человеческого глаза - вполне приемлемо.
Чего хотелось бы еще?
  1. Неплохо было бы сделать печатную плату, повысив компактность;
  2. Оформить ввод-вывод в виде библоитеки и подключать ее, чтобы не писать каждый раз одно и то же;
  3. Сделать полноценный алфавитно-цифровой дисплей.