Опять диммер на attiny85

Тема в разделе "Микроконтроллеры AVR", создана пользователем nsv2018, 26 май 2021.

  1. nsv2018

    nsv2018 Нерд

    Заранее прошу не пинать и не отправлять в поиск Google!
    Все видел и все читал!

    Суть проблемы:
    Понадобился диммер на Attiny85 с управлением по i2c.
    И схема и скетч подобного устройства ранее обсуждались на форуме.
    По аналогии решил повторить.

    схема
    [​IMG]


    скетч
    Код (C++):


    // автономный диммер на ATtiny85 с управлением по I2C
    // *********************************************************************
    //  фьюзы:  HIGH = 0xDF; LOW = 0xE2; EXTENDED = 0xFF

    // Алгоритм:
    // * таймер установлен, но отключен
    // * обнаружено пересечение нуля
    // * таймер начинает отсчет с нуля
    // * компаратор установлен в значение "задержка включения"
    // * счетчик достигает значения компаратора
    // * компаратор ISR включает симистор
    // * счетчик установлен на переполнение - ширина импульса
    // * счетчик достигает переполнения
    // * переполнение ISR выключает симистор
    // * симистор закрыт при следующем пересечении нуля

    #include <TinyWireS.h>

    #define I2C_SLAVE_ADDR (0x41) //адрес устройства
    #define DETECT 1 //физический пин 6, детектор ноля, прерывание 0
    #define GATE 3 //физический пин 2, выход на симистор
    #define PULSE 5 //константа счетчика импульсов, определяет ширину управляющего импулса
    // I2C pins: PB2 - SCL физический пин 7, PB0 - SDA физический пин 5
    // const byte averageFactor = 10;   //smoothing level (0 = not smoothing)
    //  int sensorValue = 0;
    volatile byte i2cValue, ocr, jj;

    void setup()
    {
          delay(2000); //задержка нужна чтобы не хватать мусор из шины при инициализации
          ocr = 0; // выключение нагрузки при инициализации
          // set up pins
          TinyWireS.begin(I2C_SLAVE_ADDR);
          pinMode(DETECT, INPUT);      //zero cross detect
          digitalWrite(DETECT, HIGH);  //enable pull-up resistor
          pinMode(GATE, OUTPUT);       //triac gate control
          DDRB &= ~(1 << DETECT); //обнаружение пересечения нуля
          PORTB |= (1 << DETECT); //включить подтягивающий резистор
          DDRB |= 1 << GATE; //управление симистором
          GIMSK = 1 << PCIE;
          PCMSK = 1 << PCINT1;

          OCR1A = 50; //инициализация компаратора
          TIMSK = _BV(OCIE1A) | _BV(TOIE1); //прерывание при сравнении совпадений A | разрешить прерывание переполнения таймера
          sei(); //  разрешить прерывания
          TinyWireS.onRequest(requestEvent);
    }

    ISR (PCINT0_vect) // Детектор нуля
    {
          for(uint8_t ii=0; ii<200; ii++) jj++;
          if (PINB&(1<<PINB1)) { return;}
          TCNT1 = 0; // сбросить таймер - считать с нуля
          OCR1A = ocr;
          TCCR1 = B00001010; // предварительный делитель на 1024, см. таблицу 12.5 таблицы tiny85
    }

    ISR(TIMER1_COMPA_vect) // прерывания по совпадению значения Timer1 со значением регистра OCR1A
    {
          PORTB |= (1 << GATE); //  включили симистор
          TCCR1 = 0;
          TCNT1 = 255 - PULSE; //длительность триггерного импульса, когда TCNT1 = 255, Timer1 переполняется
          TCCR1 = B00001010;
    }

    ISR(TIMER1_OVF_vect) //  прерывние по переполнению Timer1
    {
          PORTB &= ~(1 << GATE); //выключили симистор
          TCCR1 = 0; // сброс таймера остановить непреднамеренные срабатывания
    }

    void loop()
    {
      if (TinyWireS.available()) i2cValue = TinyWireS.receive();// проверка значений полученных по i2c что бы отсеять ненужное

          if ((i2cValue < 1) || (i2cValue > 254)) ocr = 0; // все что меньше 1 и больше 254 выключает нагрузку

          else if (i2cValue == 3) digitalWrite(GATE, LOW); // управляем симистором для проверки I2C
          else if (i2cValue == 9) digitalWrite(GATE, HIGH); // управляем симистором для проверки I2C

       //  else ocr = map(i2cValue, 0, 254, 145, 15); // рабочий диапазон от 1-254 ??
        else  ocr=i2cValue;              
          TinyWireS_stop_check();
    }

    void requestEvent() {
      TinyWireS.send(i2cValue);
    }

    Схему собрал на макетке.
    Прошил Attiny85, выставил фьюзы: HIGH = 0xDF; LOW = 0xE2; EXTENDED = 0xFF

    Однако, судя по форуму - у всех диммер работает - у меня нет!!
    Все проверил - перепроверил - все соответствует оригиналу. НО диммер не работает, хоть тресни!
    Чуствую - проблема с установками таймеров - а где именно - не пойму. Но ведь и схема и скетч рабочие, у всех работает.

    Для проверки железа использовал blink а также управлял симистором по i2c - симистор включается и выключается.
    Но диммер "не диммерит".

    На ноге DETECT - как и полагается - короткие импульсы от детектора нуля частотой 100 герц.
    На ноге - GATE - похожие импульсы но более четко сформированные.
    При изменении значения ocr ничего не меняются.

    Ткните носом - что не так.
    Работать с прерываниями на уровне регистров Attiny пока трудновато, матчасть только начинаю осваивать.
    Заранее благодарен.
     

    Вложения:

    Последнее редактирование модератором: 26 май 2021
  2. SergeiL

    SergeiL Оракул Модератор

    Так если у всех работает, значит таймеры настроены правильно.
    А если по I2C передавать 0 и 255, лампочка выключается и включается?
    Почему строчка
    Код (C++):
    //  else ocr = map(i2cValue, 0, 254, 145, 15); // рабочий диапазон от 1-254 ??
    закомментирована и в ocr пишется значение i2cValue?
    На какой частоте работает Тинька? На 8МГц, пределитель таймера - на 512.
    Я настраивал Тиньку на максимум, 16МГц и пределитель на 1024. Так переход через ноль более точно определяется.
    Значит в 10мс полупериода будет 156,25 тиков таймера. Так же как и у меня.
    Поэтому был сделан мапинг, и максимальное значение OCR1A не должно превышать 150 (6 тиков - переход через ноль + включение симистора).
    Код (C++):
    ISR (PCINT0_vect)// Детектор нуля
    {
         for(uint8_t ii=0; ii<200; ii++) jj++;
    - это нехорошо. Не нужно задержек в прерывании.
    И нужно добавить сброс предделителей таймера (перед сбросом таймера, в прерывании от Zero-Cross)
    Нужно добавить:
    Код (C++):
        GTCCR |= 2;                              // сбросим счетчики предделителей
     
    перед:
    Код (C++):
        TCNT1 = 0;   // сбросим таймер
     
    :
     
    Andrey12 нравится это.
  3. nsv2018

    nsv2018 Нерд

    1.строка с Map закомментирована только на время отладки. Аналогично ocr=i2cValue;
    все восстановил, ocr получает значение из Map
    2.сброс счетчика предделителя GTCCR |=2; ничего не дал
    3. лишние задержки в прерывании убрал.
    4. Самоe неприятное:
    - если по I2C передаю 0 - на ноге GATE -0, импульсов нет
    = если по I2C передаю - 255 - на ноге GATE -импульсы, похожие на импульсы от Zero-Cross, но более четко сформированные.
    кстати, симистор по I2C нормально управляется отладочными командами, т.е. железо работает
    Таким образом получается получается:
    ISR(TIMER1_COMPA_vect) включает симистор.
    ISR(TIMER1_OVF_vect) симистор выключает независимо от установленных параметров ....???
    Вопрос - почему и что не так?

    5. по поводу частоты Attiny:
    возможно здесь собака и зарыта -
    временные параметры диммера (частота работы Тиньки, делители и т.д.) не соответствую параметрам сети (50Гц), Attiny (ее таймеры) работает не синхронно с сетью.

    Я полагал, что с указанными в начале вопроса фьюзами Тинька работает на частоте 8Мгц а все указанные делители и константы расчитаны именно на эту частоту.
    Самому определить параметры пока не по силам, поэтому и воспользовался готовым и отработанным решением.

    вот мои фьюзы: HIGH = 0xDF; LOW = 0xE2; EXTENDED = 0xFF
    так что же не так?
    Какие фьюзы выставлены в Вашй Тиньке и, если можно, покажите свой скетч
     
  4. parovoZZ

    parovoZZ Гуру

    это как?

    в коде всё синхронизируется. @SergeiL неоднократно писал об этом.
     
  5. SergeiL

    SergeiL Оракул Модератор

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