17.01.2010

Простое повышение точности АЦП Arduino

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

Выбор этого источника происходит при вызове функции analogReference(type), где type может принимать одно из трех значений:
  • DEFAULT: напряжение питания, около 5 Вольт (по умолчанию, после старта скетча);
  • INTERNAL: встроенный ИОН - 1.1 Вольт для ATmega168 и 2.56 Вольт для ATmega8;
  • EXTERNAL: напряжение на пине AREF.
Я не случайно написал "около 5 Вольт", потому что в действительности питание шины USB составляет 4,40 .. 5,25 В, а стабилизатора L7805 - 4,65 .. 5,35 В. Простой математический подсчет показывает, что диапазон 0,7 В "выливается" в 14% от ожидаемых 5.00 Вольт. А теперь обратите внимание, что один шаг нашего 10-битного АЦП составляет 5.00/1024 = 0,0048828, и 0,7 Вольт в пересчете analogRead составит 143 единицы.

Это подводит нас к грустному, но неотвратимому выводу - точность лучше одного вольта при использовании DEFAULT нам заказана. Может быть, нам поможет INTERNAL?

Тут нас будет ждать второе разочарование - дело в том, что внутренний источник опорного напряжения ATmega требует предварительной калибровки. Надо взять эталонный источник напряжения, подать его на аналоговый пин и сравнить с внутренним, получив таким образом поправку, компенсирующую т.н. систематическую погрешность. Полученное значение надо сохранить в EEPROM микроконтроллера, поскольку оно индивидуально для каждого конкретного чипа, а в скетче считывать после старта. Немного занудно, но ничего сложного. Но, быть может, есть более простой путь?

Надо каким-то образом подать внешнее опорное напряжение на наш АЦП, да поточнее (это вариант EXTERNAL). В этом нам могут помочь:

  • Точный резистор: если поискать, то можно найти с погрешностью 1%,  0,1% и даже 0,01%. Есть и лучше, но это уже крутая экзотика. Из закона Ома известно, что падение напряжения на резисторе равно произведению тока на сопротивление. ОК, сопротивление-то повышенной точности, но как зафиксировать ток? Вероятно, потребуется генератор тока - это небольшая схема на операционном усилителе.
  • Диод: проводя ток в прямом направлении, он попутно "съедает" вполне фиксированное напряжение. Диод ведет себя не так, как резистор - для него закон Ома не писан, но зависимость от тока все-таки есть: достаточно взглянуть на графики вольт-амперной характеристики Vf(If) в документации.
  • Стабилитрон: это модификация диода (синоним "диод Зенера" :), который изначально предназначен для стабилизации напряжения. В простых схемах, не критичных к потерям энергии, его допустимо использовать с оглядкой на мощность. К сожалению, под рукой обычно оказываются только стандартные BX55C или BX79C, а у них погрешность 5%.
Тем не менее, вот простейшая схема стабилизатора питания +5В на стабилитроне (использована в Arduino minimum):

Более продвинутый вариант стабилитрона - это микросхема LM385-1.2, которая работает подобно стабилитрону, но обеспечивает падение напряжения 1.235 Вольта с точностью 1-2% (чем меньше ток, тем выше точность). Используются они практически повсеместно, выпускаются в корпусе SO и TO-92:




Если подключить LM385 к AREF, то получится, что мы сузим диапазон измерений от 0 до 1.235 Вольт, что не всегда удобно. В этом случае надо либо искать похожий чип на другое напряжение, либо, пожертвовав одним аналоговым пином, оставить схему DEFAULT:



Этот прием я использовал в схеме SMPReaderUSB, для измерения напряжения внутренней литиевой батареи модуля МПО-10. Резистор R9 22К выбран с таким расчетом, чтобы через LM385 протекал небольшой ток, как и положено по его документации. Измеряемый вход BATT притянут через R10 22K к земле на тот случай, если модуль не подключен и вход ADC0 повис в воздухе.

Далее, происходит считывание с двух аналоговых пинов - к одному подключен измеряемый источник напряжения BATT (ADCm), к другому - LM385 (ADC385). Оба значения передаются в хост-программу на PC, которая вычисляет пропорцию:

 Um = ADCm * 1,235 / ADC385

Значение опорного напряжения в этой формуле не участвует, и хотя зависимость по-прежнему есть, выведя это значение из формулы мы понизили его влияние на пару порядков (речь про ошибку квантования). Такой способ позволяет улучшить точность до 0,03 В, что - согласитесь - для Arduino весьма неплохо!

(в статье использованы материалы из руководства по языку Arduino)

16.01.2010

ЛУТ: какой утюг лучше? (2)

Возвращаясь к вопросу об утюгах.




При помощи совершенно случайно попавшего в мои руки датчика Pt100 и трансдьюсера PD-11T производства польской фирмы LUMEL, мне таки удалось измерить температуру обоих утюгов в режиме максимального нагревания.

Итак, "маломощный" Braun на 1900 Вт выдает нагрев около 173 градусов по шкале цельсия, а вот его китайский noname собрат на 2200 Вт - всего 159.

