Обсуждаем контроллеры компании Atmel.
Ответить

Программное изменение яркости вакуумно-люминисцентных ламп

Ср авг 11, 2021 15:58:25

Всем здравствуйте!

Пытаюсь реализовать следующий эффект: при смене цифр одна плавно гаснет, вторая плавно появляется.

С общей регулировкой яркости проблем вообще нет. Все красиво, нормально. Алгоритм общей регулировки такой

Код:
// Timer2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)                 

    switch (a) {                                             
            case 0:
                    Cathode_0_on ();
                    print (a1);
                    break;
            case 1:
                    Cathode_1_on ();
                    print (a2);
                    break;               
            case 2:
                    Cathode_2_on ();
                    print (a3);
                    break;
            case 3:
                    Cathode_3_on ();
                    print (a4);
                    break;
            case 4:
                    Cathode_4_on ();
                    print (a5);
                    break; 
            case 5:
                    Cathode_5_on ();
                    print (a1);
                    break;
    }
    a++;
    if (a == 6) {a = 0;}                                       
}               

// Timer2 output compare interrupt service routine
interrupt [TIM2_COMP] void timer2_comp_isr(void)                   
{
    all_off ();
    off_segments ();   
}



Далее путем подбора OCR2 меняется яркость.

Как плавно регулировать яркость одной лампы я так и не понимаю, хотя уже множество попыток сделал.

1) Добавлял переменную B в прерывании, делал так:

Код:
if (b < bright1) {зажигать} else {не зажигать}


полная фигня, лампа моргает, засветы и прочие артефакты

2) Пробовал выполнять переключения ламп в прерывании, а зажигать сегменты в основной программе, она же типа быстрее. Получалась тоже фигня с засветами и мерцаниями.

Очень прошу помощи, уже не помню сколько раз возвращался к вопросу и так и не осилил (

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 16:56:02

https://www.radiokot.ru/forum/viewtopic ... 0#p3875550 <-- вот описание моей реализации для ГРИ.

Если вы не можете запрячь под это дело DMA, то можете добавить просто прерывание по сравнению таймера и по прерыванию по переполнению показываете новую цифру, а по прерыванию сравнения - старую.

Когда я делал такую штуку на светодиодах, там заметил, что чтобы яркость спадала/возрастала линейно, ШИМ должен изменяться по экспоненциальному закону. Но если разом гасить и зажигать другую цифру - ничего не получится, поэтому ШИМ меняем просто линейно.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 17:03:12

С тех пор, как мне захотелось совместить регулировку яркости с плавной сменой цифр, я стал делать так:

Каждый разряд при динамической индикации обрабатывается не 1 раз, а 16 (частота, соответственно, также увеличена в 16 раз). Выводятся цифры, хранящиеся в двумерном массиве - по 16 элементов массива на разряд. Чтобы получить плавную смену цифр, например, поменять 5 на 6, нужно с некоторым интервалом заполнять массив (в данном разряде) следующими наборами значений:
5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5
6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5
...
6 6 6 6 6 6 6 6 6 6 6 6 6 6 5 5
6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 5
6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6

Заполнение я делаю не в прерывании, а в main(), при помощи программного таймера, отсчитывающего интервалы времени для шагов плавной смены.

Такой алгоритм позволяет очень легко реализовать и другие эффекты, например, не "перетекание" одной цифры в другую, а плавное погасание старой цифры и резкое зажигание новой (это делается записью в массив специального кода, соответствующего пустому разряду).

P.S. Эх, пока я это всё писал, uldemir меня опередил.
Но, к слову, я использую описанный алгоритм на прерываниях в AVR без всяких DMA. И всё прекрасно работает, поскольку код в прерываниях сделан максимально компактным - просто выводится цифра из массива.

Добавлено after 6 minutes 17 seconds:
Re: Программное изменение яркости вакуумно-люминисцентных ламп
uldemir писал(а):Если вы не можете запрячь под это дело DMA, то можете добавить просто прерывание по сравнению таймера и по прерыванию по переполнению показываете новую цифру, а по прерыванию сравнения - старую

Такой вариант плохо совмещается с регулировкой яркости, к сожалению. Я по началу так и делал, а потом захотелось регулировать яркость, и пришлось от такого способа отказаться.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 17:15:32

*Trigger* писал(а):Такой вариант плохо совмещается с регулировкой яркости, к сожалению. Я по началу так и делал, а потом захотелось регулировать яркость, и пришлось от такого способа отказаться.
А если использовать два канала сравнения? один для яркости, другой для эффекта? Или у AVR нет таймеров с несколькими каналами захвата/сравнения?

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 17:33:48

Такие таймеры в AVR есть. Тут дело в другом. Пусть есть, скажем, 8-разрядный таймер. На полной яркости прерывание, где гасятся все разряды, возникает, например, при значении 240 в счётном регистре (чтобы сформировать паузу между разрядами). А на минимальной яркости пусть будет где-нибудь 80. Тогда при максимальной яркости менять значение в регистре сравнения того канала, где меняется старая цифра на новую, нужно в диапазоне 0...239, а на минимальной - в диапазоне 0...79. Если будет, например, 16 шагов при смене цифр, то придётся рассчитывать значение регистра сравнения для канала, где переключается цифра, исходя из текущего значения яркости. На полной яркости будет один набор значений, на минимальной - другой, где-то посередине - ещё один.
На мой взгляд, это неудобно. Лишние расчёты. И ещё нужно следить за тем, чтобы значение в регистре сравнения для гашения изменялось не абы когда, а только в определённые моменты времени, чтобы прерывания не поменялись местами.

Ну и гибкость у такого решения невелика. Вариант с 16 "проходами" одного разряда позволяет очень легко реализовать и всякие другие эффекты.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 18:14:51

К сожалению пока я не понимаю... DMA в атмеге8 вряд ли найдется, может вам не сложно будет кусок кода набросать? Что проще, перетекание одной цифры в другую или плавное гашение одной и розжиг другой? Допустим для начала всего одну цифру секунд плавно гасим, затем зажигаем новую.

Подойдет и на каком-нибудь условном языке.

Идею с массивом я понял, но никак не дойдет, как это будет в виде алгоритма выглядеть, хватит ли 8 МГц на это? Среда в принципе любая, но codevision с его PORTx.y = z понятнее была бы )
---

Усиленно перечитываю, вроде потихоньку что то доходит, но все равно пока еще не очень, буду благодарен за пример кода

Вот как я представил себе это. Есть сомнения на счет t, что там будет происходить, если общая яркость понижена, что то мне подсказывает что где то фигня, поправьте пожалуйста )

Код:
unsigned char digit1 [16] = {1, 1, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
unsigned char t = 0;

// Timer2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)                 
{
    switch (a) {                                             
            case 0:
                    Cathode_0_on ();
                    print (digit [t]);
                    break;
            case 1:
                    Cathode_1_on ();
                    print (a2);
                    break;               
            case 2:
                    Cathode_2_on ();
                    print (a3);
                    break;
            case 3:
                    Cathode_3_on ();
                    print (a4);
                    break;
            case 4:
                    Cathode_4_on ();
                    print (a5);
                    break;
            case 5:
                    Cathode_5_on ();
                    print (a1);
                    break;
    }
    a++;
    t++;
    if (t > 15) t = 0;
    if (a == 6) {a = 0;}                                       
}               

// Timer2 output compare interrupt service routine
interrupt [TIM2_COMP] void timer2_comp_isr(void)                   
{
    all_off ();
    off_segments ();   
}

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 18:38:30

Вот слегка адаптированный код из программы реальных часов (правда, на ГРИ, но тут особой разницы нет):


Тут нет определения некоторых переменных и структур, а также присутствует много макросов типа SET_PORT(). Также тут нет кода, определяющего факт смены цифр, устанавливающего биты в display_state.change_effect_flags и запускающего цикл смены. Надеюсь, без этого всего принцип всё равно будет понятен.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 18:49:47

Как то так.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 18:52:39

Попробую для себя главное выделить...



Вытянет ли 8 МГц все это? Проверять в железе смогу только завтра начать...

Где у вас происходит изменение bright_step_counter ?

if(++bright_step_counter == BRIGHT_STEPS_WITH_SAFE_PAUSE){

увидел, но весь смысл кусочка не понимаю пока

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 19:10:40

Таймер 16-битный, но используется в режиме Fast PWM, TOP = OCR1A. Это сделано для того, чтобы можно было произвольно менять частоту динамической индикации. По некоторым причинам в тех часах это было нужно.
Можно использовать 8-битный, но тоже в режиме Fast PWM (выходы OC** при этом включать не нужно). Этот режим хорош тем, что значения в регистрах сравнения буферизуются - новое значение загружается при переполнении таймера, поэтому не получится так, что в регистр сравнения записывается значение, меньшее, чем текущее значение в счётном регистре, и прерывания по совпадению не пропускаются. Первое прерывание в коде заменяется на прерывание по переполнению (тут зажигаем разряд), второе - по совпадению (тут всё гасим). Можно, конечно, и наоборот, но тогда при увеличении OCR яркость будет снижаться.

Вот это:
Код:
if(bright_step_counter >= BRIGHT_STEPS)
    return;

и это:
Код:
  if(++bright_step_counter == BRIGHT_STEPS_WITH_SAFE_PAUSE){
    bright_step_counter = 0;
    digit_mask <<= 1;
    if(++digit_counter == DIGITS){
      digit_counter = 0;
      digit_mask = (1 << 0);
    }
  }

служит для создания дополнительной паузы при переключении разрядов. Так пришлось сделать для подавления паразитной засветки. Для ВЛИ, думаю, это не актуально.
BRIGHT_STEPS_WITH_SAFE_PAUSE = BRIGHT_STEPS + 1. Поэтому в конце отображения каждого разряда, когда bright_step_counter == BRIGHT_STEPS, одно прерывание, где должен был бы зажечься разряд, пропускается (именно поэтому там return). Можно убрать первый кусочек и заменить во втором BRIGHT_STEPS_WITH_SAFE_PAUSE на BRIGHT_STEPS, тогда будет обычный алгоритм, который я описывал ранее.

Во втором кусочке инкрементируется текущая градация яркости, а когда все градации пройдены - номер разряда. На digit_mask не обращайте внимания, надо было мне её из кода убрать. Это переменная с "бегущей единицой", которая использовалась для десятичных точек и мигания разрядов.

Дальше Вы всё написали верно - выбираем цифру из массива, выводим в порт (в данном случае - на К155ИД1), зажигаем нужный разряд. Потом гасим. 4 цифры - для сокращения числа строк в примере. Можно и больше сделать. :)

На 8 МГц всё это прекрасно работает. Число градаций яркости было даже не 16, а 20. Частота переполнений таймера была 135 * 20 * 4 Гц. Это соответствует обычной динамической индикации, где частота импульсов на каждый разряд равна 135 Гц.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 19:23:41

Вот накидал своё, так правильно будет? Не полезет ли косяков при изменении OCR2?

Как я думаю, 6я цифра должна гореть менее чем на пол яркости, цифра 10, переданная в print заставляет его гасить все сегменты.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 19:30:21

Почти правильно. Нужно подправить инкремент a и t:
Код:
    t++;
    if (t > 15){
        t = 0;
        a++;
        if (a == 6)
            a = 0;
    }


print(), кстати, можно вынести за switch, используя a как индекс массива. Можно оставить, как сейчас, это, вроде бы, должно даже выполняться быстрее.

И учтите, что при OCR2 = 250 и предделителе таймера 8 на выполнение прерывания по совпадению есть всего 6 * 8 = 48 тактов.

Изменять OCR в режиме Fast PWM можно как угодно, но нужно следить, чтобы не было слишком больших и слишком маленьких значений. Иначе код в прерываниях не успеет выполниться, и следующее прерывание будет сдвинуто во времени.
Последний раз редактировалось *Trigger* Ср авг 11, 2021 20:29:04, всего редактировалось 1 раз.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 19:43:17

Если так сделать, мне кажется будет довольно сильно моргать с делителем 8... Вы таймер настраиваете без делителя? Или лучше действительно делать на таймере0 с двумя совпадениями и подбирать эти совпадения так, чтобы не слишком лагало и мерцало? Без делителя мне кажется, контроллер только и будет висеть в прерываниях постоянно )

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 19:48:12

