Двухразрядный термометр

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.


Этот двухразрядный светодиодный термометр автор изготовил в качестве подарка на день рождения сыну друга. Ему всего два года, и цифры он уже читает, а буквы — нет. Теперь он может узнавать температуру за окном самостоятельно. Датчиком в термометре служит микросхема DS18B20, работающая по протоколу 1-Wire, а микроконтроллер применён типа ATtiny84. Плата — квадратная со стороной в 25 мм, по размерам она сравнима с монетой в 50 пенсов. Автор планирует поместить плату во влагозащищённый корпус и разместить за окном. Индикация включается кратковременно раз в 24 секунды, и батарейки CR2032 хватает примерно на год.

Термометр работает в диапазоне от -19 до +99 °C. При необходимости в старшем разряде одновременно отображаются минус и единица. При выходе за пределы диапазона отображаются буквы Lo или Hi. Можно «научить» устройство отображать температуры ниже -19 °C, задействовав в качестве минуса сегмент с точкой.

По такой схеме устройство было предварительно собрано на макетке:



Задействованы все выводы микроконтроллера, использован встроенный тактовый генератор на 8 МГц. Протитип получился таким:



В прототипе применены DS18B20 в корпусе TO-92, ATtiny84 в корпусе PDIP и 3,6-дюймовый индикатор 3621AS. Затем автор разработал плату в Eagle и заказал её в PCBway. Здесь микроконтроллер уже в корпусе SOIC, датчик — в корпусе µSOP, а резисторы, конденсаторы и дисплей — типоразмера 0805. Всё, кроме дисплея, впаяно феном Youyue 858D+ при температуре в 250°C.

Как на прототипе, так и на печатной плате применены индикаторы с общим анодом. Устройство изготовлено в двух вариантах, с индикаторами красного и жёлтого цветов. Красный — на КДПВ, жёлтый — вот:



С обратной стороны впаян держатель для 20-миллиметрового литиевого элемента (любого с обозначением, начинающимся на 20, т.е., 2016, 2025 или 2032):



Прошивка написана таким образом, чтобы микроконтроллер большую часть времени находился в спящем режиме и просыпался по прерыванию от сторожевого таймера. В реализации интерфейса 1-Wire задействована эта наработка того же автора. Времязадающим является 16-битный таймер-счётчик микроконтроллера, работающий на частоте в 1 МГц:

void OneWireSetup () {
  TCCR1A = 0<<WGM10;                   // Normal mode
  TCCR1B = 0<<WGM12 | 2<<CS10;         // Normal mode, divide clock by 8
}


Подпрограмма DelayMicros() обеспечивает задержку в заданное число микросекунд, опираясь на регистр сравнения выхода OCR0A:

void DelayMicros (unsigned int micro) {
  TCNT1 = 0; TIFR1 = 1<<OCF1A;
  OCR1A = micro;
  while ((TIFR1 & 1<<OCF1A) == 0);
}


Подпрограмма DisplayTemperature() считывает значение температуры из датчика и отображает его. Поскольку датчик на шине всего один, на серийный номер можно не обращать внимание, и просто подать команду Skip ROM, после чего все последующие команды поступают на любое устройство:

void DisplayTemperature () {
  cli();                                  // No interrupts
  if (OneWireReset() != 0) {
    sei();
    DisplayError(0);                      // Device not found
  } else {
    OneWireWrite(SkipROM);
    OneWireWrite(ConvertT);
    while (OneWireRead() != 0xFF);
    OneWireReset();
    OneWireWrite(SkipROM);
    OneWireWrite(ReadScratchpad);
    OneWireReadBytes(9);
    sei();                                // Interrupts
    if (OneWireCRC(9) == 0) {
      int temp = DataWords[0];
      Display((temp+8)>>4);               // Round to nearest degree
    } else DisplayError(1);               // CRC error
  }
}


В ответ на запрос датчик возвращает значение температуры в виде 16-битного целого числа со знаком в единицах, равных 1/16 градуса. Число округляется до ближайшего целого градуса и отображается вызовом подпрограммы Display().

Подпрограмма DisplayError() отображает ошибки взаимодействия микроконтроллера с датчиком по шине 1-Wire:

void DisplayError (int no) {
  Buffer[0] = Error;
  Buffer[1] = no;
}


E0 — датчик не обнаружен, E1 — ошибка CRC.

Данные для динамической индикации берутся из массива Buffer[]. Например, чтобы отобразить число 20, надо выполнить:

Buffer[0]=2; Buffer[1]=0;


Таймер-счётчик 0 генерирует прерывания на частоте в 125 Гц, чего достаточно для устранения мерцания. Вначале таймер сконфигурирован в setup()"

TCCR0A = 2<<WGM00;                      // CTC mode; count up to OCR0A
  TCCR0B = 0<<WGM02 | 4<<CS00;            // Divide by 256
  OCR0A = 250-1;                          // Compare match at 125Hz
  TIMSK0 = 0;                             // Interrupts initially off


Процедура обработки прерывания совпадения при сравнении вызывает подпрограмму DisplayNextDigit() и затем считает в обратном направлении:

ISR(TIM0_COMPA_vect) {
  DisplayNextDigit();
  Ticks--;
}


Подпрограмма DisplayNextDigit() считывает данные из соответствующей ячейки массива Buffer[] и включает нужные сегменты в соответствующем разряде дисплея. Программа использует #define для выбора между индикатором с общим катодом или анодом. Если при подаче питания светятся сразу все сегменты, значит, тип дисплея не соответствует заданному в прошивке. Для общего катода подпрограмму надо заменить на такую:

void DisplayNextDigit () {
  PORTB = PORTB | 1<<digit;                    // Turn old digit off
  digit = digit ^ 1;                           // Toggle between 0 and 1
  char segs = charArray[Buffer[digit]];
  PORTA = segs;                                // Lit segments high
  PORTB = PORTB & ~(1<<digit);                 // Turn new digit on
}


Наконец, подпрограмма Display() вырабатывает двухзначное число для записи в массив Buffer[]:

void Display (int n) {
  int units = n % 10;
  int tens = n / 10;
  int temp0 = tens;
  int temp1 = abs(units);
  if (tens < -1) {temp0 = Lo; temp1 = Lo+1; }
  else if (tens > 9) {temp0 = Hi; temp1 = Hi+1; }
  else if (tens == -1) temp0 = Minus1;
  else if ((tens == 0) && (units >= 0)) temp0 = Blank;
  else if ((tens == 0) && (units < 0)) temp0 = Minus;
  Buffer[0] = temp0;
  Buffer[1] = temp1;
}


В ней же учтены случаи отображения минуса вместе с единицей в старшем разряде, а также сообщений о выходе температуры за пределы диапазона.

Для максимально возможного энергосбережения отключены АЦП, тактовые генераторы интерфейса USI и АЦП, и разрешён спящий режим PWR_DOWN:

  ADCSRA &= ~(1<<ADEN);                   // Disable ADC to save power
  PRR = 1<<PRUSI | 1<<PRADC;              // Turn off clocks to USI & ADC to save power
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);


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

void loop () {
  Buffer[0] = DP; Buffer[1] = Blank;
  DisplayOn(12);
  WDDelay(6);                              // Sleep for 1 second
  Buffer[0] = Blank; Buffer[1] = DP;
  DisplayOn(12);
  WDDelay(6);                              // Sleep for 1 second
  DisplayTemperature();
  DisplayOn(12);
  WDDelay(9);                              // Sleep for 8 seconds
  WDDelay(9);                              // Sleep for 16 seconds
  WDDelay(9);                              // Sleep for 24 seconds
}


Дисплей остаётся выключенным на 24 секунды за счёт трёх вызовов сторожевого таймера по 8 секунд каждый. При работающем индикаторе потребляемый ток составляет 6,6 мА, в спящем режиме — 4,7 мкА, средний потребляемый ток равен 1/240 * 6,6 мА. Типичная ёмкость элемента CR2032 равна 225 мАч, поэтому хватит его на (225/6.6) x 240 / 24 = 340 дней — чуть меньше года.

Температурные диапазоны компонентов следующие: микроконтроллера и индикатора — от -40 до +85°C, резисторов и конденсатора — от -55 до +125 °C, батарейки — от -20 до +70 °C. Элемент с расширенным температурным диапазоном BR2032 будет работать в диапазоне от -30 до +85 °C.

Микроконтроллер сделан Arduino-совместимым при помощи этой разработки Spence Konde. В IDE надо выбрать пункт ATtiny24/44/84 в разделе ATTinyCore меню Board. Затем надо выставить следующие опции, не обращая внимания на остальные:

Chip: "ATtiny84"
Clock: "8 MHz (internal)"
B.O.D: "B.O.D. Disabled"
Pin Mapping: "Clockwise (like damellis core)"


Программа залита при помощи приспособления Pomona test clip, размещённого поверх микроконтроллера и подключённого к программатору SparkFun Tiny AVR Programmer. Вначале надо выбрать Burn Bootloader, затем — Upload.

Ссылки: полный текст программы, плата и программа на GitHub, плата на OSHpark.
Источник: https://habr.com/ru/post/454220/


Интересные статьи

Интересные статьи

В обновлении «Сидней» Битрикс выпустил новый продукт в составе Битрикс24: магазины. Теперь в любом портале можно создать не только лендинг или многостраничный сайт, но даже интернет-магазин. С корзино...
Если честно, к Д7 у меня несколько неоднозначное отношение. В некоторых местах я попискиваю от восторга, а в некоторых хочется топать ногами и ругаться неприличными словами.
Cтатья будет полезна тем, кто думает какую выбрать CMS для интернет-магазина, сравнивает различные движки, ищет в них плюсы и минусы важные для себя.
На сегодняшний день у сервиса «Битрикс24» нет сотен гигабит трафика, нет огромного парка серверов (хотя и существующих, конечно, немало). Но для многих клиентов он является основным инструментом ...
Если Вы используете в своих проектах инфоблоки 2.0 и таблицы InnoDB, то есть шанс в один прекрасный момент столкнуться с ошибкой MySQL «SQL Error (1118): Row size too large. The maximum row si...