диммер на прерываниях

unregistered
Offline
Зарегистрирован: 13.04.2017

Пытаюсь сделать простой диммер для ламппочки накаливания 220 В. Перерыл кучу информации, спаял плату детектора нуля и плату силовоо ключа. Нашел скетч которы более менее работает (и еще вагон), но все они мне не нравятся со своими делаями и magic number. По скольку сам немного программист, решил написать свой с основной лоикой на прерываниях. Вот загготовка:

int PIN_LOAD = 5;    // пин симистора

volatile unsigned int timer_tick = 0;//счетчик срабатываний таймера (одно срабатывание в 1 миллисекунду)
unsigned int last_timer_val = 0;
unsigned int dim_time;// интервал диммирования, задается в loop
void setup()
{
  Serial.begin(115200);
  pinMode(PIN_LOAD, OUTPUT);        // назначаем выходом
  attachInterrupt(0, zero_crosss, RISING);  // прерывание детектора нуля
//настройка тамера на срабатывание 1 раз в мс 
 TCCR0A |= (1 << WGM01);
  OCR0A = 0xF9;
  TIMSK0 |= (1 << OCIE0A);
  TCCR0B |= (1 << CS01) | (1 << CS00);
  sei(); 
}

ISR (TIMER0_COMPA_vect) //прерывание таймера для отслеживания нужного времени включения
{ 
  timer_tick++;
  if (timer_tick == dim_time)
  {
   digitalWrite(PIN_LOAD, HIGH);
   timer_tick = 0; 
  }
}                                                 

void zero_crosss()  
{
  digitalWrite(PIN_LOAD, LOW);
  timer_tick = 0; 
}

void loop()  {
  int val = analogRead(A0); //потенциометр           
  dim_time =map(val, 0, 1023, 0, 20); //масштаб от 0-20 мс - период полуволны
}

Идея простая от пересечения через ноль выключаем симистор на определенный период (0 - 20 мс - это время полуволны), потом включаем симистор до следующего перехода через 0. Например, если задать 10 мс, то лампа должна светиться в полнакала. Шаги такие: 

1. ловим ноль по внешнему прерыванию, закрываем симистор сбрасываем счетчик миллисекунд в 0

2. таймер начинает отсчитывать миллисекунды и по достижении заданного интервала диммирования открывает симистор. Возвращаемся к шагу 1.

3. Профит.

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

unregistered
Offline
Зарегистрирован: 13.04.2017

Уточнюсь: симистор не открывается вообще

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А если просто тупо (хоть в сетапе) исполнить digitalWrite(PIN_LOAD, HIGH);, он открывается? Вы проверяли?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Кстати, какой контроллер? 328?

Если он, то коду.

1. Строка 24. Кто, когда и при каких обстоятельствах возвращает пин PIN_LOAD в состояние LOW. Снаружи этого не сделать, т.к. он OUTPUT. Так где он становится LOW? Похоже, нигде. Тогда какой вообще смысл в прерывании? Достаточно было сделать его HIGH в сетапе.

2. dim_time тоже должен быть volatile

3. Нулевой таймер до Вас настраивала ардуиновская среда и она много чего напихала в регистры. чего Вам не нужно. Потому Вам надо сконфигурировать все биты так, как Вам надо. Это означает, что никаких |= в строках 12-15 быть не должно. Только прямые присваивания "="

4. Никогда не работайте вслепую! Для проверки по частям, просто дергайте какой-нибудь левый пин в обработчике прерываний и посмотрите осциллографом (или частотометром) дергается ли он и с какой частотой. Хоть будете уверены, что с таймером не ошиблись.

5. В строке 13 нужно FA вместо F9

vk007
Offline
Зарегистрирован: 16.06.2015

unregistered пишет:

Пытаюсь сделать простой диммер для ламппочки накаливания 220 В.

Идея простая от пересечения через ноль выключаем симистор на определенный период (0 - 20 мс - это время полуволны), потом включаем симистор до следующего перехода через 0.

Я чего-то не понял, какой смысл в таком диммере? Чем он будет отличаться от обычного диммера с использованием динистора? И там и тут срезается начало полуволны.

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

unregistered
Offline
Зарегистрирован: 13.04.2017

Евгений, спасибо за ответ!
По порядку тоже отвечу.

