ATtiny13A 101 применение

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

gzp13 пишет:

На ардуино код работает отлично, импульс который мне надо отследить длительностью 980мкс он четко показывает и выполняет необходимые действия как только этот импульс поймался. На импульсы другой длительности не реагирует, короче то что я хочу и сделать на Attiny13.

ну тогда не знаю, а собирать тестовый стенд лень :)

уж третий раз спрашиваю - вы условие на больше 1000 мкс ставить пробовали - горит светодиод ?

СергейНСК
Offline
Зарегистрирован: 22.11.2014

Помогите подружить ds1990a с ATtiny13a!

На ардуино всё работает. Для тиньки тот же скетч не компилируется. Ругается на библиотеку Oneware. Пробовал искать готовые примеры общения с ключом без библиотеки - ничего не получается.

Может библиотеку заточенную под тиньку надо?

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

СергейНСК пишет:

Помогите подружить ds1990a с ATtiny13a!

На ардуино всё работает. Для тиньки тот же скетч не компилируется. Ругается на библиотеку Oneware. Пробовал искать готовые примеры общения с ключом без библиотеки - ничего не получается.

Может библиотеку заточенную под тиньку надо?

Нормальная библиотека 1Wire не залезет в 64 байта ОЗУ и килобайт ПЗУ. Возможно получится написать код на ассемблере - есть такие этузиасты. Но это скорее из любви к искусству, чем из необходимости

Предлагаю заменить тиньку13 хотя бы на 85-ю. А лучше поставить Atmega8/168/328 и не мучиться. Если хочется жутко тиражируемое решение и нужно сэкономить на контроллере, то взять STM8

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

не мое, взято с гитхаба:

// OneWire функции:

void OneWireReset()
{
  PORTB &= ~_BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_us(500);
  DDRB &= ~_BV(DS_BIT);
  _delay_us(500);
}

void OneWireOutByte(uint8_t d)
{
  uint8_t n;
  for (n = 8; n != 0; n--)
  {
    if ((d & 0x01) == 1)
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(5);
      DDRB &= ~_BV(DS_BIT);
      _delay_us(60);
    }
    else
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(60);
      DDRB &= ~_BV(DS_BIT);
    }
    d = d >> 1;
  }
}


uint8_t OneWireInByte()
{
  uint8_t d, n, b;
  for (n = 0; n < 8; n++)
  {
    PORTB &= ~_BV(DS_BIT);
    DDRB |= _BV(DS_BIT);
    _delay_us(5);
    DDRB &= ~_BV(DS_BIT);
    _delay_us(5);
    b = ((PINB & _BV(DS_BIT)) != 0);
    _delay_us(50);
    d = (d >> 1) | (b << 7);
  }
  return (d);
}

 

СергейНСК
Offline
Зарегистрирован: 22.11.2014

85-й нет и дорого покупать

Атмеги тоже нет, использовать ардуину - много кушает и много места занимает... Зато на ней работает...

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

Вроде не писали. Есть еще одно ядро, основанное на ядре о котором здесь говорится:

https://github.com/MCUdude/MicroCore

Больше функций.

А вот еще интересный документ по оптимизации:

http://ww1.microchip.com/downloads/en/AppNotes/doc8453.pdf

Блинк 70байт. Без setup, loop и стандартного delay. Со всеми ими будет 200+байт

#define poten 2

int main(void) {
  pinMode(poten, OUTPUT);

  while (1) {
    digitalWrite(poten, 1);
    _delay_ms(10);
    digitalWrite(poten, 0);
    _delay_ms(10);
  }
  return 0;
}

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

jeka_tm пишет:

Вроде не писали. Есть еще одно ядро, основанное на ядре о котором здесь говорится:

https://github.com/MCUdude/MicroCore

Больше функций.

А вот еще интересный документ по оптимизации:

http://ww1.microchip.com/downloads/en/AppNotes/doc8453.pdf

Блинк 70байт. Без setup, loop и стандартного delay. Со всеми ими будет 200+байт

#define poten 2

int main(void) {
  pinMode(poten, OUTPUT);

  while (1) {
    digitalWrite(poten, 1);
    _delay_ms(10);
    digitalWrite(poten, 0);
    _delay_ms(10);
  }
  return 0;
}

 

Круто, а зачем?

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

Писать для Attiny13 в привычной среде используя ардуиновские функции

sim31
sim31 аватар
Offline
Зарегистрирован: 26.07.2017

jeka_tm пишет:
Блинк 70байт. Без setup, loop и стандартного delay. Со всеми ими будет 200+байт

Там главная проблема не с флешем, а с RAM, 64 байта всего, мне кажется сложно уложиться в такой объем.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

sim31 пишет:

jeka_tm пишет:
Блинк 70байт. Без setup, loop и стандартного delay. Со всеми ими будет 200+байт

Там главная проблема не с флешем, а с RAM, 64 байта всего, мне кажется сложно уложиться в такой объем.

Да и пинов мало и т.д. Но для мелких задач не мегу8 же ставить или тем более 328

Мне например сейчас нужен таймер автополива. Просто тупо каждый час на пару минут включать. Ну куда там более мощный камень

Joiner
Offline
Зарегистрирован: 04.09.2014

jeka_tm пишет:

Да и пинов мало и т.д. Но для мелких задач не мегу8 же ставить или тем более 328

Мне например сейчас нужен таймер автополива. Просто тупо каждый час на пару минут включать. Ну куда там более мощный камень

Полностью согласен. На днях применил в одном простеньком устройстве. Очень обрадовался, что Тинька оказалась под рукой.

Ради интереса поинтересовался в местном магазинчике сколько стоит у них Attiny13... Ответили - 275 руб. Обрадовался еще раз, что когда-то заказал у китайцев :).

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Да щас и китайцы чота прих.ели, я смотрю. 

Joiner
Offline
Зарегистрирован: 04.09.2014

DetSimen пишет:

Да щас и китайцы чота прих.ели, я смотрю. 

Есть такое :)

evgta
Offline
Зарегистрирован: 02.09.2016

Полазил в даташите, но так и не понял есть ли в тиньке защитные диоды(стабилитроны), а если и есть то на какой ток, мощность. Подскажите кто с этим сталкивался.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

полный даташит от микрочип http://ww1.microchip.com/downloads/en/DeviceDoc/doc8126.pdf

говорят диоды есть

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

Сделал автополив для выращивания травки для кошек на Attiny13 и дисплее на TM1637

Joiner
Offline
Зарегистрирован: 04.09.2014

jeka_tm пишет:

Сделал автополив для выращивания травки для кошек на Attiny13 и дисплее на TM1637

Где ссылка на проект?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

jeka_tm пишет:

Сделал автополив для выращивания травки для кошек на Attiny13 и дисплее на TM1637

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

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

Проект выложу если кому то действительно нужно.

Управление не делал, хотел использовать кнопки TM1637, но не хватило памяти. Можно на пины, 2 пина свободно.

Время устанавливается в прошивке. Даже если добавить кнопки нужно ведь сохранять в eeprom, а на это наверно памяти уже не хватит.

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

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

У меня attiny85, поэтому мне наверное и проще было, и да, я каждые сутки счётчик в eeprom сохранял, т к свет в деревне часто отключают

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

Да у меня были варианты с большей памятью и ногами. просто захотел на тиньке

sim31
sim31 аватар
Offline
Зарегистрирован: 26.07.2017

jeka_tm пишет:

Да и пинов мало и т.д. Но для мелких задач не мегу8 же ставить или тем более 328

Мне например сейчас нужен таймер автополива. Просто тупо каждый час на пару минут включать. Ну куда там более мощный камень

Есть другие тиньки, например раньше была популярна attiny2313, сейчас смысла брать нет конечно. Зато очень часто стали использовать attiny85, у нее памяти больше, удобнее использовать. Есть модули готовые на Алиэкспрессе - Digispark, и программатор не нужен.

Paul_B
Offline
Зарегистрирован: 05.12.2016

Есть реализация на ESP8266 схемы электронного дверного замка, который можно открывать кнопкой на двери, радиосигналом с брелка и, соответственно, через интернет.