А если так не делать, то получается что-то странное вместо нормального алгоритма. Хотя, можете попробовать. Даже интересно, что получится.

В том варианте, который предложил я, частота импульсов на каждый разряд (в терминах обычной динамической индикации) будет 8 000 000 / 8 / 256 / 6 / 16 = 40,7 Гц. Я мерцание с такой частотой вижу, но это всё индивидуально. В телевидении 25 Гц, и никто не жалуется. :)

Собственно, это была одна из причин, по которой я использовал таймер с двумя каналами совпадения.

Без делителя будет трудно уложить прерывания в ограниченное время выполнения.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 11, 2021 19:52:12

Что то похожее я уже делал и тут не то чтобы мерцало как телевизор... Там скорее 5-6 Гц частота была )) что весьма печалило, однако это уже кое что новое, чем делал я.

Большое спасибо за помощь и подсказки, в ближайшее время доберусь до собранных часов и попробую, а то уже очень много времени этот процесс с места не двигается, а все мои личные попытки провальны (
---

Проверил в железе... и все работает, сколько возился с этим, даже не предполагал что все на столько просто, капец...
---

К сожалению на частоте 8 МГц при делителе 1000 8 ощутимо мерцает, без делителя все адски лагает, так как постоянно висит в прерывании. Буду либо таймером0 делать, либо ставить кварц )

Re: Программное изменение яркости вакуумно-люминисцентных ла

Пн авг 23, 2021 21:29:53

Я делал просто - использовал BAM-модуляцию. Хранится текущая цифра и следующая. Дальше при выводе на единичный бит значения счётчика выводится одна цифра, а на нолик другая. Когда счётчик досчитал, одна цифра заменяется на другую.

IN12Clock V6 (with thermo).zip
(724.96 KiB) Скачиваний: 83


