Контроллер люстры

Данная схема не претендует на какую либо новизну и я осмелюсь представить на ваш суд схему контроллера или блока управления люстрой с шестью лампами. Данное устройство предназначено для управления шестью лампами любого типа. Традиционно схемы такого типа выполнялись с использованием тиристоров или симисторов, но с появлением малогабаритных люминесцентных ламп (энергосберегающих) такие схемы стали не пригодны. В данной схеме для управления используются электромеханические реле, которые управляются напряжением 12в при помощи ключей Т1..Т6, которыми в свою очередь управляет процессор АТ89С2051-24PI. Несколько странный, некоторым может показаться архаичный выбор процессора с ядром MCS-51 был обусловлен его наличием и достаточно низкой ценой, к тому же для начала освоения микроконтроллеров он на мой взгляд более подходит чем AVR контроллеры, потому что он гораздо проще. Тактирование контроллера производится с использованием встроенного генератора с внешним кварцем на частоту 8,0 МГц.

Для управления контроллером используется стандартный пульт от телевизоров Горизонт 5го поколения с протоколом RC5. На пример такой как на рисунке ниже. Там же указаны коды данных передаваемых пультом.

Для приема сигналов пульта используется любой доступный ИК приемник на частоту 36 или 38кгц. Светодиод предназначен для индикации приема сигналов пульта управления. Питается схема от линейного блока питания состоящего из трансформатора, диодов, 2-х фильтрующих конденсаторов и микросхемы стабилизатора. Напряжение 12в используется для питания реле, 5в для питания остальной части схемы. Выключатели S1 и S2 это выключатели люстры установленные на стене. В данном случае люстра была подключена с использованием 2-х выключателей, включающих каждый свою секцию ламп, после модернизации люстры путем установки описываемого контроллера логика работы выключателей не поменялась и люстра может управляться лишь ими.

Логика работы прибора проста, при включении обоих выключателей люстра включается, контроллер не выполняет ни каких действий и ждет команды с пульта, все реле обесточены. При поступлении команды с пульта контроллер выполняет ее. Предусмотрены следующие команды: кнопки 1..6 выключают соответствующую им лампу, кнопка 9 включает все лампы, кнопки VBSCT+/- выключают и включают лампы по одной (уменьшают и увеличивают свет), кнопка с кодом 38 выключает все лампы по очереди (как в кинотеатре), кнопка М демонстрирует бегущий огонек, а далее возвращает люстру в исходное состояние, кнопки Р+/- позволяют «вращать» источник света (довольно полезная функция).

Контроллером управляет программа написанная с использованием среды Keil uVision2 на языке С.

Текст программы:

//*****************************************************************************************************
//
// Lamp controller
// CPU — AT89C2051
// Clock 8.000 MHz
// Six lamp controller. IR control RC-5
// Autor Panda okt 2011
//
//******************************************************************************************************

#include

#define Lamp_A P1_7
#define Lamp_B P1_6
#define Lamp_C P1_5
#define Lamp_D P1_4
#define Lamp_E P1_3
#define Lamp_F P1_2

#define IR P3_2 //IR Port
#define LED P3_4 //LED

#define LOW 16 //VBSCT — button
#define HI 17 //VBSCT + button +- button is swop.
#define SLOW_OFF 38 //Timer off button
#define RUN_LIGHT 41 //M button run light.
#define SHIFT_R 32 //P+ button
#define SHIFT_L 33 //P- button
#define ORDER 59 //SL button

#define ON 0
#define OFF 1

unsigned char _cmd, temp, cnt, MIRROR;
unsigned int _addr;

//**********************************************************************************
// External Interrupt 0 service routine receive command from IR remote control unit
//**********************************************************************************
void ext_int0_isr(void) interrupt 0
{unsigned char ppp, pin;
unsigned int _tmp, tout;
EA = 0; //ALL interrupt disable
_tmp = 1;
LED = ON;

for(ppp = 1; ppp<14; ppp++)
{for (tout = 100; tout >0; tout—);
pin = IR;
for (tout = 100; tout > 0; tout—)
if (pin != IR) break;
if (tout == 0) {EA = 1; //timeout
IE0 = 0; //clear external interrupt flag
LED = 1;
return;};
_tmp = _tmp << 1;
if (!IR) _tmp++;
};
_cmd = _tmp & 0x003F;
_addr = _tmp & 0xFFC0;
_addr = _addr >> 6;
IE0 = 0; //clear external interrupt flag
EA = 1;
LED = OFF;
}

void main(void)
{
EA = 1;
EX0 = 1;
IT0 = 1; //external interrupt 0 activated on falling age
LED = 1; //off led
IR = 1;

P1 = 0x00; //All lamp on
MIRROR = 0x00;

LED = ON;
_addr = 50000;
while (_addr)
_addr—;
LED = OFF;

while (1)
{
if (_cmd == 1) {Lamp_A = OFF;
MIRROR |= OFF<<7;};
if (_cmd == 2) {Lamp_B = OFF;
MIRROR |= OFF<<6;};
if (_cmd == 3) {Lamp_C = OFF;
MIRROR |= OFF<<5;};
if (_cmd == 4) {Lamp_D = OFF;
MIRROR |= OFF<<4;};
if (_cmd == 5) {Lamp_E = OFF;
MIRROR |= OFF<<3;};
if (_cmd == 6) {Lamp_F = OFF;
MIRROR |= OFF<<2;};
if (_cmd == 9) {P1 = 0x00; //All lamp on
MIRROR = 0x00;};
if (_cmd == LOW)
{temp = MIRROR;
for (cnt = 2; cnt <= 7; cnt++)
{temp &= (0xFE << cnt);
if (MIRROR > temp)
break;};
if (cnt < 8)
{P1 = temp;
MIRROR = temp;};
};
if (_cmd == HI)
{temp = MIRROR;
for (cnt = 2; cnt <=7; cnt++)
{temp |= (0x01 << cnt);
if (temp > MIRROR)
break;};
if (cnt < 8)
{P1 = temp;
MIRROR = temp;};
};
if (_cmd == SLOW_OFF)
{for (cnt = 2; cnt <= 7; cnt++)
{P1 |= (1 << cnt);
MIRROR |= (1 << cnt);
_addr = 60000;
while (_addr)
_addr—;};
};
if (_cmd == SHIFT_R)
{temp = MIRROR;
temp = temp >> 1;
if ((temp & 0x02) > 0)
temp |= 0x80;
P1 = temp & 0xFC;
MIRROR = temp & 0xFC;};

if (_cmd == SHIFT_L)
{temp = MIRROR;
if ((temp & 0x80) > 0)
temp |= 0x02;
temp = temp << 1;
P1 = temp;
MIRROR = temp;};

if (_cmd == RUN_LIGHT)
{for(temp = 2; temp <= 7; temp++)
{P1 = ~(1 << temp);
_addr = 50000;
while(_addr) _addr—;};
P1 = MIRROR;
};

_cmd = 0;
};
}

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

Протокол RC-5используемый во многих системах управления теле-видео и другой аппаратурой достаточно подробно описан здесь. Коротко опишу: посылка состоит из 14 бит длительностью 1.778мс каждый и содержит два стартовых бита которые всегда равны 1, далее следует триггерный бит, который изменяет свое состояние при каждом нажатии клавиши. В простых проектах как этот, его совершенно не обязательно обрабатывать, далее 5 бит адреса и 6 бит данных, далее следует пауза длительностью 89мс. Для передачи данных используется так называемый манчестерский код, ещё такую кодировку называют бифазной. При таком способе передачи данных логическая 1 кодируется как перепад сигнала с высокого на низкий уровень (отрицательный или задний фронт импульса), и логический 0 кодируется перепадом сигнала с низкого на высокий уровень (положительный или передний фронт импульса). Смена состояний производится в середине периода. Выглядит посылка как показано ниже:

Такую посылку можно декодировать несколькими способами, самый простой из которых после приема первого импульса подождать примерно три четверти периода – это 1200-1300 мкс, далее в течении оставшегося времени отслеживать изменение уровня сигнала. Если в течении примерно 700мкс не произошло изменения сигнала, то прием пакета прерывается и ожидаем следующий. Если изменение произошло, то фиксируем 0 либо 1 (в зависимости от состояния линии) и цикл повторяем ещё 13 раз.

for(ppp = 1; ppp<14; ppp++)
{for (tout = 100; tout >0; tout—); //Ожидание 1200мкс
pin = IR;
for (tout = 100; tout > 0; tout—) //Ожидание 700-1200мкс, начальное значение tout можно уменьшить (для тех кого
if (pin != IR) break; // напугали одинаковые значения инициализиции tout)
if (tout == 0) {EA = 1; //timeout
IE0 = 0; //clear external interrupt flag
LED = 1;
return;};
_tmp = _tmp << 1;
if (!IR) _tmp++;
};

Здесь ррр – счетчик импульсов, tout – счетчик времени ожидания прихода импульса, pin – переменная в которой хранится состояние линии до изменения. В переменную _tmp записываем принятую посылку. Всякий раз после приема очередного бита данные в _tmp сдвигаются влево и в случае когда принята лог.1 к ней прибавляется единица.

Прием сигналов ИК пульта осуществляется в процедуре обработки внешнего прерывания INT0,

//**********************************************************************************
// External Interrupt 0 service routine receive command from IR remote control unit
//**********************************************************************************
void ext_int0_isr(void) interrupt 0

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