Питается система - от постоянного напряжения, которой заряжает аккумулятор 18650, а уже с того питаестя вся схема (ESP8266 и модуль радиоприемника). Хочу подстраховаться на случай отключения напряжения питания, чтобы система как можно дольше проработала автономно. Для этого хочу сделать на ATTiny13 обвес, который бы выполнял функции:

1. аппаратного watchdog'а, т.е. если вдруг модуль ESP 8266 повисает (с него перестают идти периодические импульсы) , то тинька сбрасывала бы напряжение питания.

2. Если пропадает напряжение, то модуль бы ESP 8266 отключался бы от питания аккумулятора ( т.е. к питанию аккумулятора остаются подключенными радиомодуль и тинька, которые потребляют мало)

3. В момент когда ESP 8266 отключен, но приходит сигнал с радиобрелка, то тинька бы подключала ESP 8266 к питанию аккумулятора, чтобы можно было бы открыть дверь, т.к. серва, открывающая засов, управляется через ESP8266.

Для этого мне нужет один аналоговый вход, чтобы контролировать входное напряжение питания (AC3), еще один цифровой вход для отслеживания сигнала с брелка (AC2), цифровой вход для реализации watchdoga (PB1) и цифровой выход для управления транзисторным ключом питания ESP8266 (на транзисторе 2N4401 - высокий потенциал напряжение на ESP подается, низкий - прерывается) (PB0)

