Модераторы: PILOT, ManiaK, Mazzi

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [avr]Задержки при плавной регулировке. Диммер с ДУ, Условие удержания кнопки на пульте??? 
:(
    Опции темы
mr_smit
Дата 25.11.2010, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Здравствуйте. Вот уже который день бьюсь над плавной регулировкой яркости С ПУЛЬТА ДУ. Она регулируется, но почему то "ступенчато". Не пойму где ошибка в программе.

Итак по порядку:

1. Составил таблицу временных задержек для регулировки мощности с шагом 1%
2. При нажатии кнопки происходит плавное включение/выключение (РАБОТАЕТ!!!)
3. Добавил пульт ДУ. Он непонятно чьего производства (был куплен за 250 руб взамен умершего пульта от ТВ тюнера Beholder). К тюнеру подошел. Правда пришлось "обучать" программу тюнера (это предусмотрено). Но всё работает. По ссылке, приведенной выше, видно что пульт для техники Samsung. Я предположил что работает он по протоколу NEC. Взял исходник от статьи "Некоторые протоколы ИК-пультов" для NEC протокола... Не заработало  :(

Взялся за осциллограф. Оказалось что там не совсем NEC протокол... Т.е. единица и ноль кодируются как и в NEC протоколе:
user posted image
Только вот стартовая последовательность отличается по времени:
user posted image
~4,5 мс вместо 9 мс. И нет последовательности повтора!!! Т.е. при удержании кнопки посылка отсылается постоянно. Интервал между посылками 44,8 мс, длинна самой посылки 61,6 мс.

user posted image

В посылке 32 бита: "адрес"+"адрес"+"команда"+"инв. команда"
(это данные с осциллографа!!!)

Адрес передается не инвертированный. Но он нам собственно и не нужен. Команда согласно NEC протоколу. Пришлось править исходник. А именно стартовую последовательность.

4. Я выяснил коды нужных мне кнопок, "вставил" их в программу и сравниваю с переменной cmd. А в OCR1A записываю соответствующую задержку:

Код

/*========================================= УВЕЛИЧЕНИЕ/УМЕНЬШЕНИЕ ЯРКОСТИ =======================================*/

       if (cmd == 0b11111000) {       // кнопка "Display" - увеличение яркости
          TCCR1B=0x02;
          status++;
          if (status >= 98) {
            TCCR1B=0x00;
            status = 98;   
            PORTC.5 = 1;                // полностью включили
            }
          else {
            OCR1A = nagruzka[status];   // увеличиваем яркость
            delay_ms(delay_);
            }
         }
         
       if (cmd == 0b11000000) {      // кнопка "Sleep" - уменьшение яркости
          TCCR1B=0x02;
          status--;
          if (status < 1) {
            status = 0;                 // чтобы не уйти в минус
            PORTC.5 = 0;                // полностью выключили
            TCCR1B=0x00;
            }
          else {
            OCR1A = nagruzka[status];   // уменьшаем яркость
            delay_ms(delay_);
            }
         }


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

Итак, при нажатии на кнопку вкл/выкл: плавный старт, потом плавное отключение.

При нажатии на кнопку увеличения яркости, яркость должна так же плавно расти как и в предыдущем случае. До тех пор пока не отпустили кнопку. А она как бы замирает, увеличивается, замирает, увеличивается.

Я снял на видео как всё происходит: http://www.youtube.com/watch?v=7xy9u1OUq9s

Т.е. где то в коде не порядок.

У меня есть предположение: Просто сравнивать с переменной cmd видно нельзя. Вводить флаг повтора? Но посылки то одинаковые!!!. Как быть?

Команду я сбрасываю только если ничего не приходит уже на пин. Т.е. Условие if (cmd == 0b11000000) { должно выполняться при удержании кнопки. Или нет??????
Получается оно выполняется с какими то задержками... или где то команда успевает обнулиться и условие перестает выполняться. Чего то я запутался.

Код

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
        TCNT0=0xFA;                 //переинициировали таймер - отсчитывает 96 мкс
        tick++;                          //увеличили число тиков
        if (tick > 500) {              //если прошло более 48 мс (интервал
                                            // между посылками 44,8 мс)
          TCCR0=0x00;             //сбросили все к исходному состоянию
          TCNT0=0x00;
          tick = 0;                                                       
          start_cond = 0;
          //repeat_cond = 0;
          cmd = 0;
        }


Как в таком случае корректно команду обработать? Вроде всё правильно  :( 

Я принял за условие что при удержании кнопки переменная cmd всегда равна коду нажатой кнопки <-- может это не правильно???

Пробовал 
Код
while (cmd == 0b11111000) {}
 не работает. :(

Я в отчаянии... :( Не понимаю почему не работает. Уже столько вечеров убил на это. Не регулируется плавно, хоть об стенку расшибись. Ну вроде всё правильно в коде.

Схема: 
user posted image

Код в приложении:

Присоединённый файл ( Кол-во скачиваний: 14 )
Присоединённый файл  dimmer.c 12,07 Kb
PM MAIL   Вверх
UniBomb
Дата 25.11.2010, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
***
Награды: 1



Профиль
Группа: Участник Клуба
Сообщений: 1754
Регистрация: 24.10.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 97



Столько исходной информации, что я не могу всю её в голове удержать  smile 

Итак, во-первых попробуй вот что сделать - сбрасывай cmd сразу после обработки, во-вторых поставь else ко второму условию:

Код

/*========================================= УВЕЛИЧЕНИЕ/УМЕНЬШЕНИЕ ЯРКОСТИ =======================================*/
       if (cmd == 0b11111000) {       // кнопка "Display" - увеличение яркости
          cmd = 0;
          TCCR1B=0x02;
          status++;
          if (status >= 98) {
            TCCR1B=0x00;
            status = 98;   
            PORTC.5 = 1;                // полностью включили
            }
          else {
            OCR1A = nagruzka[status];   // увеличиваем яркость
            delay_ms(delay_);
            }
         }
         
       else if (cmd == 0b11000000) {      // кнопка "Sleep" - уменьшение яркости
          cmd = 0;
          TCCR1B=0x02;
          status--;
          if (status < 1) {
            status = 0;                 // чтобы не уйти в минус
            PORTC.5 = 0;                // полностью выключили
            TCCR1B=0x00;
            }
          else {
            OCR1A = nagruzka[status];   // уменьшаем яркость
            delay_ms(delay_);
            }
         }


Добавлено через 2 минуты и 26 секунд
В-третьих - поставь флаг срабатывая таймера по достижению OCR1, т.е. пока не зажгли с текущим значением яркости не изменять её.


--------------------
PM MAIL ICQ Skype   Вверх
mr_smit
Дата 25.11.2010, 15:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Сюда флаг:

Код

...

bit stat = 0;
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
  { 
  stat = 1;
  PORTC.5 = 1;    // открыли симистор
  delay_us(200);  // импульс 200 мкс
  PORTC.5 = 0;    // вернулись в режим ожидания
  }


И как его обработать в основном цикле??? К чему привязать?

Это сообщение отредактировал(а) mr_smit - 25.11.2010, 15:30
PM MAIL   Вверх
UniBomb
Дата 25.11.2010, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
***
Награды: 1



Профиль
Группа: Участник Клуба
Сообщений: 1754
Регистрация: 24.10.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 97



Цитата(mr_smit @  25.11.2010,  15:15 Найти цитируемый пост)
В каком месте???????

Я указал в каком месте в коде))) Сразу после захода в каждый if.


--------------------
PM MAIL ICQ Skype   Вверх
mr_smit
Дата 25.11.2010, 15:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Сразу не заметил. Исправил сообщение smile
PM MAIL   Вверх
UniBomb
Дата 25.11.2010, 15:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
***
Награды: 1



Профиль
Группа: Участник Клуба
Сообщений: 1754
Регистрация: 24.10.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 97



Как-то так:

Код

bit stat = 1;

/* --- */

/*=== УВЕЛИЧЕНИЕ/УМЕНЬШЕНИЕ ЯРКОСТИ ===*/
if((cmd == 0b11111000) && (bit stat))             // кнопка "Display" - увеличение яркости
{
    cmd = 0;
    stat = 0;
    TCCR1B=0x02;
    status++;
    if(status >= 98) 
    {
        TCCR1B=0x00;
        status = 98;   
        PORTC.5 = 1;               // полностью включили
    }
    else 
    {
        OCR1A = nagruzka[status];  // увеличиваем яркость
        delay_ms(delay_);
    }
}
else if((cmd == 0b11000000) && (bit stat))        // кнопка "Sleep" - уменьшение яркости
{
    cmd = 0;
    stat = 0;
    TCCR1B=0x02;
    status--;
    if (status < 1) 
    {
        status = 0;                // чтобы не уйти в минус
        PORTC.5 = 0;               // полностью выключили
        TCCR1B=0x00;
    }
    else 
    {
        OCR1A = nagruzka[status];  // уменьшаем яркость
        delay_ms(delay_);
    }
}

/* --- */

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)

    stat = 1;
    PORTC.5 = 1;    // открыли симистор
    delay_us(200);  // импульс 200 мкс
    PORTC.5 = 0;    // вернулись в режим ожидания
}



--------------------
PM MAIL ICQ Skype   Вверх
mr_smit
Дата 25.11.2010, 19:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



То же самое. Плавности нет. С задержками  smile 
PM MAIL   Вверх
mr_smit
  Дата 25.11.2010, 22:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Пока победил это так:
Код

bit button_up =0;
...
if ((cmd_1 + cmd_0) == 0xFF) {                                  //проверили правильность приема команды
                  button_up = no;
                  cmd = cmd_1;
                  }
...
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
        TCNT0=0xFA;                                                    //переинициировали таймер - отсчитывает 96 мкс
        tick++;                                                        //увеличили число тиков
        if (tick > 500) {                                              //если прошло более 48 мс
          button_up = yes;
          ...
        }
...
if (cmd == 0b11111000) {       // кнопка "Display" - увеличение яркости
          TCCR1B=0x02;
          while (button_up == no) {
            status++;
            if (status >= 98) {
              TCCR1B=0x00;
              status = 98;   
              PORTC.5 = 1;                // полностью включили
            }
            else {
              OCR1A = nagruzka[status];   // увеличиваем яркость
              delay_ms(delay_);
            }
          }
       }


Т.е. если прошло более 48 мс и от TSOPа ничего не пришло, то значит кнопку отпустили button_up = yes; и увеличение яркости в цикле while (button_up == no) прекращается.

Теперь регулируется плавно. Но заметил такую особенность: если нажать кнопку уменьшения яркости, а потом через 0,5-1 или 2-3 сек нажать кнопку увеличения яркости, то яркость продолжает уменьшаться  :(
Подождал. Дальше как надо регулируется.

Достала эта не стабильность :(((((
PM MAIL   Вверх
UniBomb
Дата 26.11.2010, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
***
Награды: 1



Профиль
Группа: Участник Клуба
Сообщений: 1754
Регистрация: 24.10.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 97



mr_smit, в общем логика должна быть такая:

определить момент изменения cmd->запретить её изменять->инкрементировать или декрементировать ocr1a->дождаться нескольких срабатываний таймера с текущим ocr1a->обнулить и разрешить изменять cmd->перейти к первому пункту




--------------------
PM MAIL ICQ Skype   Вверх
mr_smit
Дата 26.11.2010, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Как это в коде сделать? Я запутался окончательно. Голова сейчас взорвется.

Добавлено через 1 минуту и 9 секунд
Попытался синхронизироваться по импульсам от ДУ. Т.е. по приходу команды выполнять действие. Как раз разница между посылками вроде и должна дать задержку на плавность:

Код

...
        if (b_cnt == 32)  {                                                     //если приняли уже 4 байта
                 if ((cmd_1 + cmd_0) == 0xFF) {                                  //проверили правильность приема команды              
                  cmd = cmd_1;
                    if (cmd == 0b11111000) {      // кнопка "Display" - увеличение яркости
                     TCCR1B=0x02;
                     OCR1A = nagruzka[status];
                     status++;
                     if (status >= 98) {
                      TCCR1B=0x00;
                              status = 97;   
                      PORTC.5 = 1;                // полностью включили
                                 }
                    }


Нет эффекта. Так же ступенчато. Хоть об стену расшибись  smile 

Мой код то почти что рабочий. Думаю где то надо просто или прерывания отключать или ещё что. Но не хватает мозгов сообразить где. 
PM MAIL   Вверх
mr_smit
Дата 27.11.2010, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Убавил задержку в прерывании. Было 200 мкс, поставил 75 мкс. Стало плавнее...
Код

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
  { 
  PORTC.5 = 1;    // открыли симистор
  delay_us(75);  // импульс 75 мкс
  PORTC.5 = 0;   // вернулись в режим ожидания
  }


Как подать импульс открытия не используя delay_us(75) я не знаю. Понимаю что в прерывании нельзя использовать задержку. Но а как без неё??????????

Вот, смотрите как всё работает: http://www.youtube.com/watch?v=gSkNSZsmZ8Q
Последняя редакция кода в приложении.

Заметил что:
 
(cmd == 0b11111000) {      // кнопка "Display" - увеличение яркости
(cmd == 0b11011000) {      // кнопка "TV" - вкл/выкл диммера

отличаются только 1 битом. Может поэтому иногда при нажатии на увеличение лампа загорается полностью???? Не правильное принятие команды????

Это сообщение отредактировал(а) mr_smit - 27.11.2010, 17:28

Присоединённый файл ( Кол-во скачиваний: 13 )
Присоединённый файл  dimmer.rar 3,11 Kb
PM MAIL   Вверх
UniBomb
Дата 27.11.2010, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
***
Награды: 1



Профиль
Группа: Участник Клуба
Сообщений: 1754
Регистрация: 24.10.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 97



Цитата(mr_smit @  27.11.2010,  17:02 Найти цитируемый пост)
Понимаю что в прерывании нельзя использовать задержку. Но а как без неё??????????

Любые задержки в прерывании - зло. Вообще регулирование яркости не так делают. В прерывании убери задержку и просто изменяй состояние вывода. Таким образом он честь времени горит, и такую же часть времени не горит. Из-за инертности лампы накаливания мерцания не будет видно. А вот сама яркость будет регулироваться частотой срабатывания таймера.


--------------------
PM MAIL ICQ Skype   Вверх
mr_smit
Дата 27.11.2010, 21:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Я вот так сделал:
Код

...

OCR1A = nagruzka[status];
OCR1B = nagruzka[status]+200;        // импульс 100 мкс 
...

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
  { 
  PORTC.5 = 1;    // открыли симистор
  }
  
// Timer 1 output compare B interrupt service routine
interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{
PORTC.5 = 0;    // вернулись в режим ожидания
}


По совпадению А включили, по совпадению В выключили (через 100 мкс). На текущей яркости проблем нет. Стабильно горит на заданной яркости. Проблемы именно при регулировании. Иногда, когда полностью выключено, нажатие кнопки увеличения яркости приводит к плавному включению на 100%. Как будто команды путаются...

(cmd == 0b11111000) {      // кнопка "Display" - увеличение яркости
(cmd == 0b11011000) {      // кнопка "TV" - вкл/выкл диммера

Это сообщение отредактировал(а) mr_smit - 27.11.2010, 21:51
PM MAIL   Вверх
UniBomb
Дата 29.11.2010, 09:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
***
Награды: 1



Профиль
Группа: Участник Клуба
Сообщений: 1754
Регистрация: 24.10.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 97



Цитата(mr_smit @  27.11.2010,  21:48 Найти цитируемый пост)
Как будто команды путаются...

1. А ты проверяешь принятые команды? Ну т.е. ты же получаешь команды в прямом и инверсном виде. Ты их сравниваешь?
2. Закомментируй одну из веток (например на снижение яркости) и посмотри будет ли плавно увеличиваться яркость.


--------------------
PM MAIL ICQ Skype   Вверх
mr_smit
Дата 29.11.2010, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 254
Регистрация: 27.2.2008
Где: Самара

Репутация: 1
Всего: 4



Конечно проверяю:
Код

if ((cmd_1 + cmd_0) == 0xFF) {                                  //проверили правильность приема команды              
                  cmd = cmd_1;


С cmd уже работаю.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Микроконтроллеры (MCU) и микропроцессоры (MPU)"
PILOT ManiaK
UniBomb Mazzi

На данный раздел помимо Правил форума распространяются текже следующие правила:


  • Прежде чем создать тему воспользуйтесь поиском или посмотрите в faq. Возможно на форуме уже есть ответ на ваш или близкий к вашему вопрос.
  • В заголовке темы в квадратных скобках обозначьте используемое семейство микроконтроллера: [avr],[pic],[arm].
  • При создании темы с вопросом указывайте участок кода с ошибкой, версию компилятора, схемы подключения, fuse биты и прочие данные, которые помогут найти правильный ответ. Для форматирования текста программ используйте кнопку код.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Для флуда, просьб выполнить задание, поиска партнёров или исполнителей существуют свои разделы.
  • Если вы заметили несовместимое с правилами сообщение, то можете уведомить об этом модератора раздела нажав кнопку Репорт у соответствующего сообщения.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, PILOT, ManiaK, UniBomb, Mazzi.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Микроконтроллеры (MCU) и микропроцессоры (MPU) | Следующая тема »


 




[ Время генерации скрипта: 0.3447 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.