_cmd = _tmp & 0x003F;
_addr = _tmp & 0xFFC0;
_addr = _addr >> 6;

А адрес в переменную _addr. Эта переменная в дальнейшем не используется, и разделение пультов по адресу не производится, но это довольно легко добавить. Используемые пульты работали оба на 0м канале, по этому необходимости их делить не было. Дальнейшая обработка команды, производится в основном теле цикла программы:

while (1)
{
if (_cmd == 1) {Lamp_A = OFF;
MIRROR |= OFF<<7;};
if (_cmd == 2) {Lamp_B = OFF;
MIRROR |= OFF<<6;};
if (_cmd == 3) {Lamp_C = OFF;
MIRROR |= OFF<<5;};



P1 = temp;
MIRROR = temp;};

if (_cmd == RUN_LIGHT)
{for(temp = 2; temp <= 7; temp++)
{P1 = ~(1 << temp);
_addr = 50000;
while(_addr) _addr—;};
P1 = MIRROR;
};

_cmd = 0;
};

По окончании обработки команды, ее код обнуляется.
Ещё несколько особенностей программирования с которыми сталкиваются начинающие. В программе есть переменная MIRROR, для чего она? В контроллерах серии АТ89СХХХХ обращение к портам ввода вывода производится с помощью одного регистра, но запись и чтение из порта производятся в разных регистрах внутри контроллера. То есть когда вы записываете данные в порт P1 = 0xff; внутри контроллера запись производится в один регистр не доступный для пользователя, при чтении порта aa = P1; чтение производится из другого регистра и фактически порт настраивается на чтение данных с ножек контроллера. Таким образом записав в порт любое число скажем 0х05, а далее прочитав состояние порта вы получите совсем другое число. (P1 = 0x05) != (aa = P1) à aa != 0x05; Это обстоятельство нужно учитывать при разработке программ.

Хотелось бы ещё дать один совет теперь уже по работе со средой программирования Keil_uVision2. Для решивших повторить проект, а может быть сделать что то свое с использование ИК управления захочется адаптировать программу для работы с другим кварцевым резонатором. Для этого достаточно будет изменить параметры всего 2-х циклов программы:

for(ppp = 1; ppp<14; ppp++)
{for (tout = 100; tout >0; tout—); //Ожидание ~1200мкс
pin = IR;
for (tout = 100; tout > 0; tout—) //Ожидание ~700мкс-1200мкс
if (pin != IR) break;
if (tout == 0) {EA = 1; //timeout
IE0 = 0; //clear external interrupt flag
LED = 1;
return;};
_tmp = _tmp << 1;
if (!IR) _tmp++;
};

Сделать это без расчетов будет довольно просто. Среда Keil uVision2 имеет в своем составе отладчик и в режиме отладки всегда можно посмотреть текущее процессорное время.

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

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

Теперь о конструкции. Контроллер не программируется внутрисхемно, по этому усажен в панельку, Fuse битов не имеет, что сильно упрощает процесс программирования. Для программирования использовался программатор Blow it. Взять его можно здесь, пост #3. Это очень простой и надежный программатор, который служит уже без малого 10 лет. Вопросы по программатору можно задать в указанном топике. Контроллер АT89C2051-24PI, транзисторы Т1..Т6 можно применить любые маломощные, структуры n-p-n на пример кт3102, кт315. Реле К1..К6 на напряжение 12в, способные коммутировать 220в. Ток потребляемый одним реле ~20ма. Диоды могут быть любыми выпрямительными на ток до 1А и напряжением более 100в, на пример 1N1044, 1N1050, 1N1056. Конденсатор С4 должен быть рассчитан на напряжение не менее 25в. Выпрямитель и трансформатор использованы от китайского блока питания на ток 300 мА.

Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот

МК AVR 8-битAT89C20511
АТ89С2051-24PIVR1
Линейный регуляторLM78051

ИК-приемник1
Т1-Т6
Биполярный транзисторКТ31026
КТ315D1-D10
Диод1N104410
1N1050, 1N1056С1, С2
Конденсатор33 пФ2
С3
Электролитический конденсатор1 мкФ1
С4, С5
Электролитический конденсатор200 мкФ2
С6
Конденсатор0.1 мкФ1
R1
Резистор2.2 кОм1
R2
Резистор470 Ом1
R3-R8
Резистор20 кОм6
Qz1
Кварцевый резонатор11.0592 МГц1
LED1
Светодиод1
К1-К6
Реле12 В6
Tr1
Трансформатор220/12 В1
L1-L6
Лампочка220 В6
Входят в состав люстры
Пульт дистанционного управленияRC-5001
Добавить все

Скачать список элементов (PDF)

Добавить комментарий

Ваш адрес email не будет опубликован.