Advertisement
Guest User

Power_switch

a guest
May 16th, 2015
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.01 KB | None | 0 0
  1. #include <EEPROM.h>              // библиотека для сохранения рег.данных пультов в энергонезависимой памяти
  2. #include <RCSwitch.h>            // библиотека для декодирования сигнала с пульта
  3.  
  4. #define Input 0                  // вход с приёмника радиосигнала, обязательно на INT0 (0) PD2 или INT1 (1) PD3
  5.  
  6. #define Ch_0 B00111000           // соответствие всех каналов для управления нагрузкой (здесь тоже нужно правильно указать выводы порта)
  7. #define Ch_1 B00001000           // соответствие канала для управления нагрузкой выводу Arduino (3) PD3
  8. #define Ch_2 B00010000           // соответствие канала для управления нагрузкой выводу Arduino (4) PD4
  9. #define Ch_3 B00100000           // соответствие канала для управления нагрузкой выводу Arduino (5) PD5
  10. //#define Ch_4 B01000000         // соответствие канала для управления нагрузкой выводу Arduino (6) PD6
  11.  
  12. #define prg_mode 0xFF            // код для входа в режим программирования дополнительных функций
  13.  
  14. unsigned long old_time = 0;      // переменная для регистрации времени
  15. byte count_time = 0;             // переменная для подсчёта времени удержания нажатой кнопки
  16. byte pad_number = 0;             // номер текущего пульта
  17.  
  18. RCSwitch mySwitch = RCSwitch();  // радиоприёмник, как "объект" mySwitch
  19.  
  20.  
  21. //------------------------------ декодирование радио-посылки -------------------
  22. byte Code_Decode() {
  23.  
  24.   unsigned long  code = mySwitch.getReceivedValue(); //принимаем всю посылку 24 бита.
  25.   unsigned int address = code >> 8;                  // удаляем 8 бит кода кнопки оставляем 16 бит адрес пульта.
  26.   byte Button = code & 0xFF;                         // выделяем из полной посылки только код кнопки.
  27.  
  28.   if (Verify_Remote (address)) {                     // проверяем пульт по базе известных пультов.
  29.     mySwitch.resetAvailable();                       // сброс буфера приёмника
  30.     return Button;                                   // если пульт зарегистрирован в базе, то возвращаем код нажатой кнопки.
  31.   }
  32.   // если пульт не зарегистрирован, то
  33.   New_Remote(address);                               // вызываем подпрограмму регистрации нового пульта.
  34.   return 0;                                          // возвращаем значение кнопки 0x0 (HEX)
  35. }
  36.  
  37. // ---------------- регистрация нового пульта ---------------------------
  38. void New_Remote(unsigned int addr) {
  39.  
  40.   if (count_time == 0 ) {
  41.     old_time = millis();                                             // старт процесса регистрации. Фиксируем время для выполнения процедуры
  42.   }
  43.   count_time++;                                                      // при каждом нажатии кнопки незарегистрированного пульта увеличиваем счётчик
  44.   if ((count_time > 20) && ((millis() - old_time) < 20000) ) {       // если кнопка нажата более 20 раз в течении 20 секунд, то
  45.     for (byte x = 0; x < 6; x++) {                                   // подаём сигнал о начале программирования каналов
  46.       PORTD |= Ch_0;  // три раза мигают все каналы
  47.       delay(300);                                                    // с интервалом 0.3 секунды
  48.       PORTD &= ~Ch_0; // выключаем все каналы
  49.       delay(300);
  50.     }
  51.     delay(1000);                                                     // пауза 1 сек, чтобы успеть отпустить кнопку
  52.  
  53.     // программирование соответствия каналов кнопкам
  54.  
  55.     for (byte x = 0; x <= 3; x++) {                                  // можно изменить количество программируемых каналов (сейчас 3)
  56.       Ch_control (x);                                                // включаем программируемый канал
  57.       old_time = 1;
  58.       mySwitch.resetAvailable();                                     // сброс буфера приёмника
  59.       while (old_time != 0) {
  60.         if (mySwitch.available()) {                                  // если что-то появилось в буфере приёмника,то
  61.           EEPROM.write(EEPROM.read(0) * 16 + 3 + x, (mySwitch.getReceivedValue() & 0xFF)); // принимаем всю посылку 24 бита, выделяем из полной посылки только код кнопки.
  62.           Ch_control (x);
  63.           delay(500);                                                 // гасим программируемый канал на 0.5 секунды
  64.           Ch_control (x);
  65.           delay(200);
  66.           Ch_control (x);
  67.           delay(200);                                                 // подтверждающее мигание
  68.           Ch_control (x);
  69.           delay(200);
  70.           Ch_control (x);
  71.           old_time = 0;                                               // выходим из бесконечного цикла
  72.         }
  73.       }
  74.       delay(500);                                                     // задержка перед программированием следующего канала
  75.     }
  76.  
  77.     EEPROM.write((EEPROM.read(0) * 16 + 1), (addr & 0xFF));            // записываем в EEPROM младший байт адреса нового пульта
  78.     EEPROM.write((EEPROM.read(0) * 16 + 2), (addr >> 8));              // записываем в EEPROM старший байт адреса нового пульта
  79.     EEPROM.write(0, (EEPROM.read(0) + 1));
  80.     old_time = millis();                                               // сбрасываем время ожидания удержания кнопки неизвестного пульта.
  81.     count_time = 0;                                                    // сбрасываем счётчик удержания кнопки неизвестного пульта.
  82.   }
  83.  
  84.   else if ((count_time < 20) && ((millis() - old_time) > 20000)) {     // если прошло 20 секунд и не выполнено условие нажатия кнопок нового пульта, то
  85.     old_time = millis();                                               // сбрасываем время ожидания удержания кнопки неизвестного пульта.
  86.     count_time = 0;                                                    // сбрасываем счётчик удержания кнопки неизвестного пульта.
  87.     mySwitch.resetAvailable();                                         // сброс буфера приёмника
  88.     return;                                                            // возвращаемся к обычному режиму работы
  89.   }
  90.   mySwitch.resetAvailable();                                           // сброс буфера приёмника
  91.   return;
  92. }
  93.  
  94. // ----------------- проверка номера пульта по базе данных известных пультов ------------
  95.  
  96. boolean Verify_Remote (unsigned int address) {                         // проверка номера пульта по базе данных известных пультов
  97.  
  98.   pad_number =  EEPROM.read(0);                                        // в нулевой ячейке храним количество запрограммированных пультов.
  99.   for (byte i = 0; i <= pad_number; i++) {                             // все зарегистрированные пульты
  100.     unsigned int addr = (EEPROM.read(16 * i + 2) << 8) + EEPROM.read(16 * i + 1); // читаем младший байт первым, читаем старший байт адреса пульта, получаем адрес пульта
  101.     if (address == addr) {                                             // проверяем все известные пульты на совпадение
  102.       pad_number = i;                                                  // при совпадении, устанавливаем глобальную переменную "текущий пульт"
  103.       return 1;                                                        // если нашли совпадение, возвращаем TRUE
  104.     }
  105.   }
  106.   return 0;                                                            // если не нашли совпадений возвращаем FALSE
  107. }
  108.  
  109. // ----------------- при вызове функции инвертируется состояние управляемого канала -------------
  110.  
  111. void Ch_control (byte Ch) {                                         // использование этой функции заманчиво, но может быть оптимальнее от неё отказаться
  112.  
  113.   // попробуем вариант с инверсией каналов
  114.   if      (Ch == 0 && (PIND & Ch_0) != 0)  PORTD &= ~Ch_0;          // если хотя бы один канал включен, выключаем все каналы
  115.   else if (Ch == 0 && (PIND & Ch_0) == 0)  PORTD |= Ch_0;           // если ничего не было включено, то выключаем все каналы
  116.  
  117.   else if (Ch == 1) PORTD ^= Ch_1;                                  // инвертируем состояние канала номер 1
  118.   else if (Ch == 2) PORTD ^= Ch_2;                                  // инвертируем состояние канала номер 2
  119.   else if (Ch == 3) PORTD ^= Ch_3;                                  // инвертируем состояние канала номер 3
  120.  // else if (Ch == 4) PORTD ^= Ch_4;                                  // инвертируем состояние канала номер 4
  121.  
  122.   return;
  123. }
  124.  
  125. //------------- программирование дополнительных функций  ------------------
  126. void Programm_mode() {                                               // режим программирования дополнительных функций устройства
  127.  
  128.   boolean F_erase = 1;                                               // устанавливаем флаг готовности к удалению информации в EEPROM.
  129.   byte erase_time = 50;                                              // устанавливаем счётчик для  выхода из этого режима
  130.   while (erase_time != 0) {                                          // до тех пор, пока он не станет равным "0"
  131.     mySwitch.resetAvailable();                                       // очищаем буфер приемника
  132.     if (mySwitch.available()) {                                      // читаем коды кнопок
  133.       byte prg = Code_Decode();                                      // отправляем посылку на расшифровку, получаем код следующей команды
  134.  
  135.  
  136.       if (prg == prg_mode) {                                         // если код кнопки "0xFF", то продолжаем
  137.         Ch_control(0);                                               // при каждом получении команды переключаем состояние всех каналов
  138.         erase_time--;                                                // обратный отсчёт до обнуления памяти
  139.         delay(100);
  140.       }
  141.       // -------------- блок программирования одной функции ----------------
  142.       else if (prg == 0x03) {                                        // если код кнопки не "0xFF",  0x03 - "все каналы
  143.         F_erase = 0;                                                 // то сразу отменяем процедуру очищения памяти и переходим в режим программирования.
  144.         mySwitch.resetAvailable();                                   // очищаем буфер приемника
  145.         while (1) {                                                  // бесконечный цикл ожидания кнопки канала, включенного при подаче питания
  146.           for (byte x = 3; x < 7; x++) {                             // управляющие биты каналов. Мигаем "бегущий огонь" (забавно будет на одноканальном устройстве :-))
  147.             PORTD &= ~B01111000;
  148.             PORTD |= (1 << x);                                       // просто мигаем каналами для красоты режима программирования
  149.             delay(300);
  150.           }
  151.  
  152.           if (mySwitch.available()) {                                // читаем коды кнопок
  153.             byte prg = Code_Decode();                                // отправляем посылку на расшифровку, получаем код следующей команды
  154.  
  155.             for (byte i = 1 ; i < 5; i++) {                          // перебираем все соответствия для текущего пульта. Может быть одна команда для нескольких каналов
  156.               if (prg == EEPROM.read(3 + i + pad_number * 16)) {     // Ячейки 250 - 254 определяют начальное состояние после подачи питания. Состояние меняется на противоположное.
  157.                 if (EEPROM.read(250 + i)) EEPROM.write(250 + i, 0);  // если ячейка не пустая, то пишем в неё "0"
  158.                 else if (!EEPROM.read(250 + i)) EEPROM.write(250 + i, 0xFF); // если пустая, то пишем туда "0xFF"
  159.                 PORTD &= ~Ch_0;                                      // выключаем все каналы
  160.                 for (byte x = 0; x < 10; x++) {                      // подаём сигнал о окончании программирования канала. 5 раз мигает  канал
  161.                   Ch_control(i);
  162.                   delay(100);                                        // с интервалом 0.1 секунды
  163.                 }
  164.                 PORTD &= ~Ch_0;                                      // выключаем все каналы
  165.                 return;
  166.               }
  167.             }
  168.           }
  169.         } // бесконечный цикл  ожидания кнопки
  170.  
  171.       } // конец блока программирования одной функции , можно далее делать следующий блок.
  172.  
  173.     } // mySwitch.available
  174.  
  175.   } //while
  176.  
  177.   if (F_erase == 1) {
  178.     delay(2000);
  179.     EEPROM.write(0, 0);                                               // устанавливаем число зарегистрированных пультов равным "0" в нулевой ячейке заполняем всю остальную EEPROM символом "FF"
  180.     for (byte x = 1; x < 250; x++) EEPROM.write(x, 0xFF);             // затираем данные всех пультов, оставляя без изменения "состояние каналов при инициализации".
  181.  
  182.     for (byte x = 0; x < 10; x++) {                                   // подаём сигнал о окончании программирования канала. 5 раз мигает  канал
  183.       Ch_control(0);
  184.       delay(100);                                                     // с интервалом 0.1 секунды
  185.     }
  186.     PORTD &= ~Ch_0;                                                   // выключаем все каналы
  187.     return;
  188.   }
  189.   return;
  190. }
  191.  
  192.  
  193. //----------------------------------- начальная инициализация системы ----------------------------
  194. void setup() {
  195.  
  196.   mySwitch.enableReceive(Input);
  197.   if (EEPROM.read(0) == 255)  {
  198.     EEPROM.write(0, 0);                                              // первоначальная инициализация новой микросхемы. Выполняется всего 1 раз (или при наполнении до 15 пультов)
  199.     EEPROM.write(250, 0);
  200.     EEPROM.write(251, 0);
  201.     EEPROM.write(252, 0);                                            // Ячейки 250 - 254 определяют начальное состояние после подачи питания.
  202.     EEPROM.write(253, 0);
  203.     EEPROM.write(254, 0);                                            // 0 - выключено , 0xFF -включено.
  204.   }
  205.   DDRD |= Ch_0;                                                      // устанавливаем все выводы в режим "выход"
  206.  
  207.   if (EEPROM.read(0) == 0 ) {                                        // если не запрограммировано ни одного пульта
  208.     PORTD |= Ch_0;                                                   // включаем все каналы для проверки работоспособности при начальной инициализации,
  209.     delay(1000);
  210.   }
  211.   PORTD &= ~Ch_0;                                                    // выключаем все каналы
  212.  
  213.   PORTD |= Ch_1 & EEPROM.read(251);                                  // в ячейке 251 - 254 храним первоначальное состояние каждого канала
  214.   PORTD |= Ch_2 & EEPROM.read(252);
  215.   PORTD |= Ch_3 & EEPROM.read(253);
  216.  // PORTD |= Ch_4 & EEPROM.read(254);
  217.  
  218.  
  219.  
  220. }
  221. //------------------------------------------------------------------------------------------------
  222. void loop() {
  223.  
  224.   if (mySwitch.available()) {                                 // если с пульта принята какая-либо команда
  225.     byte Button = Code_Decode();                              // расшифровываем её и получаем код нажатой кнопки
  226.     if (Button == 0xC3) {                                     // если нажата комбинация С3 (HEX), то
  227.       byte cur_Ch = PIND & 0x78;                              // считываем, какой канал сейчас включен
  228.       if (cur_Ch != 0) {                                      // если любой канал включен, то
  229.         count_time = 1;                                       // деактивируется флаг таймера автовыключения до перезагрузки МК
  230.         PORTD ^= cur_Ch;                                      // подтверждающее мигание текущими каналами
  231.         delay(200);
  232.         PORTD |= cur_Ch;                                      // возвращаем обратно работавший канал
  233.         delay(300);
  234.         PORTD ^= cur_Ch;                                      // подтверждающее мигание текущими каналами
  235.         delay(200);
  236.         PORTD |= cur_Ch;                                      // возвращаем обратно работавший канал
  237.       }
  238.     }
  239.     if (Button == prg_mode) Programm_mode();                  // если нажата комбинация 0xFF (HEX) (все кнопки сразу) переходим в режим программирования доп.возможностей.
  240.  
  241.     for (byte i = 0 ; i < 5; i++) {                           // начинаем проверять принятую команду на соответствие сопоставленному каналу управления (ячейки с 8 по 18 резерв)
  242.       if (Button == EEPROM.read(3 + i + pad_number * 16)) {   // перебираем все соответствия для текущего пульта. Может быть одна команда для нескольких каналов
  243.         Ch_control (i);                                       // если любая комбинация каналов включена, то все выключить.
  244.         old_time = millis();                                  // фиксируем время, когда был включен или выключен канал
  245.       }
  246.     }
  247.     delay(300);                                               // задержка между повторными нажатиями кнопки пульта
  248.     mySwitch.resetAvailable();                                // сброс буфера приёмника
  249.   }
  250.   if (((PIND & Ch_0) != 0) && (millis() - old_time > 1800000) && (count_time == 0)) {
  251.     // если какой-либо из каналов включен, и функция автовыключения не деактивирована, то через 30 минут все каналы отключатся.
  252.     PORTD &= ~Ch_0;                                           // выключаем все каналы сразу. При нажатии любой кнопки таймер 30 минут начинает отсчёт снова.
  253.   }
  254. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement