Таблица 1 содержит значения задержки угла отпирания тиристора. Значения в крайнем правом столбце получены путём расчёта и предназначены для занесения в счётный регистр TCNT1 таймера-счётчика Т1 управляющего микроконтроллера.

 

Одноканальный диммер часть 2

 

  Данные значения задержек заносятся в программе обработки внешнего прерывания INT0 в счётный счётчика Т1 и инкрементируются в каждом следующем такте работы микроконтроллера (с частотой 1 МГц.) Применение 16-ти разрядного счётчика для отсчёта интервалов времени позволяет достаточно точно установить время отпирания симистора. В случае использования 8-ми разрядного счётчика Т0 микроконтроллера ATtiny2313 не удаётся достичь необходимой плавности регулирования яркости.

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

Во врезке 1 приведён массив значений счётчика для двухпроводной схемы включения диммера, обеспечивающей регулировку яркости лампы накаливания в пределах 8 — 92% от номинальной для двухпроводного включения диммера. Обратите внимание, что значения в массив lig[50] записаны начиная с последнего. Для дальнейшего пояснения работы программы диммера необходимо условиться, что максимальная яркость лампы будет устанавливаться при счётчике яркости равном нулю, а минимальная при значении 49.

 

F const unsigned int lig[50] = {63787, 63294, 62901, 62566, 62271, 62005, 61763, 61539, 61331, 61136, 60952, 60779, 60615,60459, 60310, 60168, 60031, 59901, 59776, 59655, 59539, 59428, 59320, 59216, 59115, 59018, 58924, 58834, 58746, 58660, 58578, 58497, 58420, 58344, 58271, 58200, 58130, 58063, 57998, 57934, 57873, 57812, 57754, 57697, 57642, 57588, 57535, 57484, 57434, 57386}; 

 

 Теперь пришла пора определиться с внешним прерыванием. Здесь существует один «подводный камень», который может поставить даже опытного С-программиста в тупик. Казалось бы, логичным настроить внешнее прерывание микроконтроллера на срабатывание по падающему фронту импульса, что бы иметь определённый запас времени для подготовки данных к началу следующего полупериода сетевого напряжения. При этом при снижении напряжения на входе схемы синхронизации до уровня порядка 26 В. запустится программа обработки прерывания в которой можно подготавливать счётчик и отсчитывать моменты времени до отпирания симистора. Для трёхпроводной схемы подключения диммера это действительно логично, работоспособно и способствует достижению максимально возможного значения яркости лампы. Однако при двухпроводном включении начинается довольно весёлая картинка (рисунок 13).

 

 

Одноканальный диммер часть 2

 

 

 

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


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

Учитывая, что полное описание программы займёт огромный объём печатных страниц, я остановлюсь лишь на некоторых важных моментах, на которые читателю необходимо обратить внимание.


  Определившись с прерываниями и схемой первым делом необходимо настроить работу внутренних модулей микроконтроллера и портов ввода-вывода. Для защиты от зависания микропрограммы задействуем встроенный в микроконтроллер сторожевой таймер с периодом срабатывания около 1 секунды:

 

//Настройка оборудования

wdt_enable(WDTO_1S);//Настройка сторожевого таймера 

 

Для снижения потребляемого тока отключим аналоговый компаратор микроконтроллера:

 

ACSR = 0x80;              //отключение аналогового компаратора 

 

Теперь настроим порты ввода вывода:

 

DDRD =  0b00010010;

PORTD = 0b00010011;

 

Регистр DDRD задаёт направление работы порта PORTD микроконтроллера. В те разряды регистра, в которые будет записаны единицы, будут работать на выход, а те в которых останутся нули — на вход. В нашем случае выходами являются те выводы портов микроконтроллера, к которым подключены светодиод и управляющий электрод симистора. Регистр PORTD задаёт уровень выходного напряжения, если порт микроконтроллера работает на выход или включает внутренний подтягивающий регистр, если порт работает на вход.

Здесь резонно возникает вопрос: А зачем устанавливать физический внешний резистор R3, если можно обойтись внутренним. Всё дело в том, что сопротивление внутреннего резистора не нормируется и может лежать в пределах от 5 до 200 кОм. Кроме того оно сильно зависит от температуры. В нашем случае необходимо обеспечить определенную величину постоянной времени RC-цепочки, образованной элементами R3C4 для нормального распознавания кратковременных и длительных прикосновений к сенсору. Если использовать внутренний подтягивающий резистор — это становится проблематичным.

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

 

//Настройки внешних прерываний

MCUCR = (1<<ISC00) | (1<<ISC01) | (1<<ISC11);

GIMSK = (1<<INT0) | (1<<INT1);

 

Запись GIMSK = | (1<<INT0) означает, что бит INT0 в регистре GIMSK установлен в единицу.

Далее необходимо разрешить обработку прерывания по переполнению таймера-счётчика 1:

 

//Настройки таймеров

TIMSK = (1<<TOIE1);

 

И разрешить общую обработку прерываний:

 

sei();

 

После чего для получения возможности сброса настроек устройства по умолчанию и запоминания команды дистанционного управления проверим наличие низкого логического уровня на выводе микроконтроллера, к которому через транзистор подключен сенсорный контакт:

 

if((PIND&0b1) == 0)    //если это первое включение

{

PORTD &=~(1<<LED);

while(rc5_code == 0) wdt_reset(); //ждать приёма команды от пульта

eeprom_write_word(&E_key_on_off, (rc5_code & 0b1111100111111));

eeprom_write_byte(&E_out, 49);

}       

 

  Теперь получается, что если при подаче питания обнаруживается прикосновение к сенсорному контакту или нажатие на кнопку, то программа микроконтроллера гасит светодиод, который по умолчанию при запуске микроконтроллера светится, ожидает в бесконечном цикле принятия кода от пульта дистанционного управления и после принятия такового сохраняет его в eeprom памяти. После этого программа устанавливает минимальную яркость лампы равную 49 (если вы помните то отсчёт уровней яркости ведётся от 49 до 0, где 0 — максимальная яркость).

Итак, теперь если коснуться сенсора, а затем подать питание на диммер, то он перейдёт в режим сброса настроек и запоминания кода пульта дистанционного управления, на который в дальнейшем будет отзываться. В этом режиме светодиод не светится, а устройство ожидает подачи команды от пульта дистанционного управления. Здесь нужно определиться, какую кнопку пульта использовать для управления устройством и нажать её.

Далее рассмотрим момент программы, ответственный за управление светодиодом:

 

//Управление светодиодом

if(imitaciya == 0)

         {

         if(led) PORTD &=~(1<<LED);        //выключить светодиод

         else

                   {

                   if (out_flag == 0) PORTD |= (1<<LED);   //включить светодиод если лампа выключена

         else PORTD &=~(1<<LED); //выключить светодиод если лампа включена

         }

}

 

Получается, что светодиод будет светиться, если выключен режим имитации присутствия (imitaciya = 0), переменная led = 0, (она используется для кратковременного гашения светодиода при приёме команды ДУ или касании сенсора) и выключена лампа (out_flag = 0), которая подключена к диммеру.

Если сделать так:

 

//Управление светодиодом

if(imitaciya == 0)

         {

         if(led) PORTD &=~(1<<LED);        //выключить светодиод

         else PORTD |= (1<<LED);              //включить светодиод

         }

 

получится, что светодиод будет гаснуть лишь при при приёме команды ДУ или касании сенсора и мигать в режиме имитации присутствия.

Для индикации включения режима имитации присутствия в программе обработки внешнего прерывания есть один момент: Каждый 5-й вызов обработчика, т.е. раз в 100 мс., выполняется вот такой фрагмент программы:

 

//Индикация имитации присутствия быстрым миганием светодиода

if(imitaciya)

         {

         PORTD ^=(1<<2);        //выключить светодиод

         }

 

Он вызывает инвертирование состояния бита порта, к которому подключен светодиод, что вызывает его мигание с частотой 2,5 Гц. если включен режим имитации присутствия.

Теперь о включении этого режима. Режим имитации присутствия включится, если более 20 секунд непрерывно касаться сенсора. Этот момент реализован в главном цикле программы:

 

//Включение имитации присутствия при удержании кнопки в нажатом состоянии более 20 секунд

if(imitaciya_on_count > 100)

         {

         if(imitaciya == 0)

                   {

                   imit_start();

                   }

         else

                   {

                   imitaciya = imit_timer = 0; //выключить

                   }

         imitaciya_on_count = 0;

         eeprom_write_byte(&E_imitaciya, imitaciya);  

         }

 

  Получается, что когда счётчик imitaciya_on_count превысит значение 100, а это случиться после того как 100 вызовов подряд программа обработки данных от сенсора обнаружит длительное касание, включится или выключится режим имитации присутствия, в зависимости от того, включен ли он был ранее. Данное значение соответствует 20 секундам реального времени, так как программа опроса клавиатуры вызывается каждые 20 мс. в момент определения перехода сетевого напряжения через ноль, что так же способствует «отлавливанию» и игнорированию ложных электромагнитных помех, в том числе генерируемых собственным сисистором.

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

 

 

//Имитация присутствия 

if(imitaciya)

         {

         if(imit_timer--);

         else   

                   {

                   lfsr = 5 + GaloisLfsr16(lfsr); //генерируем новое число

                   imit_timer = imit_mask & lfsr;        //загрузить в таймер имитации время

                   time_current = TIME_AP_OFF; //загрузить время в таймер автоотключения

                   inv_on_off(out_flag); //переключить канал 

                   }

         } 

 

Функция генерации случайных чисел GaloisLfsr16(); была сильно упрощена по сравнению с 15-канальной версией управляемого диммера [1]. Это пришлось сделать из-за малого объёма памяти микроконтроллера ATtiny2313 (всего 2 кБ). Однако, даже такая урезанная функция генерации случайных чисел, неплохо справляется с поставленной задачей.

Итак, каждую секунду декрементируется переменная imit_timer. Когда она достигнет нулевого значения, т.е. сгенерированное в предыдущий раз значение времени закончится, будет выполнена генерация нового случайного числа. Данной значение будет загружено в счётчик после наложения маски, ограничивающей максимальное время на которое может включаться и выключаться лампа imit_timer = imit_mask & lfsr. Значение маски imit_mask определяется в заголовочном файле программы «main.h», как и все другие константы программы. При значении imit_mask равном 0x3FFF максимальное генерируемое время составит 16383 секунд или чуть более 4,5 часов. Если вам необходимо увеличить или уменьшить максимальное генерируемое число, следует изменить данную константу. Однако важно понять, что данное значение не должно превышать заданное время автоматического отключения лампы при отсутствии команд управления, заданное константой TIME_AP_OFF во всё том же заголовочном файле «main.h». Из-за малого объёма памяти программ у микроконтроллера пришлось пойти на данное ограничение. В устройстве [1] такого ограничения нет. Я время автоматического отключения равным 43200UL, что соответствует 43 200 секунд или 12 часам ровно. Символы UL обозначают, что данная константа типа unsigned long, т.е. целое длинное. Без добавления данного индекса к целым большим числам нет никакой гарантии, что компилятор интерпретирует данное число как 16-ти разрядное.

Итак, манипулируя двумя данными константами теперь каждый читатель этой статьи, желающий повторить диммер, сможет установить данные временные интервалы по своему усмотрению. Только не вздумайте установить время автоматического отключения равным нулю, а то и включить лампу то не получится ;-), не следует так же превышать значение 2^16 - 1 = 65535, а то числа более 65535 компилятор округлит до 2-х байт.

Теперь самое главное: о том, как же регулируется яркость лампы. Всё управления яркостью лампы основано на задержке отпирания симистора относительно момента перехода сетевым напряжением нулевого значения. Данное управление целиком реализовано внутри двух обработчиков прерывания: обработчик внешнего прерывания INT0 и обработчик прерывания по переполнению таймера-счётчика Т1.

При переходе сетевым напряжением нулевого значения с задержкой около 30 мкс. вызывается обработчик прерывания INT0:

 

//Обработчик прерывания от INT0 при переходе сетевого напряжения через 0

SIGNAL (SIG_INTERRUPT0)

{

         TCCR1B = 0;

                  

         if(out_flag)

                   {

                   count1 = pgm_read_word(&lig[out1]);    

                   TCNT1 = count1;//начальная яркость

                   TCCR1B = 1;                                  //запуск таймера 1                                  

                   i = 0;

                   }

                  

         skan_key();                             //опрос кнопки 

}       

 

Вначале обработчик прерывания останавливает таймер Т1 микроконтроллера записью в регистр TCCR1B нуля. Затем производится проверка необходимости включения лампы. Если переменная out_flag не равна нулю в переменную count1 считывается из flash памяти микроконтроллера значение задержки lig[out1] соответствующее текущему необходимому значению яркости лампы out1. Далее это значение заносится в счётный регистр TCNT1 таймера-счётчика Т1, после чего записью в регистр таймера TCCR1B значения 1 он запускается на счёт с коэффициентом целения частоты внутреннего генератора микроконтроллера равным 1, т.е. с частотой счёта 1 МГц. С момента выполнения данной команды счётчик Т1 начинает отсчёт первого интервала времени. Далее переменная i, содержащая номер вызова таймера Т1 обнуляется и независимо от состояния лампы вызывается программа опроса сенсора ручного управления skan_key();.

При достижении таймером-счётчиком Т1 максимального значения счёта он переполняется и генерирует прерывание. Программа обработки прерывания по переполнению счётчика Т1 определяет, путём наложения маски, равен ли последний бит переменной i, содержащей номер вызова таймера Т1 нулю. Если он окажется равен нулю (сброшен), то значит это чётный вызов программы обработки прерывания по переполнению счётчика Т1. Следовательно, симистор необходимо включить путём формирования низкого логического уровня на выводе 4 порта PORTD микроконтроллера, что и делается командой установки бита PORTD &=~(1<<4);. Но перед этим в счётный регистр TCNT1 таймера Т1 загружается константа triac_open, равная 65516. При указанном значении данной константы таймер счётчик переполнится в следующий раз через 50 мкс. В конце обработчика прерывания инкрементируется значение переменной i.

 

SIGNAL (SIG_OVERFLOW1) //управление моментом отпирания симистора и яркостью

{

if((i & 1) == 0)

         {

         TCNT1 = triac_open;

         PORTD &=~(1<<4); //ВКЛЮЧИТЬ ТИРИСТОР              

         }                         

else

         {

         TCNT1 = t10ms + triac_delay; //задержка 10 мс - 50 мкс.

         PORTD |= (1<<4); //ВЫКЛЮЧИТЬ ТИРИСТОР 

         }

i++;

return;

} 

 

При следующем переполнении таймера Т1 последний бит окажется равным единице, так как переменная i после инкремента при предыдущем вызове стала равной 1. Теперь условие if((i & 1) == 0) не выполниться и программа обработчика прерывания Т1 микроконтроллера пойдёт по дугой ветви. В этом случае в счётный регистр таймера TCNT1 вновь будет загружено новое значение, но оно будет соответствовать задержке в 10 мс. за вычетом значения задержки, соответствующего 50 мкс. импульсу отпирания симистора. После этого командой PORTD &=~(1<<4); будет установлен высокий логический уровень на управляющем выводе симистора.

Таким образом и формируется импульс низкого логического уровня и длительностью 50 мкс. для отпирания симистора с необходимой задержкой. Следующий отпирающий импульс будет сформирован аналогично через 10 мс. после начала первого и будет соответствовать следующему (отрицательному) полупериоду сетевого напряжения.

В дальнейшем вновь сработает внешнее прерывание INT0 микроконтроллера и цикл вновь повторится. Таймер Т1 не успеет отсчитать второй 10 мс. цикл. Программа-обработчик внешнего прерывания INT0 остановит его до окончания второй 10-ти мс. задержки и перезапустит таймер инициализировав его новым значением счёта, соответствующим текущей установленной яркости лампы или остановит его если лампа должна быть выключена.

Декодирование команд дистанционного управления довольно сложная и запутанная вещь. Первоначально в программе одноканального диммера предполагалось использовать помехозащищённый декодер 15-ти канальной версии диммера [1], однако не удалось разместить его в малом объёме flash-памяти микроконтроллера ATtiny2313. Поэтому был использован свободно распространяющийся в сети интернет декодер команд RC-5 автора Mark Haemmerling [4], несколько оптимизированный по размеру программы. Данный декодер команд ДУ системы RC-5, обладающий меньшей помехозащищённостью и худшей распознаваемостью кода, по сравнению со старшим собратом [1], занимает в микроконтроллере в полтора раза меньший объём памяти, что и позволяет его использовать.

Однако здесь необходимо учесть некоторый момент. Дело в том, что стандартная посылка формата RC-5 содержит два стартовых бита, бит повтора, изменяющийся при каждом новом нажатии на кнопку ПДУ, пять бит адреса устройства и шесть бит кода команды. Код ПДУ после окончания декодирования помещается в глобальную двухбайтную переменную rc5_code, причём младший байт содержит 6 бит команды и два незадействованных байта, а старший всё остальное вышеперечисленное. Для отделения кода команды и адреса от «лишних» информационных бит используется наложение на принятую последовательность маски:

 

rc5_code & 0b1111100111111 

 

Вот мы и рассмотрели основные моменты работы программы и схемы диммера. Надеюсь, с помощью моей статьи читатели смогут не только повторить, но и модернизировать устройство. Вопросы и дополнения можно присылать на e-mail: servissistemy <собачка> narod.ru. Читателей, которые повторят устройство и захотят поделиться, к примеру, рисунком печатной платы, прошу писать туда же.

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

 

 

Одноканальный диммер часть 2



 


 

  Скачать [96,96 Kb] (cкачиваний: 634) прошивку, исходник

 

Список использованных источников:

 

1. http://servissistemy.narod.ru/12.htm - Умный Дом своими руками часть II  или 15-ти канальный управляемый диммер.