И хотя точность этих абсолютных величин, увы, мне неизвестна, но разница в 10-15 градусов весьма реальна и дает ощутимый эффект, о котором я писал - отпечатки на 173 градусах гораздо устойчивее к смыванию ацетоном и механическим воздействиям.

10.01.2010

Sanguino Pro

Название: Sanguino Pro
Процессор: ATmega644P-20AU
Тактовая частота: 16 МГц
Совместимость с Shield-платами: нет
Совместимость с Arduino IDE: да (надо пропатчить, переписав некоторые файлы)
Веб-сайт проекта: http://www.dh-global.com/index.php?option=com_content&view=article&id=10&Itemid=11.
Дата первого упоминания: 03.01.2010

Проект Sanguino появился гораздо раньше, чем Arduino Mega, в попытке преодолеть ограничение на предельный размер скомпилированного скетча. Очень приятно узнать, что он до сих пор жив и радует нас новыми модификациями (кстати, сейчас Sanguino совместим с последней ArduinoIDE 0017).

На этот раз - Sanguino Pro:


Идею развила и закрепила D&H Global Enterprise, согласно CC-SA указавшую на шелкографии имя разработчика оригинальной платы: Zach Hoeken.

Как и оригинальные Arduino Pro, эти платы идут без COM/USB портов, а колодки пинов не напаяны. В результате есть возможность приспособить плату для своих потребностей, не переплачивая за ненужное. Остальные характеристики соответствуют процессору ATmega644P:
  • всего 32 универсальных пина
  • 8 аналоговых
  • 6 с поддержкой ШИМ / PWM
  • 64K Flash-памяти программ
  • 4K ОЗУ 
  • 2K EEPROM
  • 2 аппаратных UART
Sanguino Pro совместима по контактам с оригинальной Sanguino, поддерживая таким образом преемственность и совместимость со старыми проектами.



Первый раз вижу, чтобы документацию на плату выкладывали не только в формате Eagle, но также добавляли результат Gerber. Те, кто мечтает развернуть собственное производство печатных плат, получают отличный шанс разобраться в том, как всё оформляется на конкретном рабочем проекте: sanguinopro.zip.

Стоимость этой платы в интернет-магазине самого D&H Global Enterprise составляет 28 USD.

09.01.2010

Удвоение пинов Arduino (2)

Часть 2. Размножение входов или shiftIn

(окончание, начало см. Часть 1. Размножение выходов или shiftOut)

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

Для рассмотренной в предыдущей части микросхемы 74HC595 существует "брат-близнец" 74HC597 - Serial-out Shift register w/Latches, который работает с точностью до наоборот: по команде "защелкивает" данные на входе, которые затем можно считать последовательно:



Работать с такой микросхемой надо аналогичным образом, учитывая назначение выводов:

  • D0-D7 - параллельные входы;
  • Ds - последовательный вход от предыдущего чипа (для каскадирования);
  • Q - последовательный выход;
  • MR - инверсный сигнал сброса (активен в LOW);
  • SHCP - синхронизация регистра
  • STCP - синхронизация защелки
  • PL - инверсный сигнал записи с параллельных входов (активен в LOW).
Схема:

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

Кстати, защелка по входу в нашем применении не нужна, можно использовать чип и без оной. Рассмотрим CD4021B, восьмибитный регистр с последовательным или параллельным входом и последовательным выходом:



PI-# - в данном случае расшифровывается как Parallel In, всего восемь входов.

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

PARALLEL/SERIAL CONTROL - официально управляет режимом по входу - единица соответствует параллельному входу, ноль - последовательному. На практике получается чуть интереснее: пока режим параллельный - по каждому фронту CLOCK происходит обновление состояния всех восьми бит регистра. Если мы хотим "зафиксировать" состояние всех восьми выводов в определенный момент времени, надо дать один CLOCK в параллельном режиме, а потом перейти в последовательный - и прочесть 8 бит - при этом счетчик заполнится тем, что поступит со входа SERIAL IN, а Arduino к этому моменту получит все 8 бит информации, записанной в режиме параллельного ввода. Поэтому, иногда этот вход на схемах маркируют как latch - по смыслу того, что он делает.

Q6, Q7, Q8 - это выходы соответствующих разрядов последовательного счетчика, для использования всех восьми разрядов надо считывать данные с Q8.

Вообще, серия 4000В - не очень скоростная (соответствует нашей 1561), максимальное быстродействие 90 нс. Учтите, что мы-то ее будем использовать не на предельном питании +15 В, так что готовьтесь к 160...320 нс, тактировать её можно с частотой 3..6 МГц. Немного, но для считывания, например, механических контактных групп - вполне подойдет.

Схема будет выглядеть очень похожим образом:



Номинал резисторов на этой схеме - 10К, смысл академический - нельзя "бросать" вход КМОП-схемы в плавающем состоянии, на нем должен быть устойчивый потенциал.

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