Код:
volatile uint8_t Digit[4]={0,0,0,0};//текущие отображаемые цифры
volatile uint8_t NewDigit[4]={0,0,0,0};//новые отображаемые цифры
volatile uint8_t ChangeDigitCounter[4]={0,0,0,0};//счётчик перехода от старых к новым цифрам

//----------
//обработчик вектора прерывания таймера T0 (8-ми разрядный таймер) по переполнению
//----------
ISR(TIMER0_OVF_vect)
{
 //выполняем плавное зажигание/погасание цифр с импользованием BAM (binary amplitude modulation)
 static uint8_t weight=0;//вес разряда
 
 uint8_t mask=0;
 
 mask=(1<<weight);
 TCNT0=0xff-mask;
 weight++;
 if (weight==5) weight=0;
 
 uint8_t digit[4]={Digit[0],Digit[1],Digit[2],Digit[3]};
 static bool new_digit[4]={false,false,false,false};
 
 for(uint8_t n=0;n<4;n++)
 {
  if (ChangeDigitCounter[n]==0) Digit[n]=NewDigit[n];//цифра сменилась
  if (ChangeDigitCounter[n]&mask) new_digit[n]=false;
                             else new_digit[n]=true;
  if (new_digit[n]==true) digit[n]=NewDigit[n];
 }
 
 OUTPUT_OutputDigit(digit);
}





//----------
//обработчик вектора прерывания таймера T2 (8-ми разрядный таймер) по переполнению
//----------
ISR(TIMER2_OVF_vect)
{
 //таймер вызывается 122.0703125 раза в секунду

 TCNT2=0;
 KEYBOARD_Scan();
 SENSOR_DecrementEnabledDataCounter();
 
 static uint8_t tick=0;
 
 tick++;
 if (tick==122)//прошла секунда (примерно)
 {
  if (CathodeCleaningCounter>0) CathodeCleaningCounter--;
  tick=0;
 }
 
 if ((tick&0x01)!=0) return;
 
 for(uint8_t n=0;n<4;n++)
 {
  if (ChangeDigitCounter[n]>0) ChangeDigitCounter[n]--;
 }
}



Собственно, когда надо сменить цифры, делается так:

Код:
 for(uint8_t n=0;n<4;n++)
 {
  if (NewDigit[n]!=set_digit[n]) ChangeDigitCounter[n]=0x1f;
  NewDigit[n]=set_digit[n];
 }



Тут, правда, есть нюанс. У меня статическая индикация. И я не трачу МК на развёртку показаний.

Re: Программное изменение яркости вакуумно-люминисцентных ла

Ср авг 25, 2021 07:52:28

Kotto, вопрос еще актуален ?
сам алгоритм плавной смены вы понимаете ?

Re: Программное изменение яркости вакуумно-люминисцентных ла

Пн авг 30, 2021 07:13:15

FreshMan, простите за долгий ответ, был в отпуске. По алгоритму триггера получилось вроде, но вот прямо конкретно реализовать алгоритм полностью с заполнением массива еще не делал, сегодня завтра начну. В целом, на 8 МГц мерцание заметно, если вблизи находиться, но если чуть отойти, то уже не особо.

Сам алгоритм вроде понял, а вот БАМ я когда то пытался осилить для управления ргб светодиодами, теми, что не ws2812, раз сто статьи по ней прочитал, так и не дошло (

Re: Программное изменение яркости вакуумно-люминисцентных ла

Пн авг 30, 2021 09:26:54

глядя на такой чудо-код:
руки так и тянутся...
Код:
ISR(TIMER0_OVF_vect) {
    //выполняем плавное зажигание/погасание цифр с импользованием BAM (binary amplitude modulation
    static uint8_t mask = 1;
    TCNT0 = 0xff - mask;
    mask <<= 1;
    if (mask == (<< 5)) mask = 1;

    uint8_t digind[4];

    for (uint8_t n = 0; n < 4; n++) {
        if (ChangeDigitCounter[n] == 0) Digit[n] = NewDigit[n]; //цифра сменилась
        digind[n] = (ChangeDigitCounter[n] & mask) ? Digit[n] : NewDigit[n];
    }

    OUTPUT_OutputDigit(digind);

Re: Программное изменение яркости вакуумно-люминисцентных ла

Пн авг 30, 2021 09:54:28

Kotto, предлагаю вам реализовать более легкий , на мой взгляд, метод реализации регулировки яркости индикаторов на 2-м таймере атмеги8 с кварцем на 16МГц (не пожалейте на него денег :)) )
Изображение
алгоритм следующий:
- в прерыванию по сравнению мы зажигаем ту или иную лампу
- в преывании по переполнению гасятся все лампы

если данная информация вас заинтересовала, прошу лайкнуть и мы не спеша продолжим дальше наше увлекательное путешествие в удивительный мир знаний :tea:
Ответить