Вот реализация (использовал ядро Microcore для Attiny13  https://github.com/MCUdude/MicroCore , экспериментально подобрал какие номера пинов указывать, чтобы они отвечали за то, что от них хотят, в итоге есть 3 аналоговых входа и 2 выхода управления питанием двух устройств. Самое оптимальное ядро, размер указанного кода 760 байт. Причем размер не меняется, если писать как есть, либо через регистры. Функция flash нужна исключительно для отладки, после этого ее можно удалить, что сэкономит еще около 60-80 байт) :


//                          +-\/-+
//          ADC0 (D 5) PB5 1|    |8 Vcc
// аналог-3 ADC3 (D 3) PB3 2|    |7 PB2 (D 2) ADC1  аналог-5
// аналог-6 ADC2 (D 4) PB4 3|    |6 PB1 (D 1) PWM1  цифра1
//                     GND 4|    |5 PB0 (D 0) PWM0  цифра0
//                          +----+

#include <avr/io.h>
#include <avr/wdt.h> // здесь организована работа с ватчдогом
#include <avr/sleep.h> // здесь описаны режимы сна
#include <avr/interrupt.h> // работа с прерываниями
#define ADC1 5 // ADC2 = PB3 внешний watchdog  
#define ADC2 6 // ADC2 = PB2 вход для внешнего управляющего сигнала
#define ADC3 3 // ADC2 = PB4 напряжение аккумулятора
#define Servo180 2700 // для поворота сервы на 180 градусов (т.е. для открытия двери)

byte count=0, V_Akk=0, Vlast_Akk=0, High_Level=0, Numb_WDT=0, VCC=0;
bool Device_ON[2]={false,false}, Servo_Open=false;

ISR (WDT_vect) { // данна функция вызывается по прерыванию при срабатывании wdt
                 // если wdt не сбросить, то будет резет
  wdt_reset();         // сбрасываем wdt сторож
  WDTCR |= _BV(WDTIE); // разрешение прерываний от сторожевого таймера 
                       //(запрещаются автоматически при сбросе сторожевого таймера) 
  count++;             // считаем время через количество срабатывания wdt
}

int main() {
  byte i;
  
    // инициализация управляющих портов питания
    pinMode(0,OUTPUT); // PB0
    pinMode(1,OUTPUT); // PB1

        
    // инициалицация портов чтения сигналов
    pinMode(ADC3,INPUT); // ADC3 = PB3 внешний watchdog
    pinMode(ADC1,INPUT); // ADC1 = PB2 вход для внешнего управляющего сигнала
    pinMode(ADC2,INPUT); // ADC2 = PB4 напряжение аккумулятора
                
    wdt_enable(WDTO_8S); // разрешаем ватчдог 
    /*      // альтернативное подключение wdt через регистры
        MCUSR &= ~(1<<WDRF); // снимаем флаг сброса системы сторожевым таймером
        // Start the WDT Config change sequence.
        WDTCR |= (1<<WDCE) | (1<<WDE);
        // Configure the prescaler and the WDT for interrupt mode only
         WDTCR = (1<<WDP3) | (1<<WDP0); // 8sec
        // WDTCR = (1<<WDP3); // 4sec
        // WDTCR = (1<<WDP2)  | (1<<WDP1) | (1<<WDP0); // 2sec
        // WDTCR = (1<<WDP2) | (1<<WDP1); // 1sec
        // WDTCR = (1<<WDP2) | (1<<WDP0); // 0.5sec
 */
    WDTCR |= _BV(WDTIE); // разрешаем прерывания по ватчдогу. Иначе будет резет.
    sei();               // разрешаем прерывания
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную
    
    wdt_reset(); // сбрасываем    
    
    while(1) {
        
//****************** основной цикл программы ********************************

// опрашиваем заряд аккумулятора и выясняем какой режим - зарядка или разрядка

      V_Akk=analogReadOversampled(ADC3); // проверяем заряд аккумулятора
                                         // при разряженном аккумуляторе любое отключение 
                                         // потребления вызывает резкие скачки показания его заряда
      if(V_Akk>Vlast_Akk+2 || VCC==0)              // аккумулятор заряжается 
         {                           
          if(VCC!=3 || V_Akk>160)     //если было отключение аккумулятора, то после отключения приборов
                                      // его емкость повысится со временем, отсекаем такой вариант
            { 
             Device(0,true);  // включаем ESP8266
             Device(1, true); // включаем радио, его потребление 4 mA    
             flash(3,1); 
            } 
          else flash(2,1);  
          
          VCC=1;              // индикатор заряда    
          Vlast_Akk=V_Akk;
         }
      if(V_Akk<Vlast_Akk-2) // аккумулятор разряжается, 
         {                  
          flash(1,1);
          
          VCC=2;            // индикатор разряда
          Vlast_Akk=V_Akk;
         }   
  
      
      if(V_Akk>=200)    // аккумулятор полный заряд
                       // от 4.0 В
        {
          Device(0,true); // включаем ESP8266
          flash(8,1);
        }                    
       else {  
             if(V_Akk<=198 && V_Akk>170)    // аккумулятор разряжается, 
                                             // 4.04В - 3.47В
                {         
                  flash(7,1);
                 // режим работы ESP8266 2 минуты вкл, 5 минут выкл.
                  Device_Work(0, 20);
                }
             else {   
                    if(V_Akk<=170 && V_Akk>165) // аккумулятор дохлый, отключаем ESP и радио
                                                           // 3.47В -   3.02В
                                                           // и не было его отключения
                      {
                        flash(6,1);
                        // режим работы ESP8266 2 минуты вкл, 20 минут выкл.
                        Device_Work(0, 40);
                      }
                     else { 
                          if(V_Akk<=165 && V_Akk>150  && VCC!=3) // аккумулятор дохлый, отключаем ESP и радио
                                                                 // 3.47В -   3.02В
                                                                 // и не было его отключения
                            {
                              flash(5,1);
                              // режим работы ESP8266 2 минуты вкл, 20 минут выкл.
                              Device_Work(0, 80);
                            }
                           else { 
                                 VCC=3;    // показатель, что акк полностью разряжен
      
                                if(V_Akk<=150 && V_Akk>145)    // аккумулятор совсем дохлый, открываем дверь, все выключаем
                                                              //  2.99 В - 2.7В
                                    {
                                      flash(4,1);                              
                                      Device(0, false); // выключаем ESP8266
                                    }
                                 else {
                                       flash(3,1);
                                       if(!Servo_Open)
                                         {
                                          Servo_180(0);  // открываем дверь
                                          Servo_Open=true;    
                                         }
                                       Device(1, false); // выключаем радио
                                     }
                               }  
                         }     
                    }          
             }

     // если устройство ESP8266 включено, то отслеживаем ее работу
     // оно каждые 10 секунд меняет состояние одного выхода, 
     // который подключен к ADC1 - 7 нога Attiny13
      if(Device_ON[0])
        {  
          if(Numb_WDT==5)
            {
              if(High_Level==0 || High_Level==Numb_WDT) // если 3 подряд измерения уровня внешнего watchdog
                {                                 // одинаковы, то передергиваем питание
                 Device(0, false); // выключаем ESP8266
                 _delay_ms(1000);    
                 Device(0, true);           
                }     
              Numb_WDT=0;       
              High_Level=0;            
            }
          // считаем высокоуровневые сигналы для внешнего WDT  
          if(analogReadOversampled(ADC1)>=150) High_Level++;   
          Numb_WDT++;
        } 
      else { 
             Numb_WDT=0;
             High_Level=0;
             // если ESP8266 выключена, то можно открыть дверь
             // радиоприемником, если пришла команда с брелка - на случай форс-мажора
             // соответствующий выход радиоприемника должен быть подключен
             // к ADC2 - 3я нога Attiny13
              if(Device_ON[1])
                if(analogReadOversampled(ADC2)>=150) 
                  {
                    Servo_180(0);  // открываем дверь
                    Servo_Open=true;    
                  }
          }

//****************** конец основного цикла программы ***********************
        
      wdt_reset();    // перед сном сбрасываем, чтобы спать все отведенное время
      sleep_enable(); // разрешаем сон
      sleep_cpu();    // спать!
    }
}



void flash(byte n, byte port)
{
  for(byte i=0;i<n;i++)
  {
   PORTB |= _BV(port);    
   _delay_ms(200);
   PORTB &= ~_BV(port);
   _delay_ms(200);
  }
  _delay_ms(1000);
}



void Device(byte port, bool sost)
{
if(Device_ON[port]!=sost)
  {
   if(sost) PORTB |= _BV(port); // включаем устройство 
   else PORTB &= ~_BV(port);    // выключаем
   Device_ON[port]=sost;        // запоминаем в каком состоянии устройство
   _delay_ms(2000);
   V_Akk=analogReadOversampled(ADC3); // после включения-выключения производим 
   Vlast_Akk=V_Akk;                   // замер аккумулятора, чтобы скачки не исказили
  }                                   // алгоритм работы                   
}

void Device_Work(byte port, byte tm)
{
if(!Device_ON[port])               // устройство выключено
  { 
    if(count>=tm)                  // если прошло определенное время в выключенном состоянии
      {
        Device(port,true);         // включаем после паузы в соответствии с режимом работы
        count=0;                   // обнуляем счетчик
      }
  } else {                         // устройство включено
          if(count>=15)            // если прошло 15 циклов т.е. 2 минуты
            {
              Device(port,false);  // выключаем после 2 минут работы
              count=0;             // обнуляем счетчик
            } 
          }
}
/*
unsigned int ADC_READ(byte channel){// аналог AnalogRead()
  ADMUX = channel; // ADC pin
  ADCSRA |= 1<<ADEN;
  ADCSRA |= 1<<ADSC;
  while(!(ADCSRA & (1<<ADIF)));
  ADCSRA |= 1<<ADIF;
  byte low  = ADCL;
  byte high = ADCH;
  ADCSRA &= ~(1 << ADEN);  // отключаем АЦП
  return (high << 8) | low;
}
*/ 
byte analogReadOversampled(byte channel){
  unsigned int aSum = 0;   // the sum of all analog readings
  for(byte i = 0; i < 16; i++)
    aSum += analogRead(channel); // ADC_READ(channel); // read and sum 16 ADС probes
  return (aSum >> 6);   // возвращаем усредненное значение, деленное на 4
}


void Servo_180(byte servo)
{
  for (byte i=0;i<50;i++)
    {             
     digitalWrite(servo, HIGH);
     _delay_us(Servo180);
     digitalWrite(servo, LOW);
     _delay_us(15000-Servo180);
    }  
}

/*
void myPause_us(int i){
while (i>0){ _delay_us(1); i--;}
}

void Servo(byte servo, byte ugol)
{
  int ms;
  if(ugol==0) ms=580;
  if(ugol==180) ms=2700;
  
  for (byte i=0;i<50;i++)
    {             
     digitalWrite(servo, HIGH);
     myPause_us(ms);
     digitalWrite(servo, LOW);
     myPause_us(15000-ms);
    }  
}
*/