1. как обычный ключ все работает (digitalWrite HIGH работает).   В LOW его перводит функция по внешнему прерыванию от срабатывания детектора нуля на 2 пине (zero_crosss). детектор нуля дает HIGH на 2-й пин в момент перехода через этот самый ноль. 
2. dim_time, точно надо поставить volatile. хотя он меняется только в одном месте...
3 и 5. честно стырил код с уроков, так как под мои цели настройки вроде как раз. Моя вина, уже туго соображаю. попробую Ваш вариант.
4. действительно не подумал тупо подергать.

А в целом алгоритм рабочий? Я боюсь, что рассматриваю идеальную модель, на самом деле наверное может влиять например время закрытия оптопары на детекторе при переходе через ноль или еще какие-то факторы...

unregistered
Offline
Зарегистрирован: 13.04.2017

vk007, дак это тоже можно сделать, если с начала по переходу включать, а потом выключать.  HIGH на LOW поменять местами да и все... Это в целом не суть. для меня главное алгоритм рабочий

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

unregistered пишет:

А в целом алгоритм рабочий? 

Не знаю, скетч-то, как выяснилось, неполный, т.к., например,

unregistered пишет:

 В LOW его перводит функция по внешнему прерыванию 

а функции-то этой и нету :(

bwn
Offline
Зарегистрирован: 25.08.2014

unregistered пишет:

 если с начала по переходу включать, а потом выключать.  HIGH на LOW поменять местами да и все... 

С этого места можно поподробней?))))

unregistered
Offline
Зарегистрирован: 13.04.2017

vk007, подскажите что погуглить что за проблемы могут быть

unregistered
Offline
Зарегистрирован: 13.04.2017

bwn,  в zero_cross write HIGH, в функции таймера write LOW??? что может пойти не так? =)

bwn
Offline
Зарегистрирован: 25.08.2014

unregistered пишет:

vk007, подскажите что погуглить что за проблемы могут быть

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

unregistered
Offline
Зарегистрирован: 13.04.2017

Да как же нету а zero_crosss привзанная к прерыванию на RISING пин 2?

bwn
Offline
Зарегистрирован: 25.08.2014

unregistered пишет:

bwn,  в zero_cross write HIGH, в функции таймера write LOW??? что может пойти не так? =)

Симистор не транзистор, если включился, то хрен отключится, пока силовое напряжение не снимешь.

sadman41
Offline
Зарегистрирован: 19.10.2016

unregistered пишет:

bwn,  в zero_cross write HIGH, в функции таймера write LOW??? что может пойти не так? =)

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

unregistered
Offline
Зарегистрирован: 13.04.2017

Вы хотите сказать, что если я запишу LOW в пин управления симистором, то он не выключится? Мой выключается честно-честно.  И щас у меня моск (остатки) взорвется наверное

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

Тогда ты не понимаешь, как работает симистор. Выключается он не от LOW, а када синус через 0 проходит

unregistered
Offline
Зарегистрирован: 13.04.2017

sadman41 пишет:

unregistered пишет:

bwn,  в zero_cross write HIGH, в функции таймера write LOW??? что может пойти не так? =)

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

Думаю это тоже осуществимо с парой дополнительных флагов, пытаюсь с малого начать. Чтоб хоть что-то получилось

sadman41
Offline
Зарегистрирован: 19.10.2016

DetSimen пишет:

Тогда ты не понимаешь, как работает симистор. Выключается он не от LOW, а када синус через 0 проходит

Пажди, Семен. Мы еще не выяснили  - честный у него Си или как у илита.

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

Ну акей. Паду тогда квасить, пора уже

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

Но всеравно, ставлю его чесный С против двух бутылок моего срецтва, что человек за симисторы знает не все.

unregistered
Offline
Зарегистрирован: 13.04.2017

DetSimen пишет:

Тогда ты не понимаешь, как работает симистор. Выключается он не от LOW, а када синус через 0 проходит

Чо-то видимо да не понимаю. Один пишет в нуле он закрывается другой что он открывается))) Включаю я симистор по HIGH на оптопару котрая замыкается на управляющую ногу симистора (оптопара MOC3021). Симистор открывается. подаю на оптопару LOW - оптопара размыкается и сисмистор закрывается на переходе через ноль так?

unregistered
Offline
Зарегистрирован: 13.04.2017

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

unregistered
Offline
Зарегистрирован: 13.04.2017

DetSimen пишет:

Тогда ты не понимаешь, как работает симистор. Выключается он не от LOW, а када синус через 0 проходит

Запугали меня уже, я даже твой ответ неправильно прочитал ( Да все верно, это я понимаю

bwn
Offline
Зарегистрирован: 25.08.2014

Включается он у вас по HIGH, но не на нуле, а определенном минимальном напряжении, по этой причине ни один симисторный диммер не отдает 100% мощности. А отключается, да, опять таки на определенном минимальном напряжении. Останется HIGH, выключится и снова включится.

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, вам же пишут - симистор откроется по HIGH, закроется в переходе через ноль, невзирая на звания. LOW можете сразу подать после HIGH - ему пофигу уже. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

unregistered пишет:

Да как же нету а zero_crosss привзанная к прерыванию на RISING пин 2?

Виноват, с пьяных глах не заметил :(

В общем с алгоритмом включения нагрузки, тут пограмотнее меня люди подключились.

А по поводу настройки таймера - заменяйте |= на = чтобы вычистить все ьиты, которые туда среда внесла (но, кстати, Вы понимаете, что таким образом Вы убиваете функции типа millis, delay и всё, что на 0-ом таймере живёт?) И как проверить работает ли прерывание, я Вам идею дал, проверяйте.

unregistered
Offline
Зарегистрирован: 13.04.2017

Простейший силовой ключ moc3021 и сисмистор BTA 146-800. подаю HIGH - лампочка горит не тухнет. Или он закрывается но тут же открывается опять?

unregistered
Offline
Зарегистрирован: 13.04.2017

ЕвгенийП пишет:

unregistered пишет:

Да как же нету а zero_crosss привзанная к прерыванию на RISING пин 2?

Виноват, с пьяных глах не заметил :(

В общем с алгоритмом включения нагрузки, тут пограмотнее меня люди подключились.

А по поводу настройки таймера - заменяйте |= на = чтобы вычистить все ьиты, которые туда среда внесла (но, кстати, Вы понимаете, что таким образом Вы убиваете функции типа millis, delay и всё, что на 0-ом таймере живёт?) И как проверить работает ли прерывание, я Вам идею дал, проверяйте.

Это понимаю. Читал, подумал что если в скече не юзаются делэи и прочее стандартное то ничего страшного если |=

bwn
Offline
Зарегистрирован: 25.08.2014

unregistered пишет:

Простейший силовой ключ moc3021 и сисмистор BTA 146-800. подаю HIGH - лампочка горит не тухнет. Или он закрывается но тут же открывается опять?

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

unregistered
Offline
Зарегистрирован: 13.04.2017

bwn пишет:

unregistered пишет:

Простейший силовой ключ moc3021 и сисмистор BTA 146-800. подаю HIGH - лампочка горит не тухнет. Или он закрывается но тут же открывается опять?

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

Ну вот спасибо дошло до меня. Это учту. и про 100% мощности тоже понял что не получиться, тем не менее есть ли замечания по алгоритму ()кроме замечаний Евгения) Пусть и с полуволнами пока

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

unregistered пишет:

 если в скече не юзаются делэи и прочее стандартное то ничего страшного если |=

А если в процедуре прерывания таймера по сравнению в конце поставить TCNT0 = 0xFF то и delay и millis работать будут. Чучуть врать будут, да, но не критично

unregistered
Offline
Зарегистрирован: 13.04.2017

И вот еще. Раз пошел такой разовор, то пропуск целой полуволны в принципе с симистором не возможен или мгновенное закрытие/открытие можно назвать "пропуском полуволн"?

unregistered
Offline
Зарегистрирован: 13.04.2017

DetSimen пишет:

unregistered пишет:

 если в скече не юзаются делэи и прочее стандартное то ничего страшного если |=

А если в процедуре прерывания таймера по сравнению в конце поставить TCNT0 = 0xFF то и delay и millis работать будут. Чучуть врать будут, да, но не критично

delay мне религия не позволяет использовать а milis я заменю своим таймером легко

bwn
Offline
Зарегистрирован: 25.08.2014

Возможен, только для регулировки света этот метод не подходит и там уже можно х-ней не маяться, а поставить моську с ZG и рулить по времени. ИМХО.

sadman41
Offline
Зарегистрирован: 19.10.2016

unregistered пишет:

Это понимаю. Читал, подумал что если в скече не юзаются делэи и прочее стандартное то ничего страшного если |=

Там, в МК, есть еще Timer1 и Timer2. Используйте их и тогда миллис будет мягким и шелковистым. А если сразу начнете в прерывании делать HIGH только на каждой 10-й полуволне, то получите свои проценты, попадающие в нагрузку, полагаю. И с таймерами морочаться не будете.

unregistered
Offline
Зарегистрирован: 13.04.2017

bwn пишет:

 моську с ZG 

Это кто? MOC  с ZERO CROSS типа 3061?

bwn
Offline
Зарегистрирован: 25.08.2014

unregistered пишет:

Это кто? MOC  с ZERO CROSS типа 3061?

Угу.

unregistered
Offline
Зарегистрирован: 13.04.2017

sadman41 пишет:

Там, в МК, есть еще Timer1 и Timer2. Используйте их и тогда миллис будет мягким и шелковистым. А если сразу начнете в прерывании делать HIGH только на каждой 10-й полуволне, то получите свои проценты, попадающие в нагрузку, полагаю. И с таймерами морочаться не будете.

Timer1 и Timer2 тоже свое назначение имеют по шимам если правильно помню. timer0 только для подсчета мс мне нужен и дерганья ноги

unregistered
Offline
Зарегистрирован: 13.04.2017

Друзья, всем спасибо за помощь, за ликбез! Завтра буду пробовать, а потом опять приду уж не обессудьте 

nik182
Offline
Зарегистрирован: 04.05.2015

Тиристор или симистор закрываются когда ток через них становиться меньше тока удержания. Для лампочки или нагревателя это почти соответствует нулю напряжения, для индуктивных нагрузок - нет. Если есть Zero Cross в цепи управления, то тиррристор откроется с началом следующего периода тока сети, независимо от того в какой момент времени и какой длительности будет импульс управления во время текущего периода. В текущем не откроется. Не подходит для фазового управления.  Если метод управления фазовый, то тиристор открывается после подачи импульса управления. Задержка включения зависит от тока в цепи управления. Чем больше ток, тем быстрее включится тиристор. Последнее важно с точки зрения обеспечения минимального и максимального открытия тирристора. Чем уже импульс управления, тем шире углы регулирования, но надо больше тока. Тут главное не сжечь цепи управления. Также важна схема контроля перехода тока (не напряжения!!!) через ноль. Чем точнее схема выдает импульс привязки к нулю тока, тем шире угол регулирования. Это собственно все соображения для програмирования диммера. Т.е. по приему импульса синхронизации заряжаем таймер на время t=0-10 мс или два канала - один на угол открытия, второй угол открытия + длительность импульса управления . По срабатыванию таймера устанавливаем единицу в управление и заряжаем таймер на длительность импульса управления и (или ждём второй канал)  выключаем импульс управнения. Заряжать таймеры можно по разному. Главная идея обеспечить в прерывании таймеров задержку и импульс управления.   

Схему синхронизации лучше делать как то так http://www.3e-club.ru/view_full.php?id=14&name=zero-cross        

Kakmyc
Offline
Зарегистрирован: 15.01.2018

 

// управление тиристором, с регулировкой угла зажигания и синхронизацией
unsigned long CurrentMicros=0;//текущее время
unsigned long TimeShift=0;//время сдвига угла зажигания
void setup (){ 
    pinMode(10,OUTPUT);//сигнал на управление тиристором
    pinMode(3,0x2);}// сигнал перехода через ноль синхонизирующего напряжения
void loop(){ 
    TimeShift=analogRead(0)*8;//считываем время сдвига с регулировочного резистора и умножаем на коофициент задающий максимальный предел сдвига
    if(digitalRead(3)==0)//выполняем при переходе синхронизации через ноль
    {if(micros()-CurrentMicros>=TimeShift)/*даем задержку времени сдвига*/{digitalWrite(10,1); /*выдаем управляющий сигнал*/}} else {CurrentMicros=micros();digitalWrite(10,0);//при спадании уровня обновляем таймер и снимаем сигнал с управления.
		}}

http://arduino.ru/forum/programmirovanie/pomogite-porulit-tiristorom#comment-337384 Вот тут мне помогали, все работает.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

И время 20мс в корне не правильно, период полуволны 10мс

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

тоько хотел написать что получволна это 10 мс, а у автора получается отрезает один кусочек от двух полувол.

я вот только создал тему и тоже есть несколько вопросов. http://arduino.ru/forum/proekty/upravlenie-elektro-dvigatelem-ot-stiralnoi-mashinki-s-podderzhaniem-oborotov

добавлю сюда

в ардуино нано есть 2 пина с внешним прерыванием и функция выполняющаяся при наступлении какого то события, attachInterrupt http://arduino.ru/Reference/AttachInterrupt
 
1ВОПРОС - так вот 3 параметр в примрах все выбирают по возрастающему фронту (RISING )
 
почему так делают? ведь на отработку нужно минимальное время и контроллеру и триаку, не правильне ли будет выбрать параметр (FALLING ) по спадающему фронту, ведь все равно это ноль и пока все отработает триак уже будет закрыт и на подеме не будет в начале отрутым?
 
2 ВОПРОС - пины 2 и 3 поддерживают прерывание , если задать 2 разных прерывания не бдут ли пины мешать друг другу, и как обработается прерывание пина №3 если до него уже сработало прерывание пина 2 но еще не выполнилось?
 
 
и еще у автора выставлен таймер на 1мс, следовательно регулировать яркось можно на 1 деление из 10 (10%) я правильно понял?
Kakmyc
Offline
Зарегистрирован: 15.01.2018

Я вообще не уверен нужны ли тут таймер и прерывания. 

nik182
Offline
Зарегистрирован: 04.05.2015

Таймеры и прерывания нужны, если нужно иметь управление не просто крутилкой, а программно. Обмениваться информацией и каждый период сети точно выдерживать тайминг без прерываний не получится.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

nik182 пишет:

Таймеры и прерывания нужны, если нужно иметь управление не просто крутилкой, а программно. Обмениваться информацией и каждый период сети точно выдерживать тайминг без прерываний не получится.

Мы так то тут простой диммер мутим. Он как нибудь без таймеров поработает и прерываний.

bwn
Offline
Зарегистрирован: 25.08.2014

Kakmyc пишет:
nik182 пишет:

Таймеры и прерывания нужны, если нужно иметь управление не просто крутилкой, а программно. Обмениваться информацией и каждый период сети точно выдерживать тайминг без прерываний не получится.

Мы так то тут простой диммер мутим. Он как нибудь без таймеров поработает и прерываний.

Та ладно, просветите.

nik182
Offline
Зарегистрирован: 04.05.2015

Можно и простой. Но тот код, что приведён в #41, имеет склонность к дёрганию на 1 мс фазы управления. Если это нормально, то да пусть. Имеет право на существование. Мне кажется простой как раз с таймерами и прерываниями - думать не надо. Зарядил таймер и он сам отработает. 

unregistered
Offline
Зарегистрирован: 13.04.2017

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

unregistered
Offline
Зарегистрирован: 13.04.2017

Baks пишет:

тоько хотел написать что получволна это 10 мс, а у автора получается отрезает один кусочек от двух полувол.

я вот только создал тему и тоже есть несколько вопросов. http://arduino.ru/forum/proekty/upravlenie-elektro-dvigatelem-ot-stiralnoi-mashinki-s-podderzhaniem-oborotov

добавлю сюда

в ардуино нано есть 2 пина с внешним прерыванием и функция выполняющаяся при наступлении какого то события, attachInterrupt http://arduino.ru/Reference/AttachInterrupt
 
1ВОПРОС - так вот 3 параметр в примрах все выбирают по возрастающему фронту (RISING )
 
почему так делают? ведь на отработку нужно минимальное время и контроллеру и триаку, не правильне ли будет выбрать параметр (FALLING ) по спадающему фронту, ведь все равно это ноль и пока все отработает триак уже будет закрыт и на подеме не будет в начале отрутым?
 
2 ВОПРОС - пины 2 и 3 поддерживают прерывание , если задать 2 разных прерывания не бдут ли пины мешать друг другу, и как обработается прерывание пина №3 если до него уже сработало прерывание пина 2 но еще не выполнилось?
 
 
и еще у автора выставлен таймер на 1мс, следовательно регулировать яркось можно на 1 деление из 10 (10%) я правильно понял?

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

и да получается на 10%, диммер работает но хуево. моргает лампочка на значениях близких к минимуму. это наверное как раз 20 vs 10. я еще отпишусь. Спасибо за поддержку!