2. ГОСТ 2239-79. Лaмпы нaкaливaния oбщегo нaзнaчения. Tеxничеcкие уcлoвия.

3. http:///www.lutron.com/product_technical/pdf/LutronElectronics - "The Eye’s Response to Light".

4. http://electronix.ru/forum/index.php?act=Attach&type=post&id=31952 — архив с декодером RC-5.

5. http://servissistemy.narod.ru  - Мой персональный сайт.



   
slavyan # 1
 
 
Статья супер !!! smile
Спасибо большое автору и Nikolai4у.


   
st_valintin # 2
 
 
А печатка будет?


   
artemka89 # 3
 
 
Всем доброго времени суток! а можно например вместо IR приёмника поставить приёмник от автосигнализации на 433.92MHz и управлять с пультика?


   
egidis # 4
 
 
А печатка будет?


   
gosha437 # 5
 
 
Кто-нибудь собирал? Работает?


   
gosha437 # 6
 
 
Где обсуждаем данный дивайс?


   
Nikolai4 # 7
 
 
gosha437, пока нигде, если статья обсуждается на форуме то есть ссылка в статье, а так можешь создать с названием статьи тему на форуме и я прикреплю к статье, там и будем обсуждать


   
alex_user # 8
 
 
А как обучить? Все управление одной кнопкой?


   
aleks0306 # 9
 
 
собрал сенсор работает пульт нет


   
shell5050 # 10
 
 
Хочу повторить как пульт настроить?


   
krev_5680568058363 # 11
 
 
Доброго дня!
Собрал схему в Proteus-прошивка не работает. Ну думаю щас исходник откомпилирую. Загрузил данную версию WINAVR - файла проекта нет. Ну ладно думаю, щас создам проект подтяну файлы, скомпилирую, ан нет- куча ошибок. Значит нужны доп. библиотеки.
Ну, ответьте мне зачем выкладывать такой проект, без объяснения как его подтянуть. Вы очень хорошо теорию рассказали, академично а вот о практике -" кто хочет просто прошить дальше можете не читать" типа того и прошивай как знаешь. Все подивятся вашему уму(ведь мы то мало понимаем) Если вы хотите нам помочь, если вы УЧИТЕЛЬ ТО РАССКАЗЫВАЙТЕ ВСЁ И В ПЕРВУЮ ОЧЕРЕДЬ О ПРАКТИЧЕСКОМ ПРИМЕНЕНИИ НА ПАЛЬЦАХ и относитесь к нам как ученикам - в папке такие-то файлы, измените путь вот здесь, добавьте вот такие-то файлы библиотеки туда-то и туда-то. А уж где скачать мы найдем. Не забывайте, у нас нет спец знаний и только Вы и такие как Вы нас этому учите. Прошу прощение уж больно достало.


   
krev_5680568058363 # 12
 
 
И еще 1 минус автору
Ув. автор а вы обратили внимание на размер HEX-файла.
Флешь память AtTiny2313 всего 2кб, EEPROM - 128байт.
А ваш HEX-файл имеет размер более 5kб.
Это никуда не годится!!!!!!!!!!


   
DrunyaRuma # 13
 
 
Цитата: krev_5680568058363
И еще 1 минус автору
Ув. автор а вы обратили внимание на размер HEX-файла.
Флешь память AtTiny2313 всего 2кб, EEPROM - 128байт.
А ваш HEX-файл имеет размер более 5kб.
Это никуда не годится!!!!!!!!!!


hex файл это не bin, размер совпадать не должен


   
DrunyaRuma # 14
 
 
Ради интереса попробовал в Proteus, что-то работает, по крайней мере ошибок нет. Будет время посмотрю детальней.


   
DrunyaRuma # 15
 
 
Пересобрал проект из исходников под Atmel Studio 7 последней версии на сегодняшний день. Правда пришлось объединить все файлы в один Main.c т.к. последний раз работал только в AVR Studio 4 версии, а в 7 как-то все не привычно да и проект не компилировался. Кому надо в личку присылайте email.


Обновления

Сообщения ФорумаОтветов
3D Модели для Авто0
Бакометр 2335
Touch Start-Stop Engine.587
Кодграберр17
Исправляем AVR фьюзы при помощ …109
Бакометр - измеритель остатка…4
IR конструктор на PIC12F62977
Универсальное зарядное устройство103
бaкoмeтр1974
Двунаправленный автомобильный…2
Программатор GENIUS G8401
Светодиодный тахометр34
Индикаторы ГРИ ИН1 - ИН141
Multiprog1
Управляющая программа LED CUB959
Универсальное зарядное устройство9
Изготовлю печатные платы29
Простой автоматический выключа…25