Термометр 0/999 градусов на Attiny13

Понадобился термометр до 500 градусов. Ничего лучше термопары и MAX6675 не нашел. Но габариты модуля и ардуинки не устраивали. Решил делать на Attiny13. Работа с шиной I2C, взята с форума. //ATtiny13A 101 применение | Аппаратная платформа Arduino Скетч занимает 444 Байта. Получился компактный термометр. В скетче есть ссылки на исходные коды. Если кому нужны более широкие возможности, можно посмотреть первоисточники. Для пояснений выложил небольшой ролик:
https://youtu.be/8VEJq8mRu34
Схема:

Скетч:


#define _NOP() asm volatile("nop")

 //массив знакогенератора 7 сегментного индикатора
byte simv[11]={        
B00111111, //0           
B00000110, //1        
B01011011, //2   cоответствие разрядов и сегментов     
B01001111, //3           
B01100110, //4            _1_
B01101101, //5         6 |   | 2
B01111101, //6           |_7_|
B00000111, //7         5 |   | 3
B01111111, //8           |_4_|
B01101111, //9
B00000000, //пустота
}; 
 
// delay() для тиньки и свой нормальный, а delayMicroseconds() дурной
//а вот глобального такого дефайна может и не быть, как ни странно, так для страховки завел
//#define F_CPU 4800000UL
#define LOOP_CYCLES 8
#define us(num) (num/(LOOP_CYCLES*(1/(F_CPU/1000000.0))))

inline __attribute__((gnu_inline)) void asm_delay(uint16_t delay){
  uint16_t u=us(delay);
do _NOP(); while(delay--);
}

#define wdelay_us(x)  asm_delay(us(x))
#define wdelay(x) delay(x)


/*****************************************************/
//дальше мелкий вариант i2c на любых ногах

#define IICR  1
#define IICW  0

#define I2CDelay()  wdelay_us(4) // на 100КГц примерно по 4 мкс нужно держать уровни SCL 
#define miso     0               //   - со скоростью сами экспериментируйте
#define cs       1
#define clk      2
#define SDA_Pin  3
#define SCL_Pin  4
#define miso_In()   (PINB & 0B00000001)
#define SDA_In()    (PINB & 0B00001000)
#define SCL_In()    (PINB & 0B00010000)


     inline void SDA_Hi()  { PORTB |= 0B00001000; DDRB &= 0B11110111;}
     inline void SDA_Lo()  { PORTB &= 0B11110111; DDRB |= 0B00001000;}
     inline void SCL_Hi()  { PORTB |= 0B00010000; DDRB &= 0B11101111;}
     inline void SCL_Lo()  { PORTB &= 0B11101111; DDRB |= 0B00010000;}

void I2CInit (void)
{
    SDA_Hi();
    SCL_Hi();
}


void I2CStart (void)
{
  SCL_Hi();
  while (!SCL_In());
  I2CDelay();
  SDA_Lo();
  SCL_Lo();  
}
 
void I2CStop (void)
{
  I2CDelay();
  SCL_Hi();
  I2CDelay();
  SDA_Hi();
  I2CDelay();
}

boolean I2CWrite(byte b)
{
  byte i = 1<<7;
  boolean ack=0;

  while(i)
    {
      I2CDelay();
      if (b & i) SDA_Hi(); else SDA_Lo();
      I2CDelay();
      SCL_Hi();
      I2CDelay();
      SCL_Lo();
      
      i>>=1; 
    }
  SDA_Hi();
  I2CDelay();
  SCL_Hi();

  if ( SDA_In()==0 ) ack = 1;
  I2CDelay();
  SCL_Lo();
  SDA_Lo();
  return ack;
}

byte I2CRead(boolean ack)
{
  byte i=8;
  byte b=0;
  
  while(i--)
  {
   I2CDelay();
   SCL_Hi();
   if (SDA_In()) b |= 1;
   b <<= 1;
   I2CDelay();
   SCL_Lo();
  }
  if (ack) SDA_Lo();
  else SDA_Hi();
  I2CDelay();
  SCL_Hi();
  I2CDelay();
  SCL_Lo();
  SDA_Lo();
  return b;
}
/*************************************/



void setup() {



// Инициализация дисплея TM1650,Подробнее https://arduino.ru/forum/programmirovanie/kontroller-led-i-klaviatury-fd650v-kak-im-upravlyat#comment-232263 
    I2CStart();
    I2CWrite(0x27<<1);
    I2CWrite(B00010001);
    I2CStop();
    wdelay(500);

}

