Простейший термометр на Attiny 2313 и датчике температуры ds18b20

AstreyRize

★✩✩✩✩✩✩
31 Июл 2018
7
18
Преамбула
Решил я перенести проект, который делал несколько лет назад на новую плату. Дело в том, что плата для этого термометра была возможно первой платой, которую я делал и как полагается первый блин вышел комом. Основой для платы послужил гетинакс, который в магазине мне продали под видом стеклотекстолита, а для разводки платы я использовал ЛУТ. Сейчас для изготовления плат я использую текстолит и ЧПУ фрезер, вот так выглядит разница в несколько лет:

DSC01475.jpg
Вот так работал термометр на старой плате:

vNre5f2aH00.jpgyGk9e5Kk_GM.jpgB431eENcP0E.jpg

Описание устройства
Итак, что же собой представляет простейший термометр? Это микроконтроллер attiny2313 (документация на русском), который общается с датчиком температуры ds18b20 (документация на русском) по протоколу 1-wire, дело в том, что датчик ds18b20 имеет всего 3 ноги, 2 из которых предназначены для питания и только одна для передачи данных. В схеме также используется подтягивающий резистор на 4.7КОм подключенный к шине 1-wire и плюсу источника питания.
2019-03-03_17-02-33.png 2019-03-03_17-30-26.png
Полученные от датчика данные микроконтроллер выводит на 7-сегментный 4-х разрядный индикатор. Для вывода данных на индикатор используется сдвиговый регистр 74hc595.

Что интересного можно сказать про датчик температуры ds18b20?
- Для предоставления данных о температуре используется от 9 до 12 бит. Чем больше бит, тем точнее информация о температуре, но тем больше нужно ждать, пока температура будет подготовлена для передачи от датчика получателю (микроконтроллеру). Вот табличка, в которой указано, сколько бит используется для представления температуры, какая при этом будет точность и сколько времени на это понадобится.

Кол-во. бит

Точность данных

Сколько времени потребуется для подготовки данных

9

0,5 (1/2) °C

~100мс

10

0,25 (1/4) °C

~200мс

11

0,125 (1/8) °C

~400мс

12

0,0625 (1/16) °C

~800мс

- Этот датчик может питаться непосредственно от линии данных, т.е. для подключения можно использовать только одну ногу. Минусом данного способа является не возможность опрашивать датчик, пока тот готовит температуру, т.к. при подготовке температуры энергопотребление датчика может существенно возрасти (до 1,5мА), и требуется, что бы на шине денных все это время был высокий логический уровень.
If the DS18B20 is powered with parasite power, this notification technique cannot be used since the bus must be pulled high by a strong pullup during the entire temperature conversion.
Есть способы обойти это ограничение, но об этом, может быть, поговорим в другой раз.
- У каждого датчика есть свой 64 битный адрес, таким образом можно на одной шине разместить несколько датчиков и опрашивать их используя адрес каждого конкретного датчика.
- Есть возможность установить верхний и нижний придел температуры, при котором датчик температуры передаст управляющему устройству сигнал тревоги. Так же есть возможность передать по шине команду "ПОИСК ТРЕВОЖНОГО СИГНАЛА [ECh]" при котором все датчики проверят свое состояние, и датчики с данным признаком ответят.

Что интересного можно сказать про сдвиговый регистр?
Данная микросхема содержит внутри себя два регистра. Первый регистр - сдвиговый: 8-StageShiftRegister. Второй регистр - регистр хранения данных: 8-BitStorageRegister.
2019-03-03_18-36-58.png
Для записи в сдвиговый регистр используется два входа: DS и SHCP. Сначала устанавливаем на входе DS логический ноль или логическую единицу, затем подаем на вход SHCP тактовый сигнал и бит данных записан. При повторной записи информация, записанная ранее, сдвинется на один бит вперед. Если записанные данные выходят за предел регистра - они безвозвратно теряются. Вход MS используется для очистки сдвигового регистра. Обратите внимание, что данный вход относиться только к сдвиговому регистру, а не ко всей микросхеме.
Вход STCP используется для записи данных из сдвигового регистра в регистр хранения.
Вход OE разрешает выводить данные.
Более подробную информацию о том, как сигналы на выводах микросхем влияют на ее работу можно найти в таблице ниже:
2019-03-03_18-48-20.png
В последней строке описано, что будет, если подать тактовый сигнал сразу на выходы SHCP и STCP: Сначала все содержимое сдвигового регистра будет скопировано в регистр хранения, а потом произойдет запись данных в регистре сдвига. На сайте tinkerkcad можно поиграться с 4-х битным сдвиговым регистром, собранным на основе D-триггеров. Левый переключатель соответствует входу DS, правый - SHCP.
 
Изменено:

AstreyRize

★✩✩✩✩✩✩
31 Июл 2018
7
18
Разработка схемы
Схема проекта доступна на сайте Easy EDA. Однако спешу предупредить, что после изготовления платы показалось, что размеры 7-сегментоного индикатора в Easy EDA меньше реальных и на плату он не поместился! Далее я опишу, как я это обыграл.
При разводке платы просто соединяем все контакты сдвигового регистра с контактами индикатора так, чтобы они не пересекались на плате - это позволит нам сделать одностороннюю плату, а какой бит за какой сегмент будет отвечать, мы запрограммируем в микроконтроллере. Для отображения информации на всех разрядах индикатора будем использовать динамическую индикацию. Первый разряд я отвел для знака, второй и третий для температуры, далее отображается точка и десятая часть температуры. Как это выглядит можно посмотреть в преамбуле.

Написание прошивки
Прошивка доступна для скачивания на github. Для разработки я использовал программу CVAVR. Давайте разберем некоторые моменты:

Для начала определимся, какие комбинации бит соответствуют цифрам на индикаторе. Эти биты нужно будет "протолкнуть" в сдвиговый регистр, что бы отобразить соответствующие число:
C:
// Цифры для e40561
unsigned char numbers[11] =
{
    //BFAGCpDE
    0b00010100, //0
    0b01110111, //1
    0b01001100, //2
    0b01000101, //3
    0b00100111, //4
    0b10000101, //5
    0b10000100, //6
    0b01010111, //7
    0b00000100, //8
    0b00000101, //9
    0b11101111  //-
};
Каждый разряд индикатора подключен к ноге микроконтроллера, таким образом что бы включить конкретный разряд нужно, что бы ток вытекал из сдвигового регистра, протекал через индикатор и "втекал" в ногу МК, отвечающую за разряд. Для этого настраиваем порты микроконтроллера как нагрузку. Исходя из документации нужно установить регистры DDxn, PORTxn как указано в таблице ниже:
2019-03-03_19-37-36.png
Делаем так для порта B0, B1, B2, B3:
C:
// Port B initialization
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
Т.к. порты микроконтроллера соединены с разрядами индикатора не по порядку, задаем порядок в массиве:
C:
unsigned char digit[4] =
{
    0b00000001, //разряд 1
    0b00001000, //разряд 2
    0b00000100, //разряд 3
    0b00000010, //разряд 4
};
Теперь нам просто нужно взять число и получить все цифры из которых оно состоит, я думаю лучше всего объяснить как это сделать можно, просто показав пример:
C:
120 % 10 = 0 // Получили единицы.
120 / 10 = 12 // Отбрасываем дробную часть.

12 % 10 = 2  // Получили десятки.
12 / 10 = 1 // Отбрасываем дробную часть.

1 % 10 = 1 // Получили сотни.
Таким образом, алгоритм получается такой:
1. Определяем знак, если число меньше нуля выводим в первом разряде "-"
1.1. Для этого из массива numbers получаем набор бит, который соответствует знаку "-"​
1.2. Все биты по очереди проталкиваем в сдвиговый регистр​
2. Зажигаем первый по порядку регистр:
PORTB = 0b00000010;
ждем миллисекунду и тушим его:
delay_ms(1);
PORTB = 0b00000000;
3. Выводим десятую часть температуры
3.1. С помощью представленного выше алгоритма получаем десятую долю числа​
3.2. Из массива чисел получаем набор бит для этого числа: bits = numbers[number];​
3.3. Проталкиваем все биты в сдвиговый регистр​
3.4. Зажигаем соответствующий разряд, ждем 1мс и тушим.​
4. Повторяем шаг 3 для всех последующих цифр числа.

А вот и реализация данного алгоритма:
C:
// Показать цифру на индткаторе e40561
void SetNumber(unsigned char number, unsigned char mask)
{
    unsigned char bits;
    unsigned char i = 0;

    bits = numbers[number];
    bits ^= mask;

    for(i = 0; i < 8; i++)
    {
          DS = (bits>>i) & 1;
          SH_CP = 1;
          SH_CP = 0;
    }

    ST_CP = 1;
    ST_CP = 0;
}

void SetMinus()
{
    unsigned char bits;
    unsigned char i = 0;

    bits = numbers[10];

    for(i = 0; i < 8; i++)
    {
          DS = (bits>>i) & 1;
          SH_CP = 1;
          SH_CP = 0;
    }

    ST_CP = 1;
    ST_CP = 0;
}

// Отобразить число на индикаторе e40561
void ShowNumber(int temp)
{
    unsigned char step = 0;

    // Самый левый заполняем знаком
    if(temp < 0)
    {
        SetMinus();
        PORTB = 0b00000010;
        delay_ms(1);
        PORTB = 0b00000000;
    }

    // Первые 3 разряда справа заполняем числами
    do
    {
        if(step == 1)
        {
            //Младший разряд отображаем с точкой
            SetNumber(ABS(temp) % 10, 0b00000100);
        }
        else
        {
            SetNumber(ABS(temp) % 10, 0b00000000);
        }

        PORTB = digit[step];
        delay_ms(1);
        PORTB = 0b00000000;

        temp /= 10;
        step++;
    }
    while(temp && step < 3);
}
Управление датчиком температуры осуществляется с помощью встроенной библиотеки, однако эта библиотека имеет один существенный минус: для отображения чисел нам нужно каждую 1мс переключать разряды, однако при вызове библиотечной функции микроконтроллер отправляет запрос на получение температуры и ждет, пока датчик проведет конвертацию. Из таблицы выше мы видим, что это время может быть от 100 до 800мс и это время микроконтроллер ничего не делает, вот этот момент в библиотеке:
C:
// temp. conversion time [ms] depending on the resolution
static flash int conv_delay[4]={100,200,400,800};

