Двухканальный диммер на AtTiny85 (UART I2C)

Тема в разделе "Глядите, что я сделал", создана пользователем SergeiL, 13 апр 2018.

  1. Evgeniynd

    Evgeniynd Нуб

    На выходе моторчик, но как я и говорил, на макетке работало и обороты менялись
     
  2. Evgeniynd

    Evgeniynd Нуб

    осциллографа нет к сожалению, повесил просто светодид и вот как раз он начинает слегка светится при 98%
     
  3. Evgeniynd

    Evgeniynd Нуб

    Вот на макетке, где все работало как часы
     

    Вложения:

  4. SergeiL

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

    Ну чудес не бывает, если на мактке работало, все должно и на печатной плате работать.
    Если она соответствует макетке. FUSE не забыли прошить, прошили как в первом сообщении?
    Тинька с макетки или другая?
    Выкладывайте скан печатки будем искать ошибку.
    Светодиодом импульс будет не увидеть, там он очень короткий.
     
  5. Evgeniynd

    Evgeniynd Нуб

    "FUSE не забыли прошить" это что? Если речь идёт об аттинке то её прошил конечно. Или что то упустил?
     
  6. Evgeniynd

    Evgeniynd Нуб

    Вот оба слоя той части что за это всё отвечает
     

    Вложения:

  7. Evgeniynd

    Evgeniynd Нуб

    Вопрос снят! Большое спасибо! На записал загрузчик в аттини, так он в arduino ide называется
     
  8. SergeiL

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

    С загрузчиком прошиваются Фьюзы.
    Это настройка микроконтроллера на нужную тактовую частоту и т.п.
    Поэтому и не работало. Тактовая по умолчанию 8МГц, + CKDIV8 выставлен, итого 1МГц, а код рассчитан на 16МГц.
    Вот и работало не корректно.
    Я фьюзы прошиваю через AVR Studio, а потом уже заливаю прошивку через Ардуино ИДЕ. если Ардуино библиотеки используются. А если нет - ICC AVR.
     
    Andrey12 нравится это.
  9. Evgeniynd

    Evgeniynd Нуб

    Спасибо большое что откликнулись! Три дня потратил на это)
     
    Последнее редактирование: 3 ноя 2022
  10. Ariadna-on-Line

    Ariadna-on-Line Гуру

    #include <avr/io.h>
    #include <avr/interrupt.h>

    // AtTiny85 16.5MHz internal

    #define AC_DETECT 2 // Пин B2 zero cross detect, interrupt 0, физический pin 7
    #define AC_LOAD_0 3 // Пин B3 выход на нагрузку 1 физический pin 2
    #define AC_LOAD_1 4 // Пин B4 выход на нагрузку 2 физический pin 3

    #define MIN_TCNT_VAL 5 // Минимальное значение TCNT1 Dimming level (5-150) 5 = ON, 150 = OFF
    #define MAX_TCNT_VAL 150 // Максимальное значение TCNT1 Dimming level (5-150) 5 = ON, 150 = OFF

    #define PULS_COUNT 4 // Длина импульса на Gate симистора в тиках таймера 1

    #define MAX_BUFF_LENG 5 // Размер буфера под команду

    volatile uint8_t dimming_0 = MAX_TCNT_VAL; // Переменная для уровня диммирования нагрузки 1
    volatile uint8_t dimming_1 = MAX_TCNT_VAL; // Переменная для уровня диммирования нагрузки 2
    volatile uint8_t dimming_0_cur = MAX_TCNT_VAL; // Переменная для хранения текущего уровня диммирования нагрузки 1
    volatile uint8_t dimming_1_cur = MAX_TCNT_VAL; // Переменная для хранения текущего уровня диммирования нагрузки 2

    volatile uint8_t Errflag=1; // Флаг ошибки 0 - штатная работа zero cross detect, 1 - не работает zero cross detect

    volatile uint8_t test_val; // переменные для отладки

    ISR(TIMER1_COMPA_vect) // Отработчик Timer1 прерывание по сравнению с регистром OC1A
    {
    static uint8_t dimming_0_pulse=0;

    if(dimming_0_pulse)
    {
    PORTB &= ~( 1 << AC_LOAD_0 ); // Выключим оптопару
    dimming_0_pulse=0;
    }
    else
    {
    if ( dimming_0_cur < MAX_TCNT_VAL && Errflag==0 ) // Если уровень диммирования больше минимального и нет ошибки от zero cross detect
    {
    PORTB |= ( 1 << AC_LOAD_0 ); // Включение нагрузки 0
    OCR1A=OCR1A+PULS_COUNT;
    dimming_0_pulse=1;
    }
    }
    }

    ISR(TIMER1_COMPB_vect) // Отработчик Timer1 прерывание по сравнению с регистром OC1B
    {
    static uint8_t dimming_1_pulse=0;

    if(dimming_1_pulse)
    {
    PORTB &= ~( 1 << AC_LOAD_1 ); // Выключим оптопару
    dimming_1_pulse=0;
    }
    else
    {
    if ( dimming_1_cur < MAX_TCNT_VAL && Errflag==0 ) // Если уровень диммирования больше минимального и нет ошибки от zero cross detect
    {
    PORTB |= ( 1 << AC_LOAD_1 ); // Включение нагрузки 1
    OCR1B=OCR1B+PULS_COUNT;
    dimming_1_pulse=1;
    }
    }
    }

    ISR(TIMER1_OVF_vect) // Обработчик Таймер 1 переполнение. Что то пошло не так, возможно не работает zero cross detection или нет напряжения сети
    {
    PORTB &= ~( 1 << AC_LOAD_0 ); // Выключим нагрузку 1
    PORTB &= ~( 1 << AC_LOAD_1 ); // Выключим нагрузку 2
    Errflag=1; // взведем флаг ошибки в работе zero cross detect.
    }

    ISR(INT0_vect) // Отработчик INT0, zero cross detect, срабатывает по фронту (спад сетевого напряжения)
    {

    if (TCNT1 < 120 && Errflag==0) // минимизируем помехи в рабочем режиме. 10мс - 156,25 отсчетов таймера. Должны попадать сюда на отсчетах таймера 155-158
    return;
    GTCCR |= 2; // сбросим счетчики предделителей
    TCNT1 = 0; // сбросим таймер

    test_val=TCNT1; // отладка ( для отображения отсчета на котором сюда попали)

    if (dimming_0_cur>dimming_0)
    {
    OCR1A=dimming_0_cur--; // пропишем в регистр сравнения значение уровня диммирования нагрузки 0
    }
    else if(dimming_0_cur<dimming_0)
    {
    OCR1A=dimming_0_cur++; // пропишем в регистр сравнения значение уровня диммирования нагрузки 0
    }
    else
    {
    OCR1A=dimming_0_cur; // пропишем в регистр сравнения значение уровня диммирования нагрузки 0
    }


    if (dimming_1_cur>dimming_1)
    {
    OCR1B=dimming_1_cur--; // пропишем в регистр сравнения значение уровня диммирования нагрузки 1
    }
    else if (dimming_1_cur<dimming_1)
    {
    OCR1B=dimming_1_cur++; // пропишем в регистр сравнения значение уровня диммирования нагрузки 1

    }
    else
    {
    OCR1B=dimming_1_cur; // пропишем в регистр сравнения значение уровня диммирования нагрузки 1
    }

    PORTB &= ~( 1 << AC_LOAD_0 ); // Выключим оптопару
    PORTB &= ~( 1 << AC_LOAD_1 ); // Выключим оптопару
    Errflag=0; // рабочий режим, сбросим режим ошибки
    }


    void setup()
    {
    DDRB &= ~(1 << AC_DETECT); // Настроим как вход
    PORTB |= (1 << AC_DETECT); // Включим подтяжку

    DDRB |= 1 << AC_LOAD_0; // Настроим как выход
    DDRB |= 1 << AC_LOAD_1; // Настроим как выход

    PORTB &= ~( 1 << AC_LOAD_0 ); // Выключим оптопару
    PORTB &= ~( 1 << AC_LOAD_1 ); // Выключим оптопару
    GIMSK |= 1 << INT0; // Hазрешим прерывание от INT0
    MCUCR |= 1 << ISC01 | 1 << ISC00; // Настроим прерывание от INT0 по фронту.

    TIMSK |= 1 << OCIE1A | 1 << OCIE1B | 1 << TOIE1; // Разрешим прерывание для Таймера 1 по сравненю с OCR1A, OCR1B, и переполнению таймера
    TCNT1 = 0; // сбросим таймер
    TCCR1 = B00001011; // включим таймер с предделителем на 1024

    OCR1A=MAX_TCNT_VAL; // пропишем в регистр сравнения значение для выключенной нагрузки
    OCR1B=MAX_TCNT_VAL; // пропишем в регистр сравнения значение для выключенной нагрузки
    GTCCR=0x00;

    Serial.begin(38400); // оптимальный вариант, (в SoftwareSerial есть cli() на отправке)
    Serial.println(F("Ariadna")); // дает 38400
    }

    void loop() // отладочный вариант loop() с получением информациии из Arduino IDE: Канал + Мощность от 0 до 100. Например: 190 первый канал, мощность 90; 020 нулевой канал, мощность 20.
    {
    static char buff[5];
    static byte pos=0;
    static uint32_t last_ms=0;
    static uint32_t disp_ms=0;

    uint32_t tmp_ms=millis();
    int result = 0;
    byte processing_flag = 0;
    char c;

    if (Serial.available() > 0) // если что то приняли
    {
    c=Serial.read(); // прочитаем байт
    Serial.print(F("Received-"));
    Serial.println(c);

    if (c >= '0' && c <= '9' && pos < MAX_BUFF_LENG) // если цифра
    {
    buff[pos++]=c; // положим в буфер и сдвинем позицию
    last_ms = tmp_ms; // запомним время получения байта
    }
    else
    processing_flag=1; // если не символ - взведем флаг

    }

    if( pos >= 1 && ((tmp_ms - last_ms > 5000) || processing_flag) ) // если пауза больше 5 секунд или не цифра
    { // значит ввод закогчен и идет в обработку
    buff[pos]=0;
    result=atoi(buff+1); //
    pos=0;

    if (buff[0] <= '1' && result >= 0 && result <= 100) // если канал 0-1, значение 0-100
    {
    // ------ потом убрать вместе с принтами ----
    Serial.println();

    if (buff[0]=='0')
    Serial.print(" 0: <");
    else
    Serial.print(" 1: <");

    Serial.print(result);
    Serial.print("> (");
    //-------------------------
    if (buff[0]=='0')
    {
    dimming_0=map(result, 0, 100, MAX_TCNT_VAL, MIN_TCNT_VAL);
    Serial.print(dimming_0);
    }
    else
    {
    dimming_1=map(result, 0, 100, MAX_TCNT_VAL, MIN_TCNT_VAL);
    Serial.print(dimming_1);
    }
    Serial.println(") ");
    }
    }
    }
    Захотел диммер на Диджиспарк (ATtiny85). Решил компилить на платформе ATtinyCore. Взял код для УАРТ. Немного изменил.
    1. Поскольку платформа создает типа "аппаратный Сериал - нужды в СофтСериале - нет.
    2. Не все терминалы работают в пакетном режиме, а сразу шлют нажатую клавишу. Увеличил таймаут до 5 секунд для ручного ввода (str. 170).
    3. Ввел пару сервисных сообщений.
    Тестю в протеусе. Желтым - импульсы Ноль-перехода. Красный/Зеленый - Управление симистором. Регулируется, но фаза открытия симистора не желает приближаться к концу периода. На скрине задан - 1% мощности. Фаза показывает около 80-ти процентов на обоих каналах.
    Вопрос - в чем может быть причина ? Обязателен ли СофтСериал ? С уважением.
     

    Вложения:

    Последнее редактирование: 25 дек 2023
  11. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Изменил значение прескалера таймера с 1024 на 4096 и все заработало нормально. Странно.
    135 TCCR1 = B00001011; // включим таймер с предделителем на 1024
    на
    135 TCCR1 = B00001101; // включим таймер с предделителем на 4096
    Работает без СофтСериала. Кушает памяти - 21хх Байт ( С СофтСериалом -28хх Б)
    Короче говоря - всё что хотел - получил и даже больше. Тема закрыта.
     

    Вложения:

    • Pr4096.png
      Pr4096.png
      Размер файла:
      41,2 КБ
      Просмотров:
      57
    Последнее редактирование: 28 дек 2023
  12. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Всем цветомузыкам и бегущим огням нужны ТРИ канала. Добавил еще один. В Протезе работает. В реале - не собирал пока.
     

    Вложения:

    • 3Ch-dimmer.png
      3Ch-dimmer.png
      Размер файла:
      54 КБ
      Просмотров:
      64