В данной статье мы рассмотрим проект автоматизации управления несколькими потребителями переменного тока с помощью микроконтроллера PIC по инфракрасной связи (IR remote) с пульта ДУ. Подобные проекты также называют системами умного дома. Ранее аналогичный проект на нашем сайте мы рассматривали на основе платы Arduino.
Чтобы сделать данный проект более интересным, мы добавили в него возможность управления с пульта инфракрасной связи скоростью вращения вентилятора с помощью симистора (Triac). Для проекта подойдет практически любой пульт дистанционного управления (ДУ) от ваших домашних устройств: телевизора, DVD проигрывателя и т.д. Инфракрасные сигналы с пульта ДУ будет приниматься и обрабатываться нашим микроконтроллером PIC, которые будет подавать команды на включение/выключение соответствующих реле в нашем проекте.
Также на нашем сайте вы можете посмотреть и другие проекты автоматизации дома:
- автоматизация дома на Raspberry Pi с управлением с веб-страницы;
- управление светом в доме с помощью сенсорного датчика и Arduino;
- автоматическая регулировка температуры в доме с помощью терморезистора и Arduino;
- автоматизация дома на Arduino под управлением смартфона.
Общие принципы работы проекта
Принцип работы нашего проекта автоматизации дома достаточно прост. Когда вы будете нажимать какую либо кнопку на пульте ДУ, то его инфракрасный передатчик будет передавать последовательность импульсов, промодулированную частотой 38 кГц. Эта последовательность импульсов будет приниматься инфракрасным приемником TSOP1738 (который имеет возможность принимать сигналы частотой 38 кГц) и передаваться на микроконтроллер PIC. Микроконтроллер будет преобразовывать их в шестнадцатеричное значение (hex value) и сравнивать его с заранее определенными в нашей программе шестнадцатеричными значениями.
Если будет фиксироваться совпадение сравниваемых значений, то микроконтроллер будет подавать управляющую команду на соответствующее реле/симистор. Результаты выполнения команды будут отображаться с помощью светодиодов на плате нашего проекта. В качестве потребителей переменного тока в нашем проекта мы использовали 4 небольшие лампы разных цветов, а большая лампа будет имитировать работу вентилятора, частотой вращения которого мы как бы будем управлять.
Мы будем использовать клавишу 1 на пульте ДУ для переключения (включения/выключения) 1-го реле, клавишу 2 – для переключения 2-го реле и т.д. Клавиша Vol+ будет использоваться для увеличения скорости вращения вентилятора, а клавиша Vol- – для уменьшения скорости вращения вентилятора.
Примечание: вместо вентилятора в нашем проекте мы будем использовать 100-ваттную лампочку.
Наш микроконтроллер PIC работает от напряжения +5V, а реле – от напряжения +12V. Поэтому в нашем проекте мы будем использовать понижающий трансформатор на 220V, напряжение с выхода которого будет выпрямляться с помощью мостовой схемы. Далее это напряжение будет стабилизироваться к значениям +12V и +5V с помощью регуляторов напряжения 7812 и 7805 соответственно.
Для управления переключениями реле мы будем использовать транзисторы BC547. Для управления скоростью вращения вентилятора мы будем использовать симистор (TRIAC). Более подробно про использование симистора для управления скоростью вращения вентилятора вы можете прочитать в данной статье.
Также мы будем использовать схему управления симистором (Triac Driver) чтобы управлять им с помощью микроконтроллера. Эта схему будет обеспечивать углы отсечки для симистора. У нас будет 6 уровней скорости вращения вентилятора. При скорости 0 вентилятор будет выключен. При скорости 1 вентилятор будет вращаться со скоростью 1/5 от максимальной, при скорости 2 – со скоростью 2/5 от максимальной и т.д. Текущий уровень скорости вращения вентилятора можно будет контролировать с помощью семисегментного индикатора.
Структурная схема работы проекта показана на следующем рисунке.
Необходимые компоненты
- Микроконтроллер PIC18f2520.
- Программатор PICkit 3 (купить на AliExpress).
- Кварцевый генератор 20 МГц (купить на AliExpress).
- Инфракрасный приемник TSOP1738 (купить на AliExpress).
- Пульт ДУ (TV/DVD).
- Транзистор BC547 – 4 шт. (купить на AliExpress).
- Реле на 12 В – 4 шт.
- Лампочки с держателями – 5 шт.
- Источник питания 12v.
- 2-х пиновый коннектор – 8 шт.
- Трехпиновый коннектор.
- Трансформатор 12-0-12.
- Регулятор напряжения 7805 (купить на AliExpress).
- Регулятор напряжения 7812 (купить на AliExpress).
- Конденсаторы 10 и 1000 мкФ (купить на AliExpress).
- Конденсатор 0,1 мкФ (купить на AliExpress).
- Конденсатор 0,01 мкФ 400 В (купить на AliExpress).
- Конденсатор 33 пФ – 2 шт. (купить на AliExpress).
- Резисторы 10 кОм (5 шт.), 1 кОм (5 шт.), 100 Ом (7 шт.) (купить на AliExpress).
- Семисегментный индикатор с общим катодом (купить на AliExpress).
- Диод 1n4007 – 10 шт. (купить на AliExpress).
- Симистор BT136 (купить на AliExpress).
- Светодиод – 6 шт. (купить на AliExpress).
- Оптопара moc3021.
- Оптопара mtc2e или 4n35.
- Диод Зенера (стабилитрон) – 2 шт.
- Резистор 27 Ом 2 Вт.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Декодирование сигналов с пульта ДУ
В нашем проекте мы можем использовать практически любой инфракрасный пульт ДУ, но для используемого нами пульта ДУ необходимо будет знать, какие шестнадцатеричные значения будут соответствовать его кнопкам. Зная эти шестнадцатеричные значения мы сможем с помощью микроконтроллера различать какая кнопка была нажата. Авторы проекта (ссылка на оригинал приведена в конце статьи) использовали пульт NEC. Шестнадцатеричные значения для кнопок данного пульта приведены на следующем рисунке.
Как вы можете видеть, шестнадцатеричные значения для кнопок данного пульта содержат 7 цифр, из которых только последние 2 полностью различаются. Поэтому для различения кнопок данного пульта мы можем использовать только 2 последние цифры шестнадцатеричных значений как показано на следующем рисунке.
Схема проекта
Схема проекта автоматизации дома на микроконтроллере PIC с управлением по инфракрасной связи представлена на следующем рисунке.
Внешний вид собранной конструкции проекта приведен на следующем рисунке.
Объяснение программы для микроконтроллера PIC
Полный текст программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты. Программа для данного проекта была написана с помощью MPLABX, более подробно про работу с данным программным обеспечением вы можете прочитать в этой статье.
Первым делом в коде программы мы подключим используемые библиотеки и объявим используемые контакты и переменные.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <xc.h> #include<string.h> #include<stdlib.h> #include "config.h" #define tric RB1 #define ir RB2 #define relay1 RC2 #define relay2 RC3 #define relay3 RC4 #define relay4 RC5 #define rly1LED RB3 #define rly2LED RB4 #define rly3LED RB5 #define rly4LED RC1 #define fanLED RC0 int flag=0; int cmd=0; int speed=5; unsigned int dat[100]; int i=0; char result[10]; int j=0; |
После этого мы запрограммируем функцию задержки в программе с помощью цикла “for”.
1 2 3 4 5 |
void delay(int time) { for(int i=0;i<time;i++) for(int j=0;j<800;j++); } |
Затем запрограммируем функцию инициализации таймера. Более подробно про использование таймеров в микроконтроллерах PIC вы можете прочитать в данной статье.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void timer() // 10 -> 1us { T0PS0=0; T0PS1=0; T0PS2=0; PSA=0; //Timer Clock Source is from Prescaler T0CS=0; //Prescaler gets clock from FCPU (5MHz) T08BIT=0; //16 BIT MODE TMR0IE=1; //Enable TIMER0 Interrupt PEIE=1; //Enable Peripheral Interrupt GIE=1; //Enable INTs globally TMR0ON=1; //Now start the timer! } |
Далее, в функции main, мы зададим режимы работы для используемых контактов (на ввод или вывод данных), инициализируем таймер и настроим обработку внешнего прерывания int0 для обнаружения моментов перехода сигнала переменного тока через 0.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
ADCON1=0b00001111; TRISB1=0; TRISB2=1; TRISB3=0; TRISB4=0; TRISB5=0; TRISC=0x00; TRISA=0x00; PORTA=0xc0; TRISB6=0; RB6=1; relay1=0; relay2=0; relay3=0; relay4=0; rly1LED=0; rly3LED=0; rly2LED=0; rly4LED=0; fanLED=0; i=0; ir=0; tric=0; timer(); INTEDG0 = 0; // Interrupt on falling edge INT0IE = 1; // Enable the INT0 external interrupt (RB0) INT0IF = 0; // Clears INT0 External Interrupt Flag bit PEIE=1; //Enable Peripheral Interrupt GIE=1; //Enable INTs globally |
Мы не будем использовать каких либо прерываний для обнаружения инфракрасного сигнала. Для этого мы будем использовать обычный цифровой контакт, также, как если бы мы считывали состояние обычной кнопки. Всегда когда сигнал будет становиться high или low мы после задержки для устранения дребезга контактов (debouncing method) будем запускать таймер. Всегда когда контакт будет изменять свое состояние на противоположное значение времени будет сохраняться в массив.
Инфракрасный пульт ДУ передает логический 0 сигналом длительностью 562.5us, а логическую 1 – сигналом длительностью 2250us. Всегда когда с помощью таймера мы будем считывать 562.5us мы будем считать что это 0, а когда будем считывать 2250us – мы будем считать что это 1. Затем мы будем конвертировать это значение в шестнадцатеричный формат.
Сигнал с пульта ДУ содержит 34 бита. Мы будем сохранять все принятые байты от пульта ДУ в массив и затем декодировать для использования последние 2 бита.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
while(ir == 1); INT0IE = 0; while(ir == 0); TMR0=0; while(ir == 1); i++; dat[i]=TMR0; if(dat[1] > 5000 && dat[1]<12000) { } else { i=0; INT0IE = 1; } if(i>=33) { GIE=0; delay(50); cmd=0; for(j=26;j<34;j++) { if(dat[j]>1000 && dat[j]<2000) cmd<<=1; else if(dat[j]>3500 && dat[j]<4500) { cmd|=0x01; cmd<<=1; } } cmd>>=1; |
В следующем фрагменте кода мы будем принимать и декодировать инфракрасный сигнал с помощью прерывания от таймера и сохранять полученное шестнадцатеричное значение в переменной cmd. После этого мы сможем сравнить значение переменной cmd с шестнадцатеричными значениями в нашей программе и на основе результатов сравнения включить/выключить соответствующее реле.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
if(cmd == 0xAF) { relay1=~relay1; rly1LED=~rly1LED; } else if(cmd == 0x27) { relay2=~relay2; rly2LED=~rly2LED; } else if(cmd == 0x07) { relay3=~relay3; rly3LED=~rly3LED; } else if(cmd == 0xCF) { relay4=~relay4; rly4LED=~rly4LED; } else if(cmd == 0x5f) { speed++; if(speed>5) { speed=5; } } else if(cmd == 0x9f) { speed--; if(speed<=0) { speed=0; } } |
Скорость, с которой вращается наш вентилятор, будет отображаться на семисегментном индикаторе. Эти операции запрограммированы в следующих строках кода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
if(speed == 5) // turned off 5x2= 10ms triger //speed 0 { PORTA=0xC0; // display 0 RB6=1; fanLED=0; } else if(speed == 4 ) // 8 ms trigger //speed 1 { PORTA=0xfc; // displaying 1 RB6=1; fanLED=1; } else if(speed == 3) // 6 ms trigger // speed 2 { PORTA=0xE4; // displaying 2 RB6=0; fanLED=1; } else if(speed == 2) // 4ms trigger // speed 3 { PORTA=0xF0; // displaying 3 RB6=0; fanLED=1; } else if(speed == 1) // 2ms trigger // speed 4 { PORTA=0xD9; // displaying 4 RB6=0; fanLED=1; } else if(speed == 0) // 0ms trigger // speed 5 full power { PORTA=0xD2; // displaying 5 RB6=0; fanLED=1; } |
Также запрограммируем функцию для обработки внешнего прерывания (по нему будут определяться моменты перехода сигнала через 0 для управления симистором) и прерывания от таймера.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void interrupt isr() { if(INT0IF) { delay(speed); tric=1; for(int t=0;t<100;t++); tric=0; INT0IF=0; } if(TMR0IF) //Check if it is TMR0 Overflow ISR { TMR0IF=0; } } |
Разработка печатной платы для проекта
Для разработки схемы проекта его автор использовал редактор EasyEDA, который также позволяет производить разработку дизайна печатной платы. Из этого редактора можно также и заказать изготовление спроектированной печатной платы.
На следующих рисунках показаны скриншоты спроектированной в EasyEDA печатной платы для нашего проекта автоматизации дома на основе микроконтроллера PIC.
Заказ изготовления печатной платы
После завершения разработки дизайна печатной платы в редакторе EasyEDA вы можете заказать ее изготовление, нажав на иконку Fabrication output. После этого откроется страница, на который вы можете загрузить Gerber файлы для изготовления вашей печатной платы, также эти Gerber файлы вы можете использовать для изготовления печатной платы у любого другого производителя (не обязательно у того, которого вам предлагает EasyEDA).
На открывшейся странице заказа изготовления печатной платы вам необходимо требуемое количество экземпляров печатной платы, ее толщину, цвет и другие параметры. После того как вы все это введете, нажмите на кнопку “Save to Cart” и завершите свой заказ, после этого вы в течение нескольких дней получите изготовленную печатную плату.
Скачать Gerber файлы печатной платы для нашего проекта автоматизации дома вы можете скачать по этой ссылке.
Спустя несколько дней после заказа изготовления печатной платы авторы проекта получили ее в готовом виде. Ее внешний вид показан на следующих рисунках.
После этого они припаяли на нее необходимые компоненты и получили следующую готовую конструкцию проекта.
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
#include <xc.h> #include<string.h> #include<stdlib.h> #include "config.h" #define tric RB1 #define ir RB2 #define relay1 RC2 #define relay2 RC3 #define relay3 RC4 #define relay4 RC5 #define rly1LED RB3 #define rly2LED RB4 #define rly3LED RB5 #define rly4LED RC1 #define fanLED RC0 int flag=0; int cmd=0; int speed=5; unsigned int dat[100]; int i=0; char result[10]; int j=0; void delay(int time) { for(int i=0;i<time;i++) for(int j=0;j<800;j++); } void timer() // 10 -> 1us { T0PS0=0; T0PS1=0; T0PS2=0; PSA=0; //Timer Clock Source is from Prescaler T0CS=0; //Prescaler gets clock from FCPU (5MHz) T08BIT=0; //16 битный режим TMR0IE=1; //разрешаем прерывание от TIMER0 PEIE=1; //разрешаем прерывания от периферийных устройств GIE=1; // глобальное разрешение прерываний TMR0ON=1; // запускаем таймер в работу } void main(void) { ADCON1=0b00001111; TRISB1=0; TRISB2=1; TRISB3=0; TRISB4=0; TRISB5=0; TRISC=0x00; TRISA=0x00; PORTA=0xc0; TRISB6=0; RB6=1; relay1=0; relay2=0; relay3=0; relay4=0; rly1LED=0; rly3LED=0; rly2LED=0; rly4LED=0; fanLED=0; i=0; ir=0; tric=0; timer(); INTEDG0 = 0; // Interrupt on falling edge (прерывание по спадающему фронту) INT0IE = 1; // разрешаем внешнее прерывание INT0 (RB0) INT0IF = 0; // очищаем флаг внешнего прерывания INT0 PEIE=1; // разрешаем прерывания от периферийных устройств GIE=1; // глобальное разрешение прерываний while(1) { while(ir == 1); INT0IE = 0; while(ir == 0); TMR0=0; while(ir == 1); i++; dat[i]=TMR0; if(dat[1] > 5000 && dat[1]<12000) { } else { i=0; INT0IE = 1; } if(i>=33) { GIE=0; delay(50); cmd=0; for(j=26;j<34;j++) { if(dat[j]>1000 && dat[j]<2000) cmd<<=1; else if(dat[j]>3500 && dat[j]<4500) { cmd|=0x01; cmd<<=1; } } cmd>>=1; if(cmd == 0xAF) { relay1=~relay1; rly1LED=~rly1LED; } else if(cmd == 0x27) { relay2=~relay2; rly2LED=~rly2LED; } else if(cmd == 0x07) { relay3=~relay3; rly3LED=~rly3LED; } else if(cmd == 0xCF) { relay4=~relay4; rly4LED=~rly4LED; } else if(cmd == 0x5f) { speed++; if(speed>5) { speed=5; } } else if(cmd == 0x9f) { speed--; if(speed<=0) { speed=0; } } if(speed == 5) // turned off 5x2= 10ms triger //speed 0 { PORTA=0xC0; // отображаем 0 на семисегментном индикаторе RB6=1; fanLED=0; } else if(speed == 4 ) // 8 ms trigger //speed 1 { PORTA=0xfc; // отображаем 1 на семисегментном индикаторе RB6=1; fanLED=1; } else if(speed == 3) // 6 ms trigger // speed 2 { PORTA=0xE4; // отображаем 2 на семисегментном индикаторе RB6=0; fanLED=1; } else if(speed == 2) // 4ms trigger // speed 3 { PORTA=0xF0; // отображаем 3 на семисегментном индикаторе RB6=0; fanLED=1; } else if(speed == 1) // 2ms trigger // speed 4 { PORTA=0xD9; // отображаем 4 на семисегментном индикаторе RB6=0; fanLED=1; } else if(speed == 0) // 0ms trigger // speed 5 full power { PORTA=0xD2; // отображаем 5 на семисегментном индикаторе RB6=0; fanLED=1; } else { RB6=1; PORTA=0xff; // display off fanLED=0; } i=0; INT0IE = 1; GIE=1; } } } void interrupt isr() { if(INT0IF) { delay(speed); tric=1; for(int t=0;t<100;t++); tric=0; INT0IF=0; } if(TMR0IF) //Check if it is TMR0 Overflow ISR { TMR0IF=0; } } |