void loop() {
int t= spiRead();//Читаем данные из модуля термопары  MAX6675
byte ks=0;
byte kd=0;
  while(t>=100){t-=100;ks++;} ;
  while(t>=10){t-=10;kd++;}
        //************ выводим число на индикатор *******************   

if (ks==0)ks=10;
           //СОТНИ
           I2CStart();
           I2CWrite(0x34<<1);              //выставляем номер разряда индикатора  
           I2CWrite(simv[ks]);             //пишем в него символ
           I2CStop(); 
           
           //ДЕСЯТКИ
           I2CStart();
           I2CWrite(0x35<<1);      
           I2CWrite(simv[kd]); 
           I2CStop();
            
           //ЕДИНИЦЫ
           I2CStart();
           I2CWrite(0x36<<1);             
           I2CWrite(simv[t]);             
           I2CStop(); 
 
 //************ выводим на индикатор знак градуса *******************     
           I2CStart();
           I2CWrite(0x37<<1);
           I2CWrite(B01100011);
           I2CStop ();
wdelay(500);
}

//    ******************** Чтение данных из модуля термопары  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
      wdelay(2);     //  задержка 2 миллисекунды
PORTB |= (1<<cs);    //  cs,HIGH
      wdelay(200);   //  задержка 200 миллисекунд
PORTB &= ~(1<<cs);   //  cs,LOW Опускаем CS для старта преобразования

//Считываем 11 из 14 бит из MAX6675 (больше мне не нужно)и сохраняем в rawTmp

for (int i=10; i>=0; i--) {
PORTB |= (1<<clk); //clk,HIGH

byte r=0;if(PINB & (1<<miso))r=1;//Чтение пина MISO
rawTmp +=r << i;
PORTB &= ~(1<<clk); // clk,LOW
}
//rawTmp=327;
return rawTmp;

}  

2 лайка

Ой! Какой знакомы код для И2Ц! Нужно роялти пЫвом собирать! ;))

Шутка. На самом деле я рад, что моя поделка приносит пользу. Сам я давно про нее забыл, так как Тинька13 выпала из сферы моих интересов.

Сверху скетча, есть ссылка на Ваш код. А насчет тиньки, просто у меня десяток осталось. А что-то более солидное на такой девайс ставить религия не позволяет. Да и конструкция минималистичная получилась.

где?
Или вы про это:

не охотв придираться, но раз уж зашел разговор, то этого недостаточно. По-хорошему полагается вставлять ссылку на конкретную ветку, откуда код и с указанием автора, если это не коллективное творчество.
Например так, как у вас сделано для кода термопары:

Хотя если я сослепу не разглядел и такая ссылка есть - прошу прощения.

Все верно, в скетче ссылки нет. Хотя её видно при редактировании поста и при скачивании или просто копировании. Какой-то глюк. Исправился, вставил в текст сообщения. Спасибо за код и критику.

А что такое ТМ650? Гугл ничего не даёт понятного на эти символы .

Ошибка. TM1650, исправил.

А ссылка на индикатор AliExpress есть? чтоб купить.

Еще бы и тэг поправить с I2S на I2C…чтобы поисковики отрабатывали правильно

Микросхемы есть, а модулей не видел. Я когда-то помогал одной конторе с ремонтом приставок “Элект” и у меня скопилось несколько десятков, не подлежащих ремонту. Из них болгаркой и вырезаю микросхему с индикатором. В принципе там любой аналогичный модуль с I2C можно использовать, только адреса поменять. Или купить отдельную микросхему за 16 руб. и припаять к ней 4 индикатора. Бонусом будет еще и клавиатура. Кажется 8х8, и тоже по I2C.

А это где? Я на новом форуме пишу в первый раз. Еще не адаптировался.

в самом первом сообщении

I2C не дает вставить. Пишет нет совпадений. Предлагает только I2s, но удалить дал.

Нажми + и добавь тэг I2C

Спасибо.

Ввиду того, что у многих проблемы с TM1650, сделал вариант для TM1637. Схема та-же. Должна работать и на тиньке13 и на UNO и подобных. На тиньке занимает 432 байта на УНО 574. Проверить не смог т.к. нет MAX6675, а подпаиваться к мелкой платке программатором лень.

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#define miso     PB0 //MAX6675           
#define cs       PB1 //--
#define clk      PB2 //--
//#define clk    PB3 //TM1637
//#define DIO    PB4 //--
#define miso_In()   (PINB & 0B00000001)

