Данная схема не претендует на какую либо новизну и я осмелюсь представить на ваш суд схему контроллера или блока управления люстрой с шестью лампами. Данное устройство предназначено для управления шестью лампами любого типа. Традиционно схемы такого типа выполнялись с использованием тиристоров или симисторов, но с появлением малогабаритных люминесцентных ламп (энергосберегающих) такие схемы стали не пригодны. В данной схеме для управления используются электромеханические реле, которые управляются напряжением 12в при помощи ключей Т1..Т6, которыми в свою очередь управляет процессор АТ89С2051-24PI. Несколько странный, некоторым может показаться архаичный выбор процессора с ядром MCS-51 был обусловлен его наличием и достаточно низкой ценой, к тому же для начала освоения микроконтроллеров он на мой взгляд более подходит чем AVR контроллеры, так как он гораздо проще. Тактирование контроллера производится с использованием встроенного генератора с внешним кварцем на частоту 8,0 МГц.
Для управления контроллером используется стандартный пульт от телевизоров Горизонт 5го поколения с протоколом RC5. На пример такой как на рисунке ниже. Там же указаны коды данных передаваемых пультом.
Для приема сигналов пульта используется любой доступный ИК приемник на частоту 36 или 38кгц. Светодиод предназначен для индикации приема сигналов пульта управления. Питается схема от линейного блока питания состоящего из трансформатора, диодов, двух фильтрующих конденсаторов и микросхемы стабилизатора. Напряжение 12в используется для питания реле, 5в для питания остальной части схемы. Выключатели S1 и S2 это выключатели люстры установленные на стене. В данном случае люстра была подключена с использованием двух выключателей, включающих каждый свою секцию ламп, после модернизации люстры путем установки описываемого контроллера логика работы выключателей не поменялась и люстра может управляться только ими.
Логика работы прибора проста, при включении обоих выключателей люстра включается, контроллер не выполняет ни каких действий и ждет команды с пульта, все реле обесточены. При поступлении команды с пульта контроллер выполняет ее. Предусмотрены следующие команды: кнопки 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. Для решивших повторить проект, а может быть сделать что то свое с использование ИК управления захочется адаптировать программу для работы с другим кварцевым резонатором. Для этого достаточно будет изменить параметры всего двух циклов программы:
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-бит | AT89C2051 | 1 | АТ89С2051-24PI | Поиск в магазине Отрон | ||
VR1 | Линейный регулятор | LM7805 | 1 | Поиск в магазине Отрон | ||
ИК-приемник | 1 | Поиск в магазине Отрон | ||||
Т1-Т6 | Биполярный транзистор | КТ3102 | 6 | КТ315 | Поиск в магазине Отрон | |
D1-D10 | Диод | 1N1044 | 10 | 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-500 | 1 | Поиск в магазине Отрон | |||
Скачать список элементов (PDF)
Комментарии (3) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация