Шапка

15.2 Пример разработки: пляжный экспонометр (V)

Этот незаменимый спутник отдыхающих первый раз встретился в Части _4 [* §4.8.4 ] , где разбиралась его чисто аналоговая версия, а второй раз в Части 13 [* §13.9.1 ] , где использовалось интегрирующее АЦП. Упомянутые версии хорошо раскрывали методы разработки с использованием аналоговых и цифровых компонентов. В этой части история завершится микроконтроллерной реализацией. Сейчас будет задана базовая конструкция, а позднее она будет слегка доработана.

Напомним, что задача состоит в сообщении пользователю, что пора завершать солнечные ванны. Она решается подсчётом набранной дозы солнечного излучения с фотодиодом в качестве первичного датчика ( его ток пропорционален освещённости ). Любитель загара устанавливает требуемую дозу «полного солнечного эквивалента» ( FSE ) с помощью потенциометра в пределах 0...90 FSE, нажимает кнопку «START» и начинает цикл выпекания. Об окончании набора дозы сообщает пьезо-зуммер.

15.2.1 Реализация на микроконтроллере

Классическое, но скучное, решение - преобразование тока в напряжение на резисторе обратной связи операционного усилителя, оцифровка выхода ОУ с помощью внутреннего АЦП с последующим интегрированием в цифровой форме. Но есть путь проще и лучше, вполне доступный микроконтроллеру ценой $0.50 ( рис. 15.2 ). Идея состоит в том, чтобы заряжать с помощью фототока конденсатор, затем, используя встроенный в µC компаратор, активировать короткий разрядный импульс через вывод порта, находящегося до того в третьем состоянии _5 . Такая схема генерирует пилообразный сигнал, чья частота пропорциональна освещённости. Микроконтроллер просто считает циклы заряд-разряд и включает сирену, когда нужный уровень достигнут ( устанавливается потенциометром «доза» ). Цифровой входной порт фиксирует нажатие на кнопку «START», а цифровой выходной порт управляет пьезо-зуммером.

Рис. 15.2   С помощью микроконтроллера можно легко реализовать уже знакомый пляжный экспонометр

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

Схема 15.3 - самая простая из пяти представленных в книге вариантов детектора, но требует написания и загрузки в кристалл кода, о чём будет разговор далее. Перед тем, как переходить к программе, рассмотрим подробнее все достоинства и особенности нового варианта: номиналы компонентов, выбор контроллера, фотодетектора и т.п. Здесь есть чему поучиться. Собственно, выбор компонентов, а также компромиссы, на которые приходится идти, и есть суть разработки электроники.

Рис. 15.3   Полная схема пляжного экспонометра. См рис. 4.93 , где приводятся данные сенсора G5842

На рис. 15.3 показана итоговая схема, построенная на компонентах, доступных в момент написания книги. Давайте разберём её.

15.2.1.A Выбор микроконтроллера

К этому элементу каких-то особенных требований нет. Скорость не важна, а компаратор и АЦП есть сейчас почти во всех таких микросхемах. Зато хочется малого потребления и работы прямо от батареи без промежуточного регулятора. Данная модель выбрана как самая младшая в линейке “picoPower” AVR фирмы Atmel. Экземпляр на схеме имеет режим микропотребления, даже когда работает от +5V _6 . Диапазон питания 1.8—5.5 V , а ток 35...170μA ( по всему диапазону питания ) при работе от внутреннего генератора на 128 kHz .

15.2.1.B Схема разряда

От использования выхода с третьим состоянием для разряда времязадающего конденсатора ( рис. 15.2 ) придётся отказаться, т.к. параметры утечки не позволяют рассчитывать на успешное завершение проекта. Максимальный ток утечки составляет ±1μA , что сравнимо с током фотодиода на свету. Можно выбрать датчик с бОльшими размерами и, соответственно, бОльшим током, но внешний ключ на n-МОП транзисторе легко решит задачу _7 . Здесь используется компактный BSS123: уровень переключения подходит для схемы, а ток стока достигает 0.5 A при 2.5 V на затворе. Утечка для наихудшего случая 10 nA при \(V_{DS}\)=20 V . Его легко купить, а цена всего $0.05 в количествах _8 .

15.2.1.C Потенциометр установки дозы