#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))

PROGMEM const uint8_t _digit2segments[] =
{
  0x3F, // 0
  0x06, // 1
  0x5B, // 2
  0x4F, // 3
  0x66, // 4
  0x6D, // 5
  0x7D, // 6
  0x07, // 7
  0x7F, // 8
  0x6F, // 9
  0x00, // пусто
  0x63  // градус
};
 
//********************************************************************************************************
int main(void) {
		/* setup */
	 //  Serial.begin(9600);

	  TM1637_init();
    
	 _delay_ms(300);
//********************************************************************************************************
	while(1) {

int t= spiRead();//Читаем данные из модуля термопары  MAX6675
byte ks=0;
byte kd=0;
  while(t>=100){t-=100;ks++;} ;
  while(t>=10){t-=10;kd++;}
        //************ выводим число на индикатор *******************   

if (ks==0)ks=10;
           //СОТНИ
          TM1637_dig (0, ks); 
          //ДЕСЯТКИ
          TM1637_dig (1, kd); 
          //ЕДИНИЦЫ
          TM1637_dig (2, t);   
          //знак градуса
          TM1637_dig (3, 11);//градус 
    
_delay_ms(500);
}

}


//    ******************** Чтение данных из модуля термопары  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_ms(2);     //  задержка 2 миллисекунды
PORTB |= (1<<cs);    //  cs,HIGH
      _delay_ms(200);   //  задержка 200 миллисекунд
PORTB &= ~(1<<cs);   //  cs,LOW Опускаем CS для старта преобразования

//Считываем 11 из 14 бит из MAX6675 (больше мне не нужно)и сохраняем в rawTmp

for (int i=10; i>=0; i--) {
PORTB |= (1<<clk); //clk,HIGH

byte r=0;if(PINB & (1<<miso))r=1;//Чтение пина MISO
rawTmp +=r << i;
PORTB &= ~(1<<clk); // clk,LOW
}
//rawTmp=24;
return rawTmp;
}


//***********************************************************************************


void
TM1637_dig(const uint8_t position, const uint8_t digit)
{ uint8_t segments = (digit < 12 ? pgm_read_byte_near((uint8_t *)&_digit2segments + digit) : 0x00);
  TM1637_display_segments(position, segments);}

void
TM1637_display_segments(const uint8_t position, const uint8_t segments)
{ send_cmd(0x40 | 0x04);
  TM1637_start();
  TM1637_write_byte(0xC0 | (position & (4 - 1)));
  TM1637_write_byte(segments);
  TM1637_stop();}

//  Serial.println((0x80 | _config),HEX);

uint8_t TM1637_write_byte(uint8_t value)
{ uint8_t i, ack;
  for (i = 0; i < 8; ++i, value >>= 1) {
  CLK_L(); _delay_us(5);
    if (value & 0x01) {DIO_H();}
    else {DIO_L();}
  CLK_H(); _delay_us(5);}
  CLK_L();
  DIO_IN();
  DIO_H(); _delay_us(5);
  ack = DIO_RD();
  if (ack) { DIO_OUT();DIO_L();} _delay_us(5);
  CLK_H(); _delay_us(5);
  CLK_L(); _delay_us(5);
  DIO_OUT();
  return ack;}

void send_cmd(const uint8_t value)
{ TM1637_start(); TM1637_write_byte(value); TM1637_stop();}  

void TM1637_start()
{ DIO_H();CLK_H(); _delay_us(5); DIO_L();}

void TM1637_stop()
{ CLK_L(); _delay_us(5); DIO_L(); _delay_us(5); CLK_H(); _delay_us(5); DIO_H();}

void
TM1637_init()
{ DDRB |= (_BV(PB4)|_BV(PB3));
  PORTB &= ~(_BV(PB4)|_BV(PB3));
  send_cmd(0x8B);}
1 лайк

видимо так надо (строка 142)

Косяк при вставке, пардон. Возможность проверить есть? Если раскомменгировать 89 строку, то и на тиньке и на уно показывает верно, а вот работает-ли МАКС неясно.

теоретически да, но только на тиньке 85, но это не сегодня

Сегодня закончил сборку цифровой станции для жал T12. И проверил этим термометром соответствие показаний на пяти жалах с Али. Разница показаний от 5 до 40 градусов. Правда цена жал около 100 руб. За это можно многое простить. Видео мини паяльной станции: https://youtu.be/uiCsJtg9zPE