Умный дом

Отладка модуля

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

If (!(RB3&0x0D) {

PHOTOCOME = 1; RAO = 0x01;

}

Else

{

PHOTOCOME = 0; RAO = 0x00;

}

Вот и очередные «грабли»!

Приоритет приема ИК-команд хорошо бы закрепить одно­значно. Например, так: {

While((1RCIF)&(RB3 == 1))

/* устанавливается, когда регистр не пуст */ continue; return RCREG;

}

Я выделил добавленный фрагмент. У прототипа фотопри­емник подключен к выводу RB3. Смысл добавленного фраг­мента в том, что на сетевые запросы ответ будет, если модуль не занят приемом ИК-команд, то есть RB3 = 1.

Неплохо было бы защитить модуль от помех по RB3. При включении может «проскочить» короткий нулевой импульс (на чем я и споткнулся), и модуль перейдет в режим приема ИК-команды, которой нет. Поправил я это так:

Start: if (RB3&0x01) // Нет ИК сигнала. {

PHOTOCOME = 0;

RAO = 0x00;

Break;

}

If (! (RB3&0x01)) // Появился ИК сигнал.

{

For (k=0; k<30; ++k); // Поставим задержку.

If (! (RB3&0x01)) // ИК сигнал не пропал?

{

PHOTOCOME = 1;

RAO = 0x01;

}

} else

{

PHOTOCOME = 0;

RAO = 0x00;

Break;

}

Я добавляю задержку, а затем еще раз проверяю наличие активности фотоприемника. Короткий случайный импульс проскочит за время задержки, а длинный импульс команды приведет механизм считывания в действие. Помогло. Если в первый раз после включения питания (сразу или через не­сколько секунд) модуль «подвисал» на приеме ИК-команды, то после исправления перестал.

Итак, модуль получает команду. Возможно, распознает ее. Он даже передает ее по запросу через RS485. А что получит­ся, если команда не единичная, то есть в том случае, когда идет поток одинаковых команд? Что будет, если команды не системные, а чужие? Не знаю.

Первое, что приходит в голову - запустить еще один тай­мер сразу после завершения считывания ИК-команды. И пока он не завершит отсчет времени больший, чем занимают 2-3 команды, не принимать ИК-коды. Попутно я пытаюсь воспро­извести код, аналогичный тому, что использовал в отладчи­ке MPLAB, из программы WinLIRC, аппаратный модуль ко­торой имеет излучающий светодиод.

Проходит два дня. Результаты не впечатляют. Коды про­читываются не слишком уверено. Я увеличиваю интервал сканирования с 600 до 700 мкс, но совсем не удовлетворен стабильностью работы модуля. В отличие от релейного, мо­дуль приема системных ИК-команд мне совсем не нравится. Он, вроде бы, работает, но...

В конечном счете, я меняю излучатель кодов. Использую оригинал - старый пульт от видеомагнитофона Sony. Меняю второй таймер на обычный цикл в команде считывания ко­дов (выделено в тексте программы), попутно решаю внести исправления в сдвиг на один бит. У меня получился лишний сдвиг, который я после получения ИК-команды убирал обрат­ным сдвигом. После замены переменной IRCOMMAND с типа int на unsigned char я стал терять старший бит..

Замена всех этих «шатаний из стороны в сторону» оказа­лась простой (изменение выделено). Если я не ошибаюсь, это­го достаточно.

Int ir_cmd О {

Int b = 0;

While (RB3 == 0) continue; // Ждем окончания заголовка.

For (b=0; b<8; b++) //Обработаем наши импульсы.

{

While (RB3 1= 0)

Continue; // Дождемся импульса,

Time (); // Включаем таймер 1. while (1TMR1IF); // Дождемся сброса таймера. T1C0N = 0x0; // Выключаем таймер. TMR1IF = 0x0; // Сбросим флаг.

If (RB3 ==0) // Если низкий уровень, то "1". {

IRCOMMAND = IRCOMMAND +1; // Запишем это. time (); // Включаем таймер 1.

While (ITMR1IF); // Дождемся сброса таймера. T1CON = 0x0; // Выключаем таймер. TMR1IF = 0x0; // Сбросим флаг. } else // Высокий уровень, значит И0И.

IRCOMMAND = IRCOMMAND; // Запишем это.

If (b<7) IRCOMMAND = IRCOMMAND«l; //Сместимся влево

На бит.

}

PHOTOCOME = 0x0;

RA0 = 0x0; RAl=0xl;

For (ш=0; m<3; ++ш) // Перестанем щзинимать ИК-ходы.

For (1=0; 1<10000; ++1); RA1 = 0x0;

}

Здесь на выводе порта A RA1 я использую еще один свето - диод, чтобы видеть окончание команды.

В результате модуль хорошо распознает команды от пуль­та видеомагнитофона. Чувствительность высокая, распозна­вание стабильное (рис. 1.51).

Отладка модуля

Рис. 1.51. Прием ИК-кодов модулем

Не удовлетворяют меня только два момента:

• иногда во время паузы между приемами ИК-команд зап­рос по сети «подвешивает» модуль в нераспознанном месте (помогло сокращение времени этой паузы);

• коды с пульта плохо согласуются с моими ожиданиями.

Вот сравнение кодов, прочитанных с помощью WinLIRC в режиме распознавания, и кодов, которые транслирует мо­дуль в ответ на запрос по сети RS485:

Номер канала 1.

Модуль возвращает номер команды 001 - 00000001 (С14001 - в ответ на запрос статуса).

7F2h - 11111110010 (инверсия 00000001101), без послед­них трех бит 0000001.

. Номер канала 2.

Прочитано модулем 129 - 10000001

3F2h - 01111110010 (инверсия 10000001101), без послед­них трех бит 10000001.

Номер канала 3.

Прочитано модулем 65 - 1000001

5F2h - 10111110010 (инверсия 01000001101), без послед­них трех бит 1000001

Номер канала 6.

Прочитано модулем 161 - 10100001

2F2h - 01011110010 (инверсия 10100001101), без послед­них трех бит 10100001.

Номер канала 9.

Прочитано модулем 017 - 10001

772h - 11101110010 (инверсия 00010001101), без послед­них трех бит 00010001.

Power.

Прочитано модулем169 -10101001

2B2h - 1010110010 (инверсия 0101001101), без последних трех бит 0101001.

Команда включения канала 1 в записи WinLIRC - 7F2h, но я определяю единицу и ноль, как это описано в технической информации о кодах Sony, которой располагаю, а в WinLIRC сделано наоборот. Можно инвертировать код. Кроме того, я использую 8-битовый код, а оригинальный код - 11-битовый. Тоже не страшно, отбросим три последних бита. Смущающим меня обстоятельством служит то, что команды каналов 1 и 2 не совпадают, как я ожидал после превращений с инверсией и отбрасыванием. Аналогичная история с командой power. Пока я не понимаю, как это происходит.

Шутка калькулятора, который отбрасывает первые нули! Но понял я это позже.

Последнее, что я делаю, измученный борьбой с «собствен­ной гениальностью», - проверяю работу модуля в заготовке под среду программирования. Модуль работает. Я использую два кода: номер включения канала 1 - для тестирования ко­манды, а канала 2 - для включения лампы. Оба кода стабиль­но работают.

Думаю, пока следует остановиться. Основная задача - получить модуль считывания системных команд, которые стабильно распознавались бы системой, достигнута. При этом, как это и планировалось, используется старенький пульт от видеомагнитофона. А если что-то осталось непо­нятно, что ж... Будем надеяться, что это позже прояснит­ся (рис. 1.52).

Отладка модуля

Рис. 1.52. Работа модуля с основной программой

Самым непонятным для меня оказалось то, что попытка ис­пользовать третий светодиод для индикации включенного мо­дуля - я несколько раз вытаскивал микросхему из панельки без отключения питающего напряжения - успехом не увенча­лась. Я попробовал разные варианты включения. Ничего не получилось! Мистика!?

В данный момент программа модуля приема системных кодов получилась такой. Файл заголовка:

#define MODULNAMESIM ИСИ

Unsigned char getch(void); •

Int init_canms () ;

Int ir_cmd ();

Int and ();

Void time ();

Void time_cmd();

Int ir_stat ();

Файл основной программы:

// Считываем содержимое приемного

// Первый символ адреса модуля. // Второй символ адреса модуля.

#include <picl6f62xa. h> #include <stdio. h> #include "ir_rec_01.h"

Unsigned char input; регистра.

Unsigned char M0DJSIM1; unsigned char M0D_SIM2; unsigned char IRSIM1; unsigned char IRSIM2; unsigned char IRSIM3;

Unsigned char command_reciev [6]; // Массив для полученной команды.