В упрощённой схеме потенциометр поставлен между землёй и питанием, но правильная разработка требует, чтобы в этом случае ток холостого хода был существенно выше, чем утечка выводов порта, т.е. требует существенных расходов мощности. Правильнее будет подавать на потенциометр питание, только когда оно и в самом деле требуется, т.е. при считывании положения движка. Это просто: надо подключить верхний вывод вместо питания на порт микроконтроллера. Когда программа выдаст на выход ВЫСОКИЙ уровень, внутренний p-канальный ключ подтянет вывод к Vcc .

15.2.1.D Фильтрация и развязка

Схема 15.3 украшена развязочными конденсаторами, возможно, даже с некоторым перебором. Шина аналогового питания AVcc отвязана от шумной цифровой Vcc с помощью LC фильтра, рекомендованного в справочных данных на контроллер. Есть развязка и на выходной линии потенциометра, потому что напряжение на него подаётся с той же шумной цифровой шины. Наконец, клемма источника питания развязана параллельно включёнными конденсаторами, чтобы сохранить низкий импеданс на всех частотах. Последовательная индуктивность ESL и сопротивление ESR электролитического конденсатора снижает его эффективность на высоких частотах, где эстафету перенимает небольшой керамический собрат, см. Часть X1 [* ##§X1.3 ] . В предложенной схеме можно было бы снизить требования, т.к. точности 6 разрядов [* потенциометру ] хватит за глаза, а все перечисленные выше рекомендации относятся к режиму максимальной точности АЦП. Но лучше сразу привыкать проектировать схемы должным образом.

15.2.1.E Генератор

А генератора-то нет! Выбранный контроллер, подобно множеству других, имеет несколько внутренних источников тактирования, а именно два: 8 MHz и 128 kHz удовлетворительной точности ( ±10% ).

15.2.2 Код для микроконтроллера

Встроенное программное обеспечение - микропрограмма - должна решать несколько задач.

  1. Провести инициализацию при включении питания ( установить режим работы портов ввода-вывода, АЦП, компаратора и установить выходы в рабочее состояние ).
  2. Подать питание на потенциометр на 25 ms , считать выходной уровень и снять питание.
  3. Подсчитать на основе полученного с потенциометра напряжения величину дозы в полных циклах заряд-разряд пилообразного генератора.
  4. Использовать выход компаратора для подсчёта числа циклов полного заряда-разряда и формирования разрядного импульса.
  5. По достижении нужного числа циклов активировать сирену.

Кроме того, есть ещё несколько рабочих параметров ( например, частота генератора ), на которые программа повлиять не может, и которые должны быть установлены в момент загрузки кода в кристалл. Эти параметры, они называются «перемычками» ( «fuse» ), будут разобраны чуть позже.

15.2.2.A Псевдокод

Все перечисленные задачи переложены в текст на псевдокоде 15.1 . Псевдокод - неформальная текстовая замена для структурной схемы .

Псевдокод 15.1 Алгоритм экспонометра

Setup
  Variables:
    Define 32-bit integers count and termcount
  Low Power:
    Disable unused peripherals
  Ports:
    Set as outputs PC1 (potbias), PD0 (cap discharge) andPD1 (buzzer);
    set as analog inputs PC0 (pot readout) and PD7 (cap voltage);
    initialize PD1 LOW (buzzer off), and PD0 HIGH (cap held at gnd)
  Analog modes:
    Set comparator mode & bandgap ref;
    set ADC ref to Vcc, ADC mode to left-adjusted, and MUX to channel 0

Read “bake” setting
  Setbits PC1 (power to pot) and ADEN (ADC enable);
  wait 100 ms
  Start ADC conversion (setbit ADSC)
  Wait while ADSC=1 (busy), then read unsigned 8-bit result (“bake”)
  Clearbits PC1 and ADEN, and disable ADC to save power
  Compute termcount=360000 x bake/256

Count Cycles
  Wait while comparator is HIGH (Vcap < Vref), then:
    setbit PD0, then clearbit PD0 (software discharge pulse)
    increment count
    if count<termcount, repeat Count Cycles
      otherwise set bit PD1 (buzzer), clear 10 sec later 

Краткие пояснения. Код начинается с настроечных задач ( «Setup» ). Они требуются для периферийных устройств, которыми забит кристалл, настройки рабочих режимов и функций ввода-вывода _9 . Гибкость - это и удобство, и проблема. Удобства очевидны, поговорим о проблемах. Требуется изрядная внимательность, чтобы выставить все опции правильно. Делается это изменением состояния отдельных битов в массиве периферийных регистров микросхемы. У выбранного процессора таких регистров 256 , из которых около 40 отвечают за опции и настройки. Устанавливать их все нет нужды, потому что по умолчанию они получают вполне разумные значения. Потребуется менять только настройки компаратора, АЦП и портов ввода-вывода.

Код, стартующий после включения, должен выполнить именно эту задачу. Каждая линия порта может быть индивидуально настроена на вход или на выход: для этого надо выставить нужным образом биты в регистре направления передачи, а для входов можно включить или выключить внутренние подтяжки. Дальше выход пьезо-пищалки переводится в состояние НИЗКИЙ, а выход активации разряда - в состояние ВЫСОКИЙ. Завершается настройка выбором источника опорного напряжения для компаратора и АЦП, установкой масштабного коэффициента и источника аналогового сигнала. Наконец, ещё несколько бит отвечают за источник тактирования ( внешний/внутренний ), частоту и делитель. В данном микроконтроллере биты тактового сигнала входят в число «перемычек» , устанавливаются при загрузке кода в кристалл и исполняемой программе недоступны 10 .

Дальше идёт инициализация. Выходные линий зуммера и разряда устанавливаются в НИЗКОЕ состояние, заводится и обнуляется регистровая переменная «count», где будет накапливаться число циклов генератора пилы.

Читаем ( «Read “bake” setting» ) состояние потенциометра, задающего дозу. Для этого надо выдать на вывод «PC1» уровень Vcc , подождать 25 ms , запустить АЦП, подождать флага готовности данных, прочитать старший байт 10-разрядного результата ( в этой задаче точность лучше 0.5% не нужна ), снять питание с потенциометра и рассчитать требуемое число циклов интегратора. Последняя цифра предполагает нормальную пилу частотой 100 Hz с интегратора ( фототок 1 μA ) и полный цикл 90 минут.

Всё перечисленное занимает менее секунды. Дальше надо считать ( «Count Cycles» ) циклы пилы, длительность которых зависит от реального фототока, а спадающий фронт формируется программным импульсом ( ВЫСОКИЙ, затем НИЗКИЙ ) на затворе МОП транзистора. Делать процессору больше нечего, поэтому здесь просто опрашивается выход компаратора, хотя красивее было бы использовать прерывание ( в предложенных настройках прерывания запрещены ). Когда счётчик циклов досчитает до целевого значения, программа включит зуммер и войдёт в «бесконечный» цикл, т.е. перезапуск программы возможен только через выключатель питания.

15.2.2.B Развёрнутый код на Си

В листинге 15.1 приведён исходный код на Си. Программисты, знакомые с ним, легко разберутся. Отметим несколько особенностей, относящихся к микроконтроллерам. Файл «io.h» и «fuse.h» хранят определения для регистров, функций и т.д., учитывающих особенности внутреннего устройства конкретного контроллера ( фрагментация адресов, битовые переменные ). Непосредственное общение с битами в регистрах и портах - совершенно обычное дело для работы с микроконтроллерами. Выбор бита производится наложением маски. Сначала выбирается позиция бита в регистре ( по соответствующему «define» в заголовочном файле ), после чего создаётся маска для операции «ИЛИ» ( «1<<n» ) либо «И» ( «~(1<<n)» ). Скажем, для имени «PORTC1» в файле «io.h» указана позиция 1 [* счёт идёт с 0 ] , поэтому выражение « #define POT ( 1<<PORTC1 )» присваивает имени «POT» значение 0x02 [* т.е. отмечается второй справа бит ] . Здесь есть хитрая ловушка . В программах, подобных этой, значения считываются из регистров периферии ( компаратор, АЦП ), отображённых в память. Соответствующие переменные требуется отмечать модификатором «volatile», чтобы исключить «оптимизацию» операций с ними, при которой обращение к регистру может быть исключено компилятором. Именно для таких целей используется файл «io.h», где перечислены адреса памяти регистров периферии, но туда можно добавить и дополнительные переменные с долгим сроком жизни.

Программа 15.1

#include <avr/io.h>
#include <avr/fuse.h>
#include <util/delay.h>

#define DISCHARGE  (1<<PORTD0)
#define BUZZER     (1<<PORTD1)
#define POT        (1<<PORTC1)

int main() {

  long    termcount, count;     // Total timer counts and running counter

  // Power saving measures
  PRR     =   ~(1<<PRADC) & ~(1<<PRSPI); // Shut off peripherals except ADC & SPI
  DIDR0   =   0x3f;             // Disable digital input buffers on analog pins

  // Setup the pins
  DDRD    =   DISCHARGE | BUZZER; // Set two pins to output, rest to input
  DDRC    =   POT;                // Set the POT pin to output, rest to input
  DIDR0  |=   (1<<ADC0D);         // Use PC0 as ADC0 -- the ADC input
  DIDR1  |=   (1<<AIN1D);         // Use PD7 as AIN1 -- the comparator input
  PORTD   =   BUZZER;             // Hold cap low, and start with buzzer off

  // Comparator Setup
  ACSR    =   (1<<ACBG);          // Set the reference to the band gap (needs 70 us)

  // Read the desired exposure duration
  PORTC  |=   POT;                // Turn on the top of the resistor divider.

  _delay_ms(25);                  // Delay 25 ms for 10RC settle

  ADMUX   =   (1<<REFS0) | (1<<ADLAR); // Use Vcc ref; left-adjusted result
  ADCSRA  =   (1<<ADEN)  | (1<<ADSC);  // Enable, and start ADC

  /*** Wait until ADC conversion is done. ***/
  while ( ADCSRA & (1<<ADSC) )  { }

  termcount = (360000L * ADCH) >> 8; // Convert ADC result to timer count
  PORTC  &=   ~POT;               // Turn off the top of the resistor divider
  ADCSRA &=   ~(1<<ADEN);         // Disable ADC
  PRR    |=   (1<<PRADC);         // Enable power-reduction for ADC

  /*** Wait until desired sunlight exposure ***/
  for (count = 0; count < termcount; count++) {
    // Wait for cap to charge, then comparator output goes low
    while(ACSR & (1<<ACO))   { }

    PORTD  |= DISCHARGE;          // Discharge the capacitor
    PORTD  &= "DISCHARGE;         // And release it to recharge
  }

  // Buzz for 10 seconds
  PORTD  |= BUZZER;               // Power the buzzer
  _delay_ms(10*1000);             // Delay 10 seconds
  PORTD   = BUZZER;               // Turn off buzzer

  // Loop forever
  while (1)  { }
} 

15.2.2.C Некоторые комментарии

  1. Для задания начального момента в устройстве используется включение питания. Другой способ - использовать кнопку, которая замыкает вывод порта на землю. Состояние данного вывода можно опрашивать программно или использовать прерывание «по уровню». Второй вариант красивее и позволяет переводить процессор в спящий режим ( <1 μA ) по завершении работы. А будить его будет прерывание по НИЗКОМУ уровню на выводе. В такой схеме можно вообще убрать переключатель питания, но делать этого не стоит, потому что при «слёте» программы единственным способом восстановить нормальную работу будет переподсоединение батареи. В конце концов, все мы знакомы с потребительской электроникой ( автоответчиками, камерами и т.п. ), которые внезапно зависают в каком-то положении, заставляя проводить «холодную перезагрузку»: вытаскивая шнур из розетки или вынимая батарейку. [* С другой стороны, ожидать, что в давно отлаженном устройстве с конкретной ограниченной функциональностью программа внезапно сойдёт с ума, наверно, не стоит. Здесь выбор за разработчиком ] .
  1. Выход компаратора позволяет узнать, перешло ли напряжение линейно возрастающего фронта пилы заданный уровень, и опрашивается программно. Вместо программного опроса можно использовать прерывание. Делать в программе больше нечего, поэтому заметных преимуществ такая модификация не даёт. В прерывании надо разряжать конденсатор и увеличивать счётчик, а основной цикл должен просто проверять значение счётчика.
  2. Микроконтроллер - устройство с большими возможностями. Приложив некоторые усилия можно добавить в экспонометр дополнительные опции: ЖК-индикатор с линейной шкалой, показывающий степень «прожарки» и цифры текущей освещённости, проигрыватель MP3, игру... [* и взлететь потом со всем этим ] .

15.2.2.D Загрузка кода

Последним шагом будет «прошивка» кристалла, т.е. загрузка бинарного файла, выданного компилятором, и установка «перемычек» . Вот как это делается.

  1. Необходимо подключить программный адаптер к нужным выводам микроконтроллера ( через предусмотренный для этого разъём внутрисхемного программирования ) и порту USB управляющего компьютера.
  2. Подать питание на целевое устройство.
  3. Запустить тест, проверяющий корректность подключения и определяющий модель контроллера.
  4. Выбрать нужное сочетание «перемычек» 11 и загрузить его.
  5. Выбрать требуемый файл прошивки на управляющем компьютере и загрузить его в программную память контроллера. Выбрать файл с содержимым EEPROM, если требуется, и загрузить его в память данных.
  6. Завершив загрузку, утилита программирования проведёт сброс целевого кристалла, после чего последний приступит к выполнению программы. Теперь адаптер можно отключить. Программа будет запускаться вновь вместе с очередным циклом включения питания.

15.2.2.E Замечания по интерфейсу пользователя

Коллега авторов Джим МакАртур ( Jim MacArthur ) предложил следующий комментарий.

Если бы, в книге разбирался бы интерфейс пользователя ( HI ), предложенный вариант был бы учебным заданием по исправлению отклонений от спецификации. Задание звучит проще некуда: повторите функциональность аналогового решения. И ваш тестировщик интерфейса, несомненно, скажет, что данный вариант отличается от аналогового в одной важной детали: если изменить положение потенциометра в середине экспозиции, аналоговая схема это учтёт, а цифровая - нет 12 . Дальше проверяющий не без занудства сообщит, что 47% пользователей действуют строго определённым образом: сначала включают питание, а затем крутят регулятор. 13% этих людей возвратят устройство, не сделав ни одной попытки разобраться, в чём дело, компания потеряет миллионы, а вы лишитесь премии. Мораль:

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

15.2.2.F Ревизия разработки

После отрезвляющего общения со специалистом по интерфейсам было решено провести ревизию всей разработки. Кто-то обратил внимание, что вещь, лежащая на раскалённом солнцем песке, сильно нагревается. «Скажите пользователю, чтобы клал экспонометр в тень под шезлонгом». Это предложение вызвало полный ступор. Для проверки сомнений было проведено моделирование при 85°C . Это достаточно много и ток утечки BSS123, удваивающийся каждые 10°C , достиг совершенно неприемлемого уровня 3.2 μA ( т.е. в 64 раза больше, чем 50 nA при 25°C ). Опа! Интересно, что параметры компаратора при этом не изменились, потому что его входной ток 50 pA нормируется при 85°C . Кроме того, увеличился темновой ток фотодетектора: с 50 pA при комнатной температуре до 3 nA в тепле. Но это изменение не выходит за допустимые границы.

Упражнение 15.1
Найдите замену для ключа на BSS123. Одним из вариантов будет адаптация метода с рис. 13.49 для микроконтроллера.
Подсказка Замените \(U_2\), \(U_3\) и \(U_4\) микроконтроллером. Учтите, что напряжение в точке «X» не имеет значения. В схеме 13.49 используется операционный усилитель LMC6842, для которого указывается входной ток 10 pA max при температуре 85°C , что очень хорошо, а плохо то, что ток потребления у него 1 mA . ОУ станет основным потребителем. Попробуйте, может, найдёте решение получше.

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

6 Многие микроконтроллеры используют режим пониженного потребления при низком напряжении питания, например, 1.8 V , но не включают его при уровнях 3...5V . <-

7 Зато можно быть вполне уверенным, что типовой ток утечки, скорее всего, ниже 10 nA , т.к. специфицируется при полном промышленном диапазоне температур –40°...+85°C . Обычно производители кремния бывают очень консервативны при указании значений утечек, и в данном случае беспокоиться не о чем: по спецификации максимальное значение входного тока компаратора 50 nA . <-

8 BSS123 является аналогом 2N7000 и 2N7002, см. табл. 3.4a .   <-

9 Например, на 28-ой вывод корпуса заведён бит 5 ( из 8 ) порта «C». Кроме того, тот же вывод может использоваться как аналоговый вход АЦП ( через внутренний мультиплексор на 8 входов ), как тактовый вывод «SCL» и как «источник прерывания по изменению состояния». <-

10 У микроконтроллеров с большим числом выводов корпуса часто можно увидеть несколько ножек, отведённых на выбор режима начальной загрузки, состояние которых влияет на поведение стартового кода. <-

11 Для AVR в их число входят: напряжение срабатывания внутреннего детектора питания, разрешение/запрет отладки, источник тактового сигнала ( внутренний, внешнее тактирование, внешний кристалл ), разрешение JTAG, SPI и сторожевого таймера. <-

12 Но программу можно подправить, чтобы цифровая система тоже «учитывала» изменения. <-

Previous part:

Next part:

14 final checking; (cmp w/orig) 16 images to SS; 17 final vision & links checking;