#define DATA  9
#define LATCH 8
#define CLOCK 7

#define CLKUS 1 

byte dataInput; 

void setup() {
  pinMode(DATA,INPUT);
  pinMode(LATCH,OUTPUT);
  pinMode(CLOCK,OUTPUT);
  
  Serial.begin(9600);
}

void loop() {
  
  dataInput = 0;
  digitalWrite(LATCH,HIGH); // Parallel mode

  for (int i=7; i>=0; i--) {
   digitalWrite(CLOCK,HIGH); 
   delayMicroseconds(CLKUS);
   dataInput |= (digitalRead(DATA) ? (1<<i) : 0);
   digitalWrite(CLOCK,LOW);    
   delayMicroseconds(CLKUS);
   if (i==7) digitalWrite(LATCH,LOW); // Serial Mode
  }
  
  Serial.println(dataInput, BIN);
  delay(1000);
}

В основном теле loop() раз в секунду происходит считывание всех кнопок путем кратковременной подачи высокого уровня на пин LATCH. Дальше в цикле формируется восемь перепадов CLOCK и данные запишутся в соответствующие разряды переменной dataInput, после чего будут в двоичном формате выведены в последовательный порт (наблюдайте результаты в мониторе последовательного порта). Задержки умышленно даны с запасом, если есть желание - попробуйте их уменьшить до предела по документации.

Прием с каскадированием для повышения разрядности:



Скетч при этом почти не изменится:

#define DATA  9
#define LATCH 8
#define CLOCK 7

#define CLKUS 1 

word dataInput; 

void setup() {
  pinMode(DATA,INPUT);
  pinMode(LATCH,OUTPUT);
  pinMode(CLOCK,OUTPUT);
  
  Serial.begin(9600);
}

void loop() {
  
  dataInput = 0;
  digitalWrite(LATCH,HIGH); // Parallel mode

  for (int i=15; i>=0; i--) {
   digitalWrite(CLOCK,HIGH); 
   delayMicroseconds(CLKUS);
   dataInput |= (digitalRead(DATA) ? (1<<i) : 0);
   digitalWrite(CLOCK,LOW);    
   delayMicroseconds(CLKUS);
   if (i==15) digitalWrite(LATCH,LOW); // Serial Mode
  }
  
  Serial.println(dataInput, BIN);
  delay(1000);
}


Разрядность переменной, в которую читается состояние увеличилась в два раза - с 8 до 16 бит, чтение выполняется за 16 тактов. В остальном - тоже самое.

Часто бывает так, что импортный чип достать сложнее, зато наш (советский или белорусский) валяется без дела, да так и просится в схему. Мне в свое время сильно помог К561ИР9 (функциональный аналог CD4035B):



RESET - сброс всех разрядов в ноль в произвольный момент времени.

PI1..PI4 - параллельные входы, как в CD4021.

Q1..Q4 - это параллельные выходы, как в 74HC595 (см. часть 1)

J/K - это последовательный вход. Замечу, что он выполнен в виде J/K триггера, и если J и К соединить, то получится D-триггер, как в CD4021.

P/S - управление режимом ввода, как в CD4021. По логической единице будут записаны данные с параллельных входов, по нулю - с последовательного входа J/K.

T/C - прямой/дополнение (true/complement). Микросхема универсальна до такой степени, что умеет менять знак у выводимого кода (т.е. выдавать не само число, а дополнение к нему). Нам это навряд ли понадобится, поэтому притянем этот вход к Vcc - это вечный true.

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



Можно использовать скетчи от предыдущих примеров практически без изменений:
  • в режиме ввода считывать данные последовательным кодом с digital9
  • в режиме вывода подавать последовательный код через digital10.
В последнем случае, увы, комбинация на выходах Q1..Q3 будут сдвигаться. А если бы не этот недостаток, то при наличии защелки на выходе получился бы идеальный вариант - универсальная схема, которая поможет расширить и входы, и выходы!

Время взвешивать за и против.

Плюсы Arduino / Seeeduino Mega: компактность, гибкость, быстродействие, попутно получаем 128К  памяти программ.

Плюсы логических микросхем: цена решения, на надо платить за лишнее/неиспользуемое, нагрузочная способность линии, доступность.

Казалось бы, на этом можно ставить точку, но... спустя какое-то время появилась и третья статья про увеличение числа пинов Arduino.

(в тексте использованы материалы статьи Parallel to Serial Shifting-In with a CD4021BE).

Обновленный сайт Arduino

Зашел в очередной раз на arduino.cc и увидел магическую надпись:


YOU ARE ACCESSING AN OLD VERSION OF THE ARDUINO SERVER, PLEASE READ THIS NOTE FOR DETAILS


Далее разъясняется, что это "старый сервер", и вы сюда попали потому, что еще не прошло обновление DNS.

Готовьтесь к изменениям! ;)

UPD: мигрировали под CentOS 5.4. Уж не знаю, чем оно им поможет, но нагрузка на этот сайт немаленькая, это точно!