Int PHOTOCOME =0; // Флаг активности фотоприемника.

Int MOD_ADDR; // Заданный адрес модуля, как число.

Unsigned char IRCOMMAND = 0;

Int siml_num = 0;

Int sim2_num = 0;

Int sim_end_num = 0;

Int MOD_NUM; // Полученный адрес модуля, как число.

Int і int k int 1 int m

Unsigned char getch() {

While((!RCIF)&(RB3 == 1)

Continue; return RCREG;

}

// Когда регистр не пуст.

// Вывод одного байта

// Когда регистр пуст.

Void putch(unsigned char byte) {

While(ITXIF) continue; TXREG = byte;

}

Int init_comms () {

PORTA = 0x00; CMCON = 0x7; TRISA = 0x00; TRISB = OxFE; PCON = OxFF; RCSTA = OblOOlOOOO; TXSTA = ObOOOOOllO; SPBRG = 0x68; N,8,1.

INTCON = 0x0; RB0 = 0x0; PIE1 = 0x0; T1CON = 0x0; ноль.

TMR1H = 0x00; TMR1L = 0x00; IRCOMMAND = 0x0; MOD_jADDR = PORTB;

MOD_ADDR=MOD__ADDR»4 ; }

// Инициализация модуля.

// Настройка портов А и В.

Тактовая частота 4 МГц. // Настройка приемника. // Настройка передатчика. //Настройка режима приема-передачи 2400,

// Запретить прерывания.

Выключим передатчик драйвера RS485.

Настройка таймера 1, запрет прерывания.

//

И //

II Выбор внутреннего генератора, бит 1 в

// Обнулим таймер.

/* Определим номер модуля */ // Номер модуля в старших битах. // Сдвинем на четыре бита.

// Преобразуем символьный адрес в число, int sim_num_adr()

{

Sim_end_num = 0x0; M0D_SIM1 = command_reciev [1]; M0DJSIM2 = command_reciev [2]; M0D_SIM1 = M0DJSIM1 - 0x30; MOD_SIM2 = MOD_SIM2 - 0x30; sim_end_num = MOD_SIMl*OxOA + MOD return sim_end_num;

}

Int ir_cmd () {

Int b = 0;

While (RB3 == 0) continue; // Ждем окончания заголовка.

For (b=0; b<8; b++) //Обработаем наши импульсы.

{

While (RB3 != 0)

Continue; // Дождемся импульса,

Time (); // Включаем таймер 1. while (1TMR1IF); // Дождемся сброса таймера. T1CON = 0x0; // Выключаем таймер. TMR1IF = 0x0; // Сбросим флаг.

If (RB3 == 0) // Если низкий уровень, то "І". {

IRCOMMAND = IRCOMMAND +1; // Запишем это. time ()? // Включаем таймер 1.

While (ITMR1IF); // Дождемся сброса.

T1CON = 0x0; // Выключаем таймер.

TMR1IF = 0x0; // Сбросим флаг.

} else // Высокий уровень, значит "О".

IRCOMMAND = IRCOMMAND; // Запишем это.

If (b<7) IRCOMMAND = IRCOMMANDccl; //Сместимся влево

На бит. }

PHOTOCOME = 0x0; RAO = 0x0; RAl=0xl;

For (m=0; m<3; ++m) // Перестанем принимать ИК.

// Первый символ номера. // Второй символ номера.

SIM2;

For (1=0; 1<10000; ++1); RA1 = 0x0;

Int cmd() {

If (commanderееіev [5] = "S") ir_stat();

}

Void timeO {

TMR1H = OxFD; переполнения. TMR1L = 0x43; T1CON = 0x1;

} // Таймер 1 для чтения ИК.

// Установка числа циклов до

// FFFF минус 700 (2BCh). // Включение таймера.

Int ir_stat() {

Int ircom; int ircoml; int ircom2; int ігсотЗ;

Command_reciev[0] = "C"; command_reciev[l] = MOD_SIMl+0x30; command_reciev[2] = MOD_SIM2+Ox3Q;

Ircom = IRCOMMAND; // Преобразуем команду в символы.

Ircoml = ircom/0x64;

IRSIMl = ircoml + 0x30;

Ircom2 = (ircom - ircoml*0x64)/OxA;

IRSIM2 = ircom2 + 0x30;

ІгсотЗ = (ircom - ircoml*0x64 - ircom2*0xA); IRSIM3 = ігсотЗ + 0x30;

If (IRCOMMAND == 0) {

Command_reciev[3j = n#n; // Команда не менялась. command_reciev[4] = "f"; command_reciev[5] = "f"-;

CREN =0x0; // Запрещаем прием.

RB0 = 0x1; //Переключим драйвер RS485 на передачу.

TXEN = 0x1; // Разрешаем передачу.

For (i=0; i<6; ++i) putch (commander ее iev [ і ]);

For (i=0;i<1000;i++); // Задержка для вывода, for (i=0; i<6; ++i) command_reciev [і] = " RBO = 0x0; // Выключаем драйвер RS485 на передачу.

TXEN = 0x0; // Запрещаем передачу. CREN =0x1; // Разрешаем прием.

} else //За время между двумя запросами пришла ИК

Команда. {

Cominand_reciev[3] = IRSIMl; command_reciev[4] = IRSIM2; command_reciev[5] = IRSIM3;

CREN =0x0; // Запрещаем прием.

RBO = 0x1; //Переключим драйвер RS485 на передачу.

TXEN =0x1; // Разрешаем передачу.

For (i=0; i<6; ++i) putch (command_reciev [і]) ;

For (i=0;iclOOO;i++); // Задержка для вывода.

For (i=0; i<6; ++i) command_reciev [i] = " ";

RBO = 0x0; // Выключаем драйвер RS485 на передачу.

TXEN =0x0; // Запрещаем передачу.

CREN =0x1; // Разрешаем прием. }

IRCOMMAND = 0x0; //Мы передали команду, она больше не

Нужна. }

Void main (void) // Начнем работать.

{

Init_comms(); // Инициализация модуля,

For (i=0; i<6; ++i) command_reciev [і] = " "; command_reciev [0] = "С";

//Прочитаем и преобразуем номер модуля. MOD_ADDR = PORTB; // Номер модуля в старших битах. MOD_ADDR=MOD_ADDR»4; // Сдвинем на четыре бита. RA2 = 0x1; // Чтобы видно, что модуль включен.

// Так и не получилось!!

// Начинаем работать.

Start: if (RB3) // Нет ИК-сигнала.

{

PHOTOCOME = 0x0; RAO = 0x00;

If (!RB3) // Появился ИК-сигнал {

For (k=0; k<30;++k); // Поставим задержку.

If (!RB3) // ИК-сигнал не пропал?

{

PHOTOCOME = 0x1? RAO = 0x01;

}

} else {

PHOTOCOME = 0x0; RAO = 0x00;

}

While (PHOTOCOME == 1) {

// Обработаем ИК-команду.

Ir_cmd ();

Break; }

// Нет ИК-сигнала, проверим сеть. CREN =0x1; input = getch();

Switch (input) {

Case "С": // Если обращение к фото модулю.

For (i=l; i<6; ++i) // Запишем команду в массив.

{

Input = getch(); command_reciev [і] = input;

}

MOD_NUM = sim_num_adr (); // Чтение из сети.

If (MODJNUM!= MOD_ADDR) break; // Если не наш адрес.

Else

If (commanderееіev [3] = n$n) cmd(); // Если

Команда.

Default: goto start;

}

Умный дом

Вторая версия основной программы на языке С++

/****************^ * TOC o "1-3" h z Copyright (С) 2006 by Vladimir Gololobov * * vgololobov@yandex. ru * * * * This program is free software; you can redistribute it …

Циклы

Циклы выполняют выражения или блоки выражений до тех пор, пока выражение условия не становится истинным. Наша программа требует двух циклов (один вложен в дру­гой). Пока пользователь желает угадывать последовательно­сти: { …

Две полезные схемы

Первая схема относится к настенному выключателю, работа­ющему по протоколу XI0. Что полезного можно почерпнуть из этой схемы? Например, организацию сканирования сети и управления триаком. Схему я привожу, как она сохранилась …

Как с нами связаться:

Украина:
г.Александрия
тел./факс +38 05235  77193 Бухгалтерия
+38 050 512 11 94 — гл. инженер-менеджер (продажи всего оборудования)

+38 050 457 13 30 — Рашид - продажи новинок
e-mail: msd@inbox.ru
msd@msd.com.ua
Схема проезда к производственному офису:
Схема проезда к МСД

Оперативная связь

Укажите свой телефон или адрес эл. почты — наш менеджер перезвонит Вам в удобное для Вас время.