Высокотемпературный электронный термометр на ATTiny13, MAX6675 и TM1637
Решил сделать свою паяльную станцию и возник вопрос о её калибровке. Покупать на Али высокотемпературный точный измеритель температуры просто жаба задавила. Дома были в наличии простенькие микроконтроллеры ATTiny13 и четырёхразрядный дисплей на TM1637. А также завалялась пара аккумуляторов от электронных сигарет и термопара от мультиметра.
Поэтому решил сделать свой высокотемпературный электронный термометр, используя специализированную микросхему преобразователь для термопар K-типа.
Самая простая, которая была на Али, это MAX6675.
Заодно, решил проверить сколько кода нужно, по минимуму, для вывода данных на TM1637, если писать код без использования библиотек.
В качестве термопары используется хорошо знакомая версия для мультиметров. Цена на Али меньше трёх долларов за пару. Там именно термопара типа К, которая нужна для MAX6675.
На Али были куплены три микросхемы MAX6675 за четыре доллара. Там же был куплен пластиковый корпус размером 73X43X23mm за доллар.
Немного помудрил со схемой, чтобы удобнее было собирать всё до кучи и ножки одной микросхемы удобно попадали напротив ножек другой.
В результате получилась такая схема:

На схеме также указана распиновка Arduino Nano и её пины, к которым подключалась схема при тестировании кода с Arduino Nano вместо ATTiny13.
Код писался в Arduino IDE 1.8.19.
Размер скетча при компиляции получился 362 байта. Так что желающие могут попробовать нарастить функционал. Например, фиксация максимального напряжения. Или запись температуры в память по кнопке, которые поддерживаются TM1637, и индикация по вызову сохранённых значений. Звуковая индикация разных событий (тоже через TM1637) и т.д…
В качестве программатора использовал Arduino Nano, прошитый под ISP программатор. При попытке прошивки иногда выдавалась ошибка. Устранялась повторным запуском процесса прошивки. Два раза подряд ошибка ни разу не выскакивала.
Ядро использовалось MicroCore.
Настройки Arduino IDE при прошивке вот такие:
Проверил написанный код с этой схемой в Proteus. Всё ОК.
Спаял, прошил – не работает. ((
Заменил ATTiny13 на Arduino Nano. Прошил тем же кодом. Всё работает.
Путём проб и ошибок и с помощью осциллографа выяснил, что вся проблема в величине пауз между сигналами на входе TM1637. При слишком коротких паузах, TM1637 не успевает отрабатывать команды СТАРТ, СТОП и ЗАПИСЬ БАЙТА.
Подобрал правильные паузы. Заработало.
При проверке точности получилось, что прибор завышает показания примерно на три градуса (проверял по комнатной температуре, температуре тела и по кипящей воде).
Внёс поправку в код скетча на минус три градуса. Стал показывать точно 100 при окунании в кипящую воду, 36 градусов в качестве медицинского термометра и при сравнении с комнатной температурой по обычному термометру разбежность ушла. Вроде нормально, учитывая паспортную погрешность MAX6675.
При сравнении показаний от трёх термопар от мультиметров, расхождения между ними не превышали одного градуса. То есть даже дешевые термопары от мультиметров штука достаточно стабильная.
Потом решил сэкономить ещё чуток памяти контроллера и заменил паузы между сменами уровней на выходе контроллера просто повторными выдачами команд на установку нужного уровня сигнала на выходах контроллера, идущих к TM1637.
Получилось. Работает.
Теперь, с учётом этих нюансов, можно пробовать сделать паяльную станцию с дисплеем TM1637 на базе ATTiny13.
С монтажом решил не заморачиваться.
Всё паялось навесным монтажом с использованием переходников для микросхем контроллера и MAX6675.
Внутри корпуса всё крепилось на горячий клей.
Фото результата:
1. Температура в комнате

2. Вид внутри

3. Заряжаем от USBmicro

4. Моя температура тела

Код скетча прилагается:
Поэтому решил сделать свой высокотемпературный электронный термометр, используя специализированную микросхему преобразователь для термопар K-типа.
Самая простая, которая была на Али, это MAX6675.
Заодно, решил проверить сколько кода нужно, по минимуму, для вывода данных на TM1637, если писать код без использования библиотек.
В качестве термопары используется хорошо знакомая версия для мультиметров. Цена на Али меньше трёх долларов за пару. Там именно термопара типа К, которая нужна для MAX6675.
На Али были куплены три микросхемы MAX6675 за четыре доллара. Там же был куплен пластиковый корпус размером 73X43X23mm за доллар.
Немного помудрил со схемой, чтобы удобнее было собирать всё до кучи и ножки одной микросхемы удобно попадали напротив ножек другой.
В результате получилась такая схема:

На схеме также указана распиновка Arduino Nano и её пины, к которым подключалась схема при тестировании кода с Arduino Nano вместо ATTiny13.
Код писался в Arduino IDE 1.8.19.
Размер скетча при компиляции получился 362 байта. Так что желающие могут попробовать нарастить функционал. Например, фиксация максимального напряжения. Или запись температуры в память по кнопке, которые поддерживаются TM1637, и индикация по вызову сохранённых значений. Звуковая индикация разных событий (тоже через TM1637) и т.д…
В качестве программатора использовал Arduino Nano, прошитый под ISP программатор. При попытке прошивки иногда выдавалась ошибка. Устранялась повторным запуском процесса прошивки. Два раза подряд ошибка ни разу не выскакивала.
Ядро использовалось MicroCore.
Настройки Arduino IDE при прошивке вот такие:
Проверил написанный код с этой схемой в Proteus. Всё ОК.
Спаял, прошил – не работает. ((Заменил ATTiny13 на Arduino Nano. Прошил тем же кодом. Всё работает.
Путём проб и ошибок и с помощью осциллографа выяснил, что вся проблема в величине пауз между сигналами на входе TM1637. При слишком коротких паузах, TM1637 не успевает отрабатывать команды СТАРТ, СТОП и ЗАПИСЬ БАЙТА.
Подобрал правильные паузы. Заработало.
При проверке точности получилось, что прибор завышает показания примерно на три градуса (проверял по комнатной температуре, температуре тела и по кипящей воде).
Внёс поправку в код скетча на минус три градуса. Стал показывать точно 100 при окунании в кипящую воду, 36 градусов в качестве медицинского термометра и при сравнении с комнатной температурой по обычному термометру разбежность ушла. Вроде нормально, учитывая паспортную погрешность MAX6675.
При сравнении показаний от трёх термопар от мультиметров, расхождения между ними не превышали одного градуса. То есть даже дешевые термопары от мультиметров штука достаточно стабильная.
Потом решил сэкономить ещё чуток памяти контроллера и заменил паузы между сменами уровней на выходе контроллера просто повторными выдачами команд на установку нужного уровня сигнала на выходах контроллера, идущих к TM1637.
Получилось. Работает.
Теперь, с учётом этих нюансов, можно пробовать сделать паяльную станцию с дисплеем TM1637 на базе ATTiny13.
С монтажом решил не заморачиваться.
Всё паялось навесным монтажом с использованием переходников для микросхем контроллера и MAX6675.
Внутри корпуса всё крепилось на горячий клей.
Фото результата:
1. Температура в комнате

2. Вид внутри

3. Заряжаем от USBmicro

4. Моя температура тела

Код скетча прилагается:
// Точный термометр до 1000 градусов на ATTiny13 с MAX6675 и TM1637
// есть отображение значка градусов в 4-ом разряде
//
// Скетч использует 362 байт (35%) памяти устройства. Всего доступно 1024 байт.
// Глобальные переменные используют 0 байт (0%) динамической памяти, оставляя 64 байт для локальных переменных. Максимум: 64 байт.
// Обновление данных 1 раз в секунду.
// Усреднение по четырём замерам
// Значёк градуса в правом разряде дисплея
// В коде поправка на -3 градуса - при этом точность температуры в комнате, температуры тела и температуры кипения воды - до одного градуса
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
// Определить пины для кодключения к МАХ6675
#define miso PB0 // MAX6675 MISO - 5 ножка ATtiny13
#define cs PB1 // MAX6675 CS - выбор микросхемы - 6 ножка ATtiny13
#define clk PB2 // MAX6675 CLK - 7 ножка ATtiny13
// Определить состояние пинов для кодключения к TM1637
#define DIO_H() (PORTB |= _BV(PB4))
#define DIO_L() (PORTB &= ~_BV(PB4))
#define DIO_OUT() (DDRB |= _BV(PB4))
#define DIO_IN() (DDRB &= ~_BV(PB4))
#define DIO_RD() (((PINB & _BV(PB4)) > 0) ? 1 : 0)
#define CLK_H() (PORTB |= _BV(PB3))
#define CLK_L() (PORTB &= ~_BV(PB3))
//------------- ¤ркость свечени¤ индикатора TM1637 ----------
#define Bright0 0x88
#define Bright1 0x89
#define Bright2 0x8A
#define Bright3 0x8B
#define Bright4 0x8C
#define Bright5 0x8D
#define Bright6 0x8E
#define Bright7 0x8F
#define SetBright Bright5 //сюда прописать ¤ркость от 0 до 7. По умолчанию 5.
//------------------------------------------------------------------
// Коды цифр 0-9, пусто и значка градуса для сегментов (A-B-C-D-E-F-G)
const uint8_t digits[] PROGMEM =
{
// Соответствие разрядов и сегментов
0x3F, // 0 - B00111111
0x06, // 1 - B00000110
0x5B, // 2 - B01011011
0x4F, // 3 - B01001111
0x66, // 4 - B01100110 _1_
0x6D, // 5 - B01101101 6 | | 2
0x7D, // 6 - B01111101 |_7_|
0x07, // 7 - B00000111 5 | | 3
0x7F, // 8 - B01111111 |_4_|
0x6F, // 9 - B01101111
0x00, // пусто - B00000000
0x63 // градус - B001100011
};
//********************************************************************************************************
//*************************** SETUP *****************************************************************
int main(void)
{
//=================== Инициализация дисплея ===================
DDRB |= (_BV(PB4)|_BV(PB3)); // Настройка PB3 и PB4 на выход
PORTB &= ~(_BV(PB4)|_BV(PB3)); // Установка PB3 и PB4 в ноль
delay_msTK(100);
#if F_CPU != 9600000UL
#error "Частота в коде не совпадает с настройками IDE!"
#endif
//********************************************************************************************************
//********************* ОСНОВНОЙ ЦИКЛ ******************************************************************
while(1)
{
int t = getSmoothTemp(); //Читаем усреднённые данные из модуля термопары MAX6675 и ...
if (t > 3) // ... вычитаем поправку (у меня выдавал без поправки на три градуса больше)
t = t - 3;
byte ks = 0;
byte kd = 0;
while (t>=100)
{
t-=100;
ks++;
}
while (t>=10)
{
t-=10;
kd++;
}
//************ Выводим число на индикатор *******************
if (ks==0)
ks=10;
// 1. Команда установки данных (0x40 - автоинкремент адреса)
start();
writeByte(0x40);
stop();
// 2. Установка адреса начала (0xC0) и передача 4 цифр
start();
writeByte(0xC0);
writeByte(pgm_read_byte(&digits[ks])); // Первая цифра
writeByte(pgm_read_byte(&digits[kd])); // Вторая
writeByte(pgm_read_byte(&digits[t])); // Третья
writeByte(pgm_read_byte(&digits[11])); // Четвертая
stop();
// 3. Установка яркости (0x88 - включено, средняя яркость)
start();
writeByte(SetBright);
stop();
delay_msTK(100); // задержка
}
}
//********************* КОНЕЦ MAIN ******************************************************************
//*****************************************************************************************************
//*****************************************************************************************************
//*****************************************************************************************************
//********************* ФУНКЦИИ *********************************************************************
//------------------------------------------------------
//--------- Функция отправки одного байта ------------
void writeByte(uint8_t value)
{
uint8_t i;
for (i = 0; i < 8; ++i)
{
CLK_L();
if (value & 0x01)
DIO_H();
else
DIO_L();
value >>= 1;
CLK_H();
}
CLK_L();
DIO_IN();
DIO_IN();
CLK_H();
DIO_OUT();
}
//------------------ Команда СТАРТ --------------------
void start()
{
DIO_H();
CLK_H();
CLK_H();
CLK_H();
DIO_L();
}
//------------------ Команда СТОП ---------------------
void stop()
{
CLK_L();
DIO_L();
DIO_L();
DIO_L();
CLK_H();
DIO_H();
}
//=== Своя функция задержки в мс ====================
void delay_msTK(uint8_t ms)
{
while(ms--)
_delay_ms(1);
}
//******************** Усреднение по 4 замерам для стабильности показаний ***********************
int getSmoothTemp()
{
int sum = 0;
for (int i = 0; i < 4; i++) // В цикле суммируем показания 8 опросов ...
{
sum += spiRead() ; // ... в переменную sum
delay_msTK(240); // Делаем паузу между опросами - MAX6675 нужно время на преобразование 170 - 220 мс
}
return (sum >>= 2); // Делим показания на 4 - получаем усреднённое значение
}
//*************************** Чтение данных из модуля термопары MAX6675 ******************************
//https://arduinodiy.wordpress.com/2019/12/06/using-a-max6675-temperature-sensor-without-a-library/
int spiRead()
{
DDRB = DDRB | 0B00000110;
int rawTmp = 0;
PORTB &= ~(1<<cs); // cs,LOW
delay_msTK(2); // задержка 2 миллисекунды
PORTB |= (1<<cs); // cs,HIGH
delay_msTK(200); // задержка 200 миллисекунд
PORTB &= ~(1<<cs); // cs,LOW Опускаем CS для старта преобразования
//Считываем 11 из 14 бит из MAX6675 и сохраняем в rawTmp
//(больше не нужно - 11 бит это целая часть температуры без точнсти 0,25 градусов)
for (int i=10; i>=0; i--)
{
PORTB |= (1<<clk); // clk,HIGH
byte r=0;
if(PINB & (1<<miso)) // Чтение пина MISO - если на ножке MISO 1, то ...
r=1; // ... фиксируем единичку
rawTmp +=r << i; // Сохраняем считанный бит в переменную температуры
PORTB &= ~(1<<clk); // clk,LOW
}
PORTB |= (1<<cs); // cs,HIGH
return rawTmp;
}
//=========================================================================================================
Самые обсуждаемые обзоры
| +76 |
3901
136
|
| +31 |
1557
40
|
| +37 |
2512
127
|
Автору, конечно респект, но вид, конечно… Строго 18+!!!