....

float ds18b20_temperature(unsigned char* addr)
{
    unsigned char resolution;
    if (ds18b20_read_spd(addr) == 0)
        return -9999;
    resolution = (__ds18b20_scratch_pad.conf_register >> 5) & 3;
    if (ds18b20_select(addr) == 0)
        return -9999;
    w1_write(0x44);
    delay_ms(conv_delay[resolution]);  // Здесь мы ждем заданное количество времени.
    if (ds18b20_read_spd(addr) == 0)
        return -9999;
    w1_init();
    return (*((int*)&__ds18b20_scratch_pad.temp_lsb) & ((int)bit_mask[resolution])) * 0.0625;
}
Что бы исправить это я разбил функцию на две, одна функция запрашивает данные, а вторая получает готовую температуру. Исправленную библиотеку можно найти в папке с проектом.

Разработка корпуса
Как я выше писал: после изготовления платы обнаружилось что индикатор из библиотеки Easy EDA на 10мм короче, чем мой и таким образом расположить индикатор на плате стало невозможно, поэтому я решил соединить индикатор и плату проводами и напечатать корпус на принтере. Детали корпуса я спроектировал в Kompas 3D и напечатал на своем принтере Anycubic i3 Mega. Так выглядит модель в Kompas 3D:
2019-03-03_20-58-48.png2019-03-03_20-59-13.png2019-03-03_20-57-49.png2019-03-03_20-58-02.png

Тут же выкладываю файлы для Kompas 3D v17.1, они будут в аттаче.

Получился вот такой бутерброд:
DSC01479.jpgDSC01480.jpg

Результат
Ну и собственно, вот что получилось:
DSC01483.jpg
 

Вложения

Изменено:
Вещь конечно нужная, но у Вас как то всё сложно. Вот схема и прошивка для Attiny2313 в другом исполнении. Без всяких сдвиговых регистров.
Термометр на ATtiny2313 схема.jpg
 

Вложения

Изменено:
  • Лойс +1
Реакции: Wan-Derer

AstreyRize

★✩✩✩✩✩✩
31 Июл 2018
7
18
Вещь конечно нужная, но у Вас как то всё сложно. Вот схема и прошивка для Attiny2313 в другом исполнении. Без всяких сдвиговых регистров.
Посмотреть вложение 3883
Ага, такая схема имеет место быть. Просто тогда я учился использовать сдвиговые регистры, а в этом посту я рассказал, как переделывал плату с тех бородатых времен и заодно расписал основные моменты, если кто-то захочет разобраться в сдвиговых регистрах.
 

dankr

✩✩✩✩✩✩✩
16 Янв 2020
2
0
Здравствуйте. Меня интересует схема 2-х канального термометра на МК. Я ищу любителя-программиста, который бы мне помог воплотить в жизнь свою задумку. Немного расширить функционал термометра, использовать более крупный ЖК дисплей, добавить некоторые модуля. Если кто в принципе согласен, то можно пообщаться и развить тему далее. И в этом случае заодно скажите пожалуйста регион вашего проживания и ну и почту для общения.
 
Здравствуйте! Схем таких в инете хоть пруд, пруди. Вот схема на Attiny2313, с разжёванным кодом. https://cxem.net/mc/mc205.php Схемы термометра на ATMega8 http://tutlay.ru/radioshemy/r1/82-termometr-na-atmega8-i-2-4-datchika-ds18b20.html и вот https://microkontroller.ru/shemyi-k...dvuhkanalnyiy-termometr-na-atmega8-i-ds18b20/ и вот ещё https://www.radiokot.ru/circuit/digital/home/128/ Полно вариантов для творчества! :)
 

dankr

✩✩✩✩✩✩✩
16 Янв 2020
2
0
Спасибо. Но это всё не то. Многие схемы интересны, но почти в каждой чего-то не хватает. У меня дисплей ЖК специализированный, WO12864D3-TGK от кассового аппарата MINI-T 400 МЕ. А почему именно этот - потому что у меня их несколько лежат на полке, покупать не надо. Ну и специализированные модуля датчиков давления I2C/SPI BMP280 и часов DS3231 AT24C32 II (только для календаря) и своим оформлением дисплея. А так как я не программист, то мне это не осилить. Могу плату страссировать, помакетировать под руководством, собрать. Потому и ищу любителя энтузиаста. В любом случае спасибо за помощь и то, что откликнулись.