Главная       Продать работу       Блог       Контакты       Оплата       О нас       Как мы работаем       Регистрация       Вход в кабинет
Тех. дипломные работы
   автомобили
   спец. техника
   станки
   тех. маш.
   строительство
   электроснабжение
   пищевая промышленность
   водоснабжение
   газоснабжение
   автоматизация
   теплоснабжение
   холодильники
   машиностроение
   др. тех. специальности

Тех. курсовые работы
   автомобили
   спец. техника
   станки
   тех. маш.
   строительство
   детали машин
   электроснабжение
   газоснабжение
   водоснабжение
   пищевая промышленность
   автоматизация
   теплоснабжение
   ТММ
   ВСТИ
   гидравлика и пневматика
   машиностроение
   др. тех. специальности

Тех. дополнения
   Отчеты
   Расчетно-графические работы
   Лекции
   Задачи
   Лабораторные работы
   Литература
   Контрольные работы
   Чертежи и 3D моделирование
   Тех. soft
   Рефераты
   Общий раздел
   Технологический раздел
   Конструкторский раздел
   Эксплуатационный раздел
   БЖД раздел
   Экономический раздел
   Экологический раздел
   Автоматизация раздел
   Расчетные работы

Гум. дипломные работы
   педагогика и психология
   астрономия и космонавтика
   банковское, биржевое дело
   БЖД и экология
   биология и естествознание
   бухгалтерский счет и аудит
   военное дело
   география
   геология
   государство и право
   журналистика и СМИ
   иностранные языки
   история
   коммуникации
   краеведение
   кулинария
   культура и искусство
   литература
   экономика и торговля
   математика
   медицина
   международное отношение
   менеджмент
   политология
   музыка
   религия
   социология
   спорт и туризм
   таможенная система
   физика
   химия
   философия
   финансы
   этика и эстетика
   правознавство

Гум. курсовые работы
   педагогика и психология
   астрономия и космонавтика
   банковское, биржевое дело
   БЖД и экология
   биология и естествознание
   бухгалтерский счет и аудит
   военное дело
   география
   геология
   государство и право
   журналистика и СМИ
   иностранные языки
   история
   коммуникации
   краеведение
   кулинария
   культура и искусство
   литература
   экономика и торговля
   математика
   медицина
   международное отношение
   менеджмент
   политология
   музыка
   религия
   социология
   спорт и туризм
   таможенная система
   физика
   химия
   философия
   финансы
   этика и эстетика
   правознавство

Гум. дополнения
   Отчеты
   Расчетные работы
   Лекции
   Задачи
   Лабораторные работы
   Литература
   Контрольные работы
   Сочинения
   Гум. soft
   Рефераты

Рефераты
   Авиация и космонавтика
   Административное право
   Арбитражный процесс
   Архитектура
   Астрология
   Астрономия
   Банковское дело
   Безопасность жизнедеятельнос
   Биографии
   Биология
   Биология и химия
   Биржевое дело
   Ботаника и сельское хоз-во
   Бухгалтерский учет и аудит
   Валютные отношения
   Ветеринария
   Военная кафедра
   ГДЗ
   География
   Геодезия
   Геология
   Геополитика
   Государство и право
   Гражданское право и процесс
   Делопроизводство
   Деньги и кредит
   ЕГЭ
   Естествознание
   Журналистика
   ЗНО
   Зоология
   Издательское дело и полиграф
   Инвестиции
   Иностранный язык
   Информатика
   Информатика, программировани
   Исторические личности
   История
   История техники
   Кибернетика
   Коммуникации и связь
   Компьютерные науки
   Косметология
   Краеведение и этнография
   Краткое содержание произведе
   Криминалистика
   Криминология
   Криптология
   Кулинария
   Культура и искусство
   Культурология
   Литература : зарубежная
   Литература и русский язык
   Логика
   Логистика
   Маркетинг
   Математика
   Медицина, здоровье
   Медицинские науки
   Международное публичное прав
   Международное частное право
   Международные отношения
   Менеджмент
   Металлургия
   Москвоведение
   Музыка
   Муниципальное право
   Налоги, налогообложение
   Наука и техника
   Начертательная геометрия
   Оккультизм и уфология
   Остальные рефераты
   Педагогика
   Политология
   Право
   Право, юриспруденция
   Предпринимательство
   Прикладные науки
   Промышленность, производство
   Психология
   психология, педагогика
   Радиоэлектроника
   Реклама
   Религия и мифология
   Риторика
   Сексология
   Социология
   Статистика
   Страхование
   Строительные науки
   Строительство
   Схемотехника
   Таможенная система
   Теория государства и права
   Теория организации
   Теплотехника
   Технология
   Товароведение
   Транспорт
   Трудовое право
   Туризм
   Уголовное право и процесс
   Управление
   Управленческие науки
   Физика
   Физкультура и спорт
   Философия
   Финансовые науки
   Финансы
   Фотография
   Химия
   Хозяйственное право
   Цифровые устройства
   Экологическое право
   Экология
   Экономика
   Экономико-математическое мод
   Экономическая география
   Экономическая теория
   Этика
   Юриспруденция
   Языковедение
   Языкознание, филология

Главная > Тех. дипломные работы > автоматизация
Название:
Разработка автоматизированной системы контроля и управления бытовой техникой на основе Linux и микроконтроллера AVR

Тип: Дипломные работы
Категория: Тех. дипломные работы
Подкатегория: автоматизация

Цена:
0 руб



Подробное описание:

Аннотация
Данная пояснительная записка содержит 113 страниц и включает 27 иллюстраций, 19 таблиц, 1 приложение, 5 использованных источников.
Ключевые слова: микроконтроллер, Linux, автоматизация, роутер, сеть.
Дипломный проект на тему «Разработка автоматизированной системы контроля и управления бытовой техникой на основе Linux и микроконтроллера AVR» посвящен созданию комплексу устройств и программного обеспечения, которые позволяют удалённо и централизованно производить управление бытовой техникой, а также вести контроль за помещением.
В рамках дипломного проекта было проведено:
• исследование и анализ предметной области;
• исследование и анализ электронных компонентов;
• исследование протоколов взаимодействия;
• разработка микропрограммы для микроконтроллера AVR;
• разработка серверного программного обеспечения для ОС «Linux»;
• разработка клиентского программного обеспечения;
• согласование различных элементов комплекса;
В проекте также содержится экономическое обоснование разработки и рекомендации по охране труда с учетом требований эргономики.

Содержание
Аннотация 4
Введение 7
1. Аналитическая часть 8
1.1. Общая схема работы системы 8
1.2. Микроконтроллеры AVR 10
1.3. Компоненты основного модуля 17
1.3.1. Системная синхронизация и тактовые источники 17
1.3.2. Знакогенерирующий дисплей 29
1.3.3. ДУ приёмник 31
1.3.4. Датчики температуры 32
1.3.5. Конвертор уровней USART и RS-232 34
2. Практическая часть 36
2.1 Разработка программы для микроконтроллера 36
2.1.2. Работа с контроллером дисплея HD44780 36
2.1.3. Работа с USART контроллером 46
2.1.4. Работа с датчиками температуры 49
2.1.5. Работа с ДУ приёмником 59
2.1.6. Разработка протокола для обмена данными. 61
2.1.7. Функции основного блока 65
2.2. Разработка серверного и клиентского программного обеспечения 66
2.2.1. Разработка серверной части для ОС «Linux». 67
2.2.2. Модификация роутера для работы с комплексом. 67
2.2.3. Разработка клиентского ПО для Microsoft Windows 70
2.2.4. Пример использования сторонних приложений 73
3. Оценка экономической эффективности проекта 75
3.1. Определение затрат на разработку проекта 75
3.2. Определение затрат на производство 77
4. Безопасность жизнедеятельности 78
4.1. Санитарно-гигиенические требования при работе с ПЭВМ 78
4.2. Требования к оборудованию рабочих мест 85
Заключение 87
Список источников информации 88
Приложение А 89

Введение
Целью дипломной работы является разработка автоматизированной системы управления бытовой техникой, которая позволяет включать (выключать) электронные устройства – по телефону, по сети, по таймеру и т.д. В последнее время подобные системы становятся очень популярны в мире, обычно их называют «Smart House» или «умный дом». Реализуются они обычно простыми устройствами, которые заранее оптимизированы для определённого способа управления и не обладают возможностью доработки пользователем. В дипломной работе предлагается реализация концепции «умного дома» на основе микроконтроллеров AVR и операционной системы Linux. Данная реализация может быть доработана с учетом расширяющихся возможностей операционной системы Linux. Именно расширяемость программной части комплекса делает этот проект уникальным. Рядовые пользователи не знакомы с программированием микроконтроллеров, а установить простое программное обеспечение может почти каждый. Программисты-любители же легко смогут разработать свои скрипты для ОС «Linux».
Благодаря простому протоколу, клиентское программное обеспечение можно легко разработать для любой платформы, что в совокупности с поддержкой сети позволяет организовать управление техникой практически с любого устройства, имеющего сетевой интерфейс и поддерживающего запуск стороннего кода. В настоящее время список таких платформ огромен: мобильные телефоны, игровые консоли, персональные компьютеры, карманные компьютеры, коммуникаторы и т.п.
Всё это делает разработанную систему очень гибкой и доступной.

1. Аналитическая часть
1.1. Общая схема работы системы
При разработке комплекса основной целью являлось сделать систему независимой от персонального компьютера, поэтому в основе системы лежит блок с микроконтроллером AVR – ATMEGA16 (рисунок 1), который согласует работу всех устройств, опрашивает датчики, включает и выключает реле, выводит на дисплей информацию и работает с управляющим устройством через RS-232 интерфейс. Работу с сетью обеспечивает ОС «Linux», в качестве такого устройства был взят бытовой роутер, который был доработан для работы с микроконтроллером через RS-232. В результате чего получилось идеальное решение для дома – он не шумит и очень экономно расходует электроэнергию, что позволяет использовать его круглосуточно. Под ОС «Linux» работает серверное программное обеспечение, которое обеспечивает работу с локальной сетью и сетью Интернет. Клиентские приложения могут быть установлены на любое устройство и ОС, после подключения к серверу с их помощью можно удалённо контролировать бытовую технику и управлять ей, а при использовании веб-сервера это можно делать через любой веб-браузер. При желании всю систему можно расширить, подключая дополнительные модули и устанавливая дополнительное программное обеспечение. Таким образом, представленный комплекс позволяет управлять устройствами как локально, так и удалённо.

 

 

 

 

 

 


1.2. Микроконтроллеры AVR
AVR — это семейство восьмибитных микроконтроллеров фирмы Atmel.

Описание архитектуры
Микроконтроллеры AVR имеют гарвардскую архитектуру (программа и данные находятся в разных адресных пространствах) и систему команд, близкую к идеологии RISC. Процессор AVR имеет 32 8-битных регистра общего назначения, объединённых в регистровый файл. В отличие от «идеального» RISC, регистры не абсолютно ортогональны:
• Три «сдвоенных» 16-битных регистра-указателя X (r26:r27), Y (r28:r29) и Z (r30:r31)
• Некоторые команды работают только с регистрами r16…r31.
• Результат умножения (в тех моделях, в которых есть модуль умножения) всегда помещается в r0:r1

Система команд
Система команд микроконтроллеров AVR весьма развита и насчитывает в различных моделях от 90 до 133 различных инструкций. Большинство команд занимает только 1 ячейку памяти (16 бит). Большинство команд выполняется за 1 такт.
Всё множество команд микроконтроллеров AVR можно разбить на несколько групп:
• команды логических операций
• команды арифметических операций и команды сдвига
• команды операции с битами
• команды пересылки данных
• команды передачи управления
• команды управления системой

Управление периферийными устройствами осуществляется через адресное пространство данных. Для удобства существуют «сокращённые команды» IN/OUT.

Семейства микроконтроллеров
Стандартные семейства:
• tinyAVR
• Флеш-память 8 Кб, SRAM 512 б, EEPROM 512 б
• Число линий В/В 6-18 (общее количество выводов 8-32)
• Ограниченный набор периферийных устройств
• megaAVR
• Флеш-память 256 Кб, SRAM 8 Кб, EEPROM 4 Кб
• Число линий В/В 23-86 (общее количество выводов 28-100)
• Аппаратный умножитель
• Расширенная система команд и периферийных устройств
• XMEGA AVR
• Флеш-память 384 Кб, SRAM 32 Кб, EEPROM 4 Кб
• 4-ех канальный DMA-контроллер
• Инновационная система обработки событий
Был выбран микроконтроллер ATMEGA16 из серии megaAVR, т.к. он не очень дорогой, имеет при этом достаточное количество памяти, линий данных и лёгкие в освоении средства разработки.
Отличительные особенности ATMEGA16:
• 8-разрядный высокопроизводительный AVR микроконтроллер с малым потреблением
• Прогрессивная RISC архитектура
• 130 высокопроизводительных команд, большинство команд выполняется за один тактовый цикл
• 32 8-разрядных рабочих регистра общего назначения
• Полностью статическая работа
• Производительность приближается к 16 MIPS (при тактовой частоте 16 МГц)
• Встроенный 2-цикловый перемножитель
• Энергонезависимая память программ и данных
• 16 Кбайт внутрисистемно программируемой Flash памяти (In-System Self-Programmable Flash)
• Обеспечивает 1000 циклов стирания/записи
• Дополнительный сектор загрузочных кодов с независимыми битами блокировки
• Внутрисистемное программирование встроенной программой загрузки
• Обеспечен режим одновременного чтения/записи (Read-While-Write)
• 512 байт EEPROM
• Обеспечивает 100000 циклов стирания/записи
• 1 Кбайт встроенной SRAM
• Программируемая блокировка, обеспечивающая защиту программных средств пользователя
• Интерфейс JTAG (совместимый с IEEE 1149.1)
• Возможность сканирования периферии, соответствующая стандарту JTAG
• Расширенная поддержка встроенной отладки
• Программирование через JTAG интерфейс: Flash, EEPROM памяти, перемычек и битов блокировки
• Встроенная периферия
• Два 8-разрядных таймера/счетчика с отдельным предварительным делителем, один с режимом сравнения
• Один 16-разрядный таймер/счетчик с отдельным предварительным делителем и режимами захвата и сравнения
• Счетчик реального времени с отдельным генератором
• Четыре канала PWM
• 8-канальный 10-разрядный аналого-цифровой преобразователь
• 8 несимметричных каналов
• 7 дифференциальных каналов (только в корпусе TQFP)
• 2 дифференциальных канала с программируемым усилением в 1, 10 или 200 крат (только в корпусе TQFP)
• Байт-ориентированный 2-проводный последовательный интерфейс
• Программируемый последовательный USART
• Последовательный интерфейс SPI (ведущий/ведомый)
• Программируемый сторожевой таймер с отдельным встроенным генератором
• Встроенный аналоговый компаратор
• Специальные микроконтроллерные функции
• Сброс по подаче питания и программируемый детектор кратковременного снижения напряжения питания
• Встроенный калиброванный RC-генератор
• Внутренние и внешние источники прерываний
• Шесть режимов пониженного потребления: Idle, Power-save, Power-down, Standby, Extended Standby и снижения шумов ADC
• Выводы I/O и корпуса
• 32 программируемые линии ввода/вывода
• 40-выводной корпус PDIP и 44-выводной корпус TQFP
• Рабочие напряжения
• 2,7 - 5,5 В (ATMEGA16L)
• 4,5 - 5,5 В (ATMEGA16)
• Рабочая частота
• 0 - 8 МГц (ATMEGA16L)
• 0 - 16 МГц (ATMEGA16)


Рисунок 2 – Блок схема ATMEGA16


Рисунок 3 – Расположение выводов ATMEGA16

1.3. Компоненты основного модуля
Кроме микроконтроллера ATMEGA16 в основном модуле используются и другие компоненты:
• Кварцевый резонатор на 16МГц
• Знакогенерирующий дисплей Winstar WH2402A
• Конвертор уровней Maxim MAX232
• Два цифровых датчика температуры Dallas DS1820
• Датчик движения
• Панель с кнопками
• Промежуточные твёрдотельные реле

Рассмотрим каждый из компонентов подробнее.

1.3.1. Системная синхронизация и тактовые источники
В микроконтроллерах AVR доступен широкий выбор источников тактовой частоты центрального процессора. Выбор между ними следует делать на основе технических требований от итогового устройства.
На рисунке ниже представлены источники синхронизации и распределение синхроимпульсов к встроенным блокам ATMEGA16. Не обязательно вся синхронизация должна работать в одно и тоже время. В целях снижения энергопотребления тактирование неиспользуемых модулей может быть прекращено путем перевода в различные режимы сна.

Рисунок 4 – Источники синхронизации

Синхронизация ЦПУ – clkCPU
Синхронизация ЦПУ подключается к модулям микроконтроллера, которые связаны с работой ядра AVR. Примерами таких модулей являются файл регистров общего назначения, регистр статуса и память данных, выполняющая функцию стека. Остановка синхронизации ЦПУ приводит к прекращению выполнения ядром любых действий и вычислений.
Синхронизация ввода-вывода – clkI/O
Синхронизация ввода-вывода используется основными модулями ввода-вывода, в т.ч. таймеры-счетчики, SPI и USART. Она также используется модулем внешних прерываний, но в некоторых случаях внешние прерывания детектируются в асинхронном режиме для поддержки работоспособности внешних прерываний даже при отключенной синхронизации. Также обратите внимание, что после отключения данной синхронизации (во всех режимах сна) двухпроводной интерфейс TWI продолжает наблюдать за передаваемым по шине адресом асинхронно.


Синхронизация флэш-памяти – clkFLASH
Синхронизация флэш-памяти тактирует работу интерфейса флэш-памяти. Обычно эта синхронизация работает одновременно с синхронизацией ЦПУ.

Синхронизация асинхронного таймера – clkASY
Синхронизация асинхронного таймера используется для тактирования асинхронного таймера-счетчика внешним кварцевым резонатором частотой 32 кГц. Данный тактовый генератор позволяет использовать таймер-счетчик как счетчик реального времени, даже при переводе микроконтроллера в режим сна.

Синхронизация АЦП – clkADC
АЦП тактируется обособленным блоком синхронизации. Это позволяет остановить работу синхронизации ЦПУ и ввода-вывода на время преобразования АЦП в целях снижения влияния цифрового шума на результат преобразования. С помощью этого достигается более точный результат преобразования.

Источники синхронизации
С помощью конфигурационных бит имеется возможность выбора нескольких источников синхронизации. Сигнал синхронизации выбранного источника является входным для тактового генератора AVR и затем подключается к соответствующим модулям.
Таблица 1 – Выбор опций синхронизации
Источники синхронизации CKSEL3..0(1)
Внешний кварцевый/керамический резонатор 1111 – 1010
Внешний низкочастотный кварцевый резонатор 1001
Внешний RC-генератор 1000 – 0101
Встроенный калиброванный RC-генератор 0100 – 0001
Внешняя синхронизация 0000

При выходе ЦПУ из режима выключения (Power-down) или экономичного режима (Power-save) выбранный источник синхронизации используется по истечении времени на запуск, тем самым гарантируя стабильность работы генератора перед первым выполнением инструкции. Запуск микроконтроллера, инициированный сбросом (reset), сопровождается дополнительной задержкой для достижения питанием стабильного уровня перед переводом микроконтроллера в нормальный режим работы. Генератор сторожевого таймера используется для синхронизации данного модуля, который формирует задержку при запуске. Длительность генерируемой задержки определяется количеством импульсов генератора сторожевого таймера. Частота генератора сторожевого таймера зависит от напряжения питания.
Таблица 2 – Количество тактов сторожевого таймера
Типичное время переполнения
(VCC = 5.0В) Типичное время переполнения
(VCC = 3.0В) Количество тактов
4.1 мс 4.3 мс 4K (4096)
65 мс 69 мс 64K (65536)

Первоначальный источник синхронизации
Микроконтроллер поставляется с установками CKSEL = “0001” и SUT = “10”. Эти значения соответствуют выбору в качестве источника синхронизации внутреннего RC-генератора с максимальным временем старта. Данная настройка гарантирует всем пользователям возможность установить требуемый источник синхронизации с помощью внутрисистемного или параллельного программатора.

Кварцевый генератор
XTAL1 и XTAL2 – вход и выход, соответственно, инвертирующего усилителя, который может быть настроен для использования в качестве встроенного генератора. Для задания частоты может использоваться либо кварцевый либо керамический резонатор. Конфигурационный бит CKOPT выбирает один из двух режимов усилителя генератора. Если CKOPT запрограммирован, то амплитуда колебаний выходного сигнала генератора будет ограничена уровнями питания. Данный режим рекомендуется использовать при высоком уровне окружающих шумов или при использовании выхода XTAL2 в качестве источника синхронизации внешней схемы. Данный режим характеризуется широким частотным диапазоном. Если CKOPT – не запрограммирован, то амплитуда выходных колебаний генератора снижается. Использование данного режима позволяет существенно снизить потребляемую мощность, но при этом ограничен частотный диапазон и нельзя XTAL2 использовать для внешней синхронизации.
При использовании резонаторов максимальная частота равна 8 МГц, если CKOPT – не запрограммирован, и 16 МГц, если CKOPT- запрограммирован. C1 и C2 должны быть всегда равны независимо от использования кварцевого или керамического резонатора. Оптимальное значение емкостей конденсаторов зависит от используемого кварцевого или керамического резонатора, от значения паразитной емкости и от окружающего уровня электромагнитного шума. Рекомендации по выбору номиналов конденсаторов приведены в таблице ниже. Для керамических резонаторов необходимо использовать конденсаторы с номиналом, рекомендуемым производителем.

Таблица 3 – Рабочие режимы кварцевого генератора
CKOPT CKSEL3..1 Частотный диапазон(1), МГц Рекомендуемый диапазон номиналов C1 и C2 при использовании кварцевого резонатора
1 101 0.4-0.9 -
1 110 0.9-3.0 12пФ-22пФ
1 111 3.0-8.0 12пФ-22пФ
0 101, 110, 111 1.0- 12пФ-22пФ

Таблица 4 – Временная задержка при запуске для различных настроек
CKSEL0 SUT1..0 Длительность задержки при выходе из режима выключения и экономичного режима Дополнительная задержка после сброса (VCC= 5.0В) Рекомендуемая область применения
0 00 258 CK 4.1 мс Керамический резонатор, быстро нарастающее питание
0 01 258 CK 65 мс Керамический резонатор, медленно нарастающее питание
0 10 1K CK – Керамический резонатор, детектор питания (BOD) включен
0 11 1K CK 4.1 мс Керамический резонатор, быстро нарастающее питание
1 00 1K CK 65 мс Керамический резонатор, медленно нарастающее питание
1 01 16K CK – Кварцевый генератор, детектор питания (BOD) включен
1 10 16K CK 4.1 мс Кварцевый резонатор, быстро нарастающее питание
1 11 16K CK 65 мс Кварцевый резонатор, медленно нарастающее питание

Низкочастотный кварцевый генератор
Для использования часового кварцевого резонатора 32768 кГц в качестве источника синхронизации необходимо выбрать низкочастотный кварцевый генератор путем установки конфигурационных бит CKSEL равными “1001”. Подключение кварцевого резонатора показано на рисунке 19. Путем программирования конфигурационного бита пользователь может разрешить подключение встроенных конденсаторов к выводам XTAL1 и XTAL2, тем самым исключая необходимость применения внешних конденсаторов. Внутренние конденсаторы имеют номинал 36 пФ. После выбора данного генератора, длительности задержек при старте определяются конфигурационными битами SUT (Таблица 5).

Таблица 5 – Длительности задержек
SUT1..0 Длительность задержки при выходе из режима выключения и экономичного режима Дополнительная задержка после сброса (VCC= 5.0В) Рекомендуемая область применения
00 1K CK(1) 4.1 мс Быстро нарастающее питание или включен детектор питания BOD
01 1K CK(1) 65 мс Медленно нарастающее питание
10 32K CK 65 мс Стабильная частота при старте
11 Зарезервировано

Внешний RC-генератор
Для приложений некритичных к стабильности временных характеристик в качестве источника синхронизации может использоваться внешняя RC-цепь, подключение. Тактовая частота грубо определяется выражением f = 1/(3RC). Номинал конденсатора C должен быть не менее 22 пФ. Путем программирования конфигурационного бита CKOPT пользователь может разрешить подключение внутреннего конденсатора 36 пФ между XTAL1 и GND (рисунок), тем самым исключая необходимость применения внешнего конденсатора. Более подробная информация о работе генератора и о выборе номиналов R и C приведена в рекомендациях по применению внешнего RC-генератора.

Рисунок 5 – Внешний RC генератор

Генератор может работать в четырех различных режимах, каждый из которых ориентирован на специфический частотный диапазон. Рабочий режим выбирается конфигурационными битами CKSEL3..0 (
Таблица 6).

Таблица 6 – Рабочие режимы внешнего RC генератора
CKSEL3..0 Частотный диапазон, МГц
0101 - 0.9
0110 0.9 - 3.0
0111 3.0 - 8.0
1000 8.0 - 12.0

После разрешения работы данного генератора длительность задержки при старте определяется установками конфигурационных бит (Таблица 5).

Таблица 7 – Длительности задержек при старт после выбора внешнего RC-генератора
SUT1..0 Длительность задержки при выходе из режима выключения и экономичного режима Дополнительная задержка после сброса (VCC= 5.0В) Рекомендуемая область применения
00 18 CK(1) - Включен детектор питания BOD
01 18 CK 4.1 мс Быстро нарастающее питание
10 18 CK 65 мс Медленно нарастающее питание
11 6 CK (1) 4.1 мс Быстро нарастающее питание или включенный детектор питания BOD

Встроенный калиброванный RC-генератор
Встроенный калиброванный RC-генератор формирует фиксированные тактовые частоты 1.0, 2.0, 4.0 или 8.0 МГц. Данные значения частот являются номинальными и определены для напряжения питания 5В при 25 градусах. Одна из этих частот может быть выбрана в качестве тактовой, если запрограммировать конфигурационные биты CKSEL (
Таблица 8). После выбора микроконтроллер будет работать без внешних компонентов. Конфигурационный бит CKOPT должен быть всегда незапрограммированным, если используется внутренний RC-генератор. В процессе сброса калибровочный байт аппаратно записывается регистр OSCCAL, тем самым автоматически выполняя калибровку RC-генератора. При питании 5В, температуре 25 градусов и выбранной частоте генератора 1.0 МГц данный метод калибровки обеспечивает погрешность генерации частоты не хуже ± 3% от номинального значения. Использование методов калибровки во время работы микроконтроллера позволяет достичь точности ± 1% при любой заданной температуре и напряжении VCC. При использовании данного генератора в качестве тактового генератор сторожевого таймера также останется использоваться для тактирования сторожевого таймера и для задания длительности задержки при сбросе. Более подробная информация о предварительно запрограммированном калибровочном значении приведена в разделе “Калибровочный байт”.

Таблица 8 – Режимы встроенного калибрированного RC-генератора
CKSEL3..0 Номинальная частота, МГц
0001(1) 1.0
0010 2.0
0011 4.0
0100 8.0


После выбора данного генератора длительность задержки при запуске микроконтроллера определяется установками конфигурационных бит SUT (Таблица 9). Выводы XTAL1 и XTAL2 должны быть оставлены неподключенными (NC).

Таблица 9 – Длительности задержек при запуске с различными настройками встроенного калибрированного RC-генератора
SUT1..0 Длительность задержки при выходе из режима выключения и экономичного режима Дополнительная задержка после сброса (VCC= 5.0В) Рекомендуемые условия для применения
00 6 CK - Включен детектор питания BOD
01 6 CK 4.1 мс Быстро нарастающее питание
10 6 CK 65 мс Медленно нарастающее питание
11 Зарезервировано

Регистр калибровки генератора – OSCCAL

Разряды 7..0 – CAL7..0: Калибровочное значение для генератора

Запись значения калибровочного байта в данный регистр приведет к подстройке генератора на номинальную частоту. В процессе сброса калибровочное значение для частоты 1МГц (расположен в старшем байте строки сигнатуры) автоматически записывается в регистр OSCCAL. Если встроенный RC-генератор используется на других частотах, то калибровочный байт необходимо записывать программно. Для этого необходимо с помощью программатора считать значение калибровочного байта, затем сохранить его значение во флэш-память или ЭСППЗУ. После этого, калибровочное значение может быть считано программно, а затем записано в регистр OSCCAL. Если в регистр OSCCAL записать ноль, то выбирается минимальная частота. Запись ненулевого значения приводит к повышению частоты генератора. Запись $FF – к выбору максимальной частоты. Калиброванный генератор используется для синхронизации доступа к ЭСППЗУ и флэш-памяти. Во время выполнения записи в ЭССПЗУ или во флэш-память не следует выполнять калибровку на частоту выше на 10% от номинальной. В противном случае, запись в ЭССПЗУ или во флэш-память может быть некорректной. Обратите внимание, что генератор откалиброван отдельно на частоты 1.0, 2.0, 4.0 или 8.0 МГц (
Таблица 10).

Таблица 10 – Диапазон частот встроенного RC-генератора
Значение OSCCAL Минимальная частота в
процентах от номинальной, % Максимальная частота в
процентах от номинальной, %
$00 50 100
$7F 75 150
$FF 100 200

Внешняя синхронизация
Если необходимо тактировать микроконтроллер от внешнего источника, то его необходимо подключить к выводу XTAL1. В этом случае внешняя синхронизация должна быть разрешена записью в конфигурационные биты CKSEL значения “0000”. Если запрограммировать конфигурационный бит CKOPT, то между XTAL1 и GND будет подключен внутренний конденсатор номиналом 36 пФ.

Рисунок 6 – Схема подключения внешнего источника синхронизации

После выбора данного источника синхронизации длительность задержки при запуске определяется конфигурационными битами SUT (
Таблица 11)

Таблица 11 – Длительность задержки при запуске при выборе внешней синхронизации
SUT1..0 Длительность задержки при выходе из режима выключения и экономичного режима Дополнительная задержка после сброса (VCC= 5.0В) Рекомендуемые условия для применения
00 6 CK - Включен детектор питания BOD
01 6 CK 4.1 мс Быстро нарастающее питание
10(1) 6 CK 65 мс Медленно нарастающее питание
11 Зарезервировано

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

Генератор таймер-счетчика
Выводы генератора таймера-счетчика TOSC1 и TOSC2 предназначены для непосредственного подключения кварцевого резонатора. В этом случае не требуются внешние конденсаторы. Генератор оптимизирован для совместной работы с часовым кварцевым резонатором 32.768 кГц. Подключение внешнего тактового источника к выводу TOSC1 не рекомендуется.

Планируется использовать часы, также понадобится достаточно точный отсчёт времени, поэтому было решено использовать внешний кварцевый резонатор на 8 МГц.

1.3.2. Знакогенерирующий дисплей
Для использования основного блока независимо от других частей комплекса было решено встроить в него жидкокристаллический знакогенерирующий дисплей Winstar WH2404 (Рисунок 7). Эта модель может выводить две строки текста, по 24 символа в каждой. Этого достаточно для вывода меню, часов и основной информации.

Рисунок 7 – Внешний вид дисплея
Дисплей поставляется уже с поддержкой кириллических символов (Рисунок 8), также в него можно загрузить до восьми собственных символов. Данные передаются по восьми или четырём проводам по протоколу контроллера HD44780, который является одним из самых распространённых среди дисплеев. Было решено использовать четырёхпроводную схему. Помимо шины данных требуется подключить ещё три провода для синхронизации, итого семь проводов. Для этого был выделен отдельный порт – скорость передачи данных в таком случае немного ниже, но при этом хватает выводов, что приводит к значительной экономии.

Рисунок 8 – Заводской шрифт в CGRAM памяти дисплея

1.3.3. ДУ приёмник
Для удобства управления устройствами и самим комплексом было решено использовать приёмник сигналов для пультов дистанционного управления, работающих на основе лучшей инфракрасного диапазона. Был выбран TSOP1736 (Рисунок 9).

Рисунок 9 – Внешний вид ДУ приёмника TSOP1736

Этот ДУ приёмник поддерживает большинство бытовых пультов дистанционного управления, поэтому почти в любом доме можно найти пульт дистанционного управления, который сразу будет работать с системой. Можно использовать пульт от телевизора, видеомагнитофона и т.п. TSOP1736 имеет всего три контакта – земля (GND), питание (Vs) и данные (OUT). На самом деле он представляет из себя сложный комплекс устройств (Рисунок 10), который позволяет получить на выходе уже цифровой сигнал, остаётся его только декодировать и выполнить соответствующую команду.


Рисунок 10 – Схема строения ДУ приёмника

1.3.4. Датчики температуры
Было решено не ограничиваться контролем бытовой техники и использовать некоторые датчики системе. Так были установлены два датчика температуры DS1820. В них используется технология «One-Wire», разработанная компанией Dallas, которая позволяет подключить к одному проводу неограниченное количество датчиков и получать информацию о температуре прямо в цифровом виде. DS1820 поставляется в корпусе TO92 и имеет три контакта (Рисунок 11). Технология One-Wire позволяет использовать паразитное питание, т.е. питать датчик от линии данных. Было решено сделать именно так, в результате используется только два контакта – земля (GND) и данные (DQ).

Рисунок 11 – Внешний вид и выводы датчика DS1820
Линия данных работает как на приём, так и на передачу. Таким образом, теоретически неограниченное количество датчиков используют только один вывод на микроконтроллере, что очень экономично. Каждый датчик имеет свой уникальный 64-битный серийный номер, который записан в ROM память, диапазон температур тоже очень широкий: от –55°C до +125°C, а точность измерения при этом составляет ±0.5°C. Всё это делает датчики DS1820 отличным выбором для проекта.

1.3.5. Конвертор уровней USART и RS-232
В микроконтроллере ATMEGA16 есть встроенный USART (Universal Asynchronous Receiver/Transmitter) контроллер. Это универсальный асинхронный приёмопередатчик, используется он для связи микроконтроллера с другими цифровыми устройствами и компьютером. Было решено использовать USART для связи с Linux устройством, при этом планируется сделать интерфейс как можно более универсальным. Встаёт несколько проблем:
• На персональных компьютерах нет USART порта, но есть COM порт, который работает с данными по протоколу RS-232.
• Длина провода при соединении устройств через USART сильно ограничена, буквально до нескольких сантиметров. При использовании протокола RS-232 это ограничение увеличивается до десятков метров.

USART отличается от RS-232 только уровнями напряжений, существует множество готовых устройств для преобразования этих уровней. Было решено воспользоваться MAX232 от компании Maxim, эта микросхема уже давно стала индустриальным стандартом, и её можно встретить почти в каждом устройстве, работающим с RS-232. Использовать её достаточно легко (Рисунок 12), из дополнительных компонентов нужно использовать только четыре конденсатора на 1 мкФ.

Рисунок 12 – Схема подключения конвертера
Работает MAX232 как на приём, так и на передачу. Это позволяет легко реализовать двухстороннюю связь на большом расстоянии с любым устройством, обладающим COM (RS-232) портом.

2. Практическая часть
2.1 Разработка программы для микроконтроллера
Во втором разделе дипломной работы подробно рассматривается разработка программного обеспечения комплекса. В случае с микроконтроллером микропрограмма, записываемая в него, называется прошивкой. Было решено написать её на языке C, используя среду WinAVR. Этот пакет содержит компилятор C/C++ для микроконтроллеров AVR и набор готовых библиотек, облегчающих разработку. Самое сложное в данном проекте – согласование всех цифровых компонентов, ведь у каждого из них свой протокол обмена данными, соответственно надо написать модули для работы с этими протоколами, основываясь на технической документации к компонентам. Рассмотрим каждый из них подробнее.
2.1.2. Работа с контроллером дисплея HD44780
Разработку устройства, основанного на микроконтроллере, стоит начинать с организации ввода и вывода, иначе контролировать выполняемую программу будет невозможно. Дисплей Winstar WH2404 основан на контроллере HD44780, это очень популярный контроллер, на нём основаны почти все знакогенерирующие дисплеи. Для его связи с микроконтроллером используется семь проводов, под которые был выделен отдельный порт:
• A0 – RS, определяет тип данных
• A1 – RW, определяет направление данных
• A2 – E, синхронизация
• A3 – D4, данные
• A4 – D5, данные
• A5 – D6, данные
• A6 – D7, данные

Логическая структура LCD контроллера HD44780.
Контроллер имеет свой блок управления, который обрабатывает команды и память. Она делится на три вида:
DDRAM - память дисплея. Все что запишется в DDRAM, будет выведено на экран. Например, при записи туда кода 0×31 — на экране выскочит символ “1″ т.к. 0х31 это ASCII код цифры 1. Но есть тут одна особенность – DDRAM память гораздо больше, чем видимая область экрана. DDRAM содержит 80 ячеек — 40 в первой строке и 40 во второй, а дисплей может двигаться по этой памяти, высвечивая видимую область. Для перемещения дисплея есть специальная команда. Также есть понятие курсора — это место, в которое будет записан следующий символ, т.е. текущее значение счетчика адреса. Курсор не обязательно может быть на экране, он может располагаться и за экраном или быть отключен вовсе.
CGROM - таблица символов. Когда мы записываем в ячейку DDRAM байт, то из таблицы берется символ и рисуется на экране. CGROM нельзя изменить, поэтому важно, чтобы она имела кириллические символы.
CGRAM - тоже таблица символов, но ее мы можем менять, создавая свои символы. Адресуется она линейно, то есть вначале идет 8 байт одного символа, построчно, снизу вверх — один бит равен одной точке на экране. Потом второй символ также. Поскольку знакоместо составляет 5 на 8 точек, то старшие три бита роли не играют. Всего в CGRAM может быть 8 символов, соответственно CGRAM имеет 64 байта памяти. Эти программируемые символы имеют коды от 0х00 до 0х08. Например, записав в первые 8 байт CGRAM (первый символ с кодом 00) какую-то информацию, и записав в DDRAM нуль (код первого символа в CGRAM) мы увидим на экране наш символ.
Доступ к памяти осуществляется достаточно легко: выбираем командой в какую именно память и начиная с какого адреса будут записываться данные, затем просто посылаем эти данные. Если указано, что записываем в DDRAM то данные выводятся на экран (или в скрытую область), а если в CGRAM то данные будут записаны в память знакогенератора.
Контроллер DH44780 предоставляет нам несколько простых команд. О том, что передается дисплею - команда или данные, определяется состоянием вывода RS. Сама команда состоит из старшего бита, определяющего, за что отвечает данная команда, и битов параметров, указывающих контроллеру HD44780 что именно требуется сделать. Таблица команд приведена ниже.

Таблица 12 – Команды контроллера HD44780
DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 Значение
0 0 0 0 0 0 0 1 Очистка экрана. Счетчик адреса на 0 позицию DDRAM
0 0 0 0 0 0 1 - Адресация на DDRAM сброс сдвигов, Счетчик адреса на 0
0 0 0 0 0 1 I/D S Настройка сдвига экрана и курсора
0 0 0 0 1 D C B Настройка режима отображения
0 0 0 1 S/C R/L - - Сдвиг курсора или экрана, в зависимости от битов
0 0 1 DL N F - - Выбор числа линий, ширины шины и размера символа
0 1 AG AG AG AG AG AG Переключить адресацию на SGRAM и задать адрес в SGRAM
1 AD AD AD AD AD AD AD Переключить адресацию на DDRAM и задать адрес в DDRAM

Значения бит:
• I/D – инкремент или декремент счетчика адреса. По умолчанию стоит «0» - инкремент. Т.е. каждый следующий байт будет записан в n+1 ячейку. Если поставить 1 - будет декремент.
• S – сдвиг экрана, если поставить «1», то с каждым новым символом будет сдвигаться окно экрана, пока не достигнет конца DDRAM.
• D – включить дисплей. Если поставить туда «0» то изображение исчезнет, а чтобы картинка появилась в эту позицию надо записать «1».
• С – включить курсор в виде прочерка. «1» - включился курсор, «0» - выключить.
• B – вид курсора. «1» - в виде прямоугольника, «0» - в виде чёрточки.
• S/C – сдвиг курсора или экрана. «0» - сдвигается курсор, «1» - экран. По одному разу за команду
• R/L – определяет направление сдвига курсора и экрана. «0» - влево, «1» - вправо.
• D/L – бит определяющий ширину шины данных. «1» - 8 бит, «0» - 4 бита.
• N – число строк. «0» - одна строка, «1» - две строки.
• F – размер символа. «0» - 5х8 точек, «1» - 5х10 точек.
• AG – адрес в памяти CGRAM.
• АD – адрес в памяти DDRAM.

Соответственно перед началом работы (т.е. при включении устройства) нужно сначала инициализировать дисплей. Для этого требуется выполнить следующие команды (Рисунок 13).

Рисунок 13 – Инициализация дисплея

Для наглядности привожу временные диаграммы для записи и чтения данных.


Рисунок 14 – Запись данных



Рисунок 15 – Чтение данных

Для упрощения работы с передачей и приёмом данных было написано несколько функций.
Функция «hd44780_outnibble» для записи 4 бит данных, т.к. используется четырёхбитную шину передачи данных:
static void
hd44780_outnibble(uint8_t n, uint8_t rs)
{
uint8_t x;
HD44780_PORTOUT &= ~_BV(HD44780_RW);
if (rs)
HD44780_PORTOUT |= _BV(HD44780_RS);
else
HD44780_PORTOUT &= ~_BV(HD44780_RS);
x = (HD44780_PORTOUT & ~HD44780_DATABITS) | ((n << HD44780_D4) & HD44780_DATABITS);
HD44780_PORTOUT = x;
(void)hd44780_pulse_e(false);
}

Функция «hd44780_outbyte» для записи байта данных, соответственно она два вызывает функцию «hd44780_outnibble»:
void
hd44780_outbyte(uint8_t b, uint8_t rs)
{
hd44780_outnibble(b >> 4, rs);
hd44780_outnibble(b & 0xf, rs);
}

Функция «hd44780_innibble» для чтения четырёх бит данных:

static uint8_t
hd44780_innibble(uint8_t rs)
{
uint8_t x;

HD44780_PORTOUT |= _BV(HD44780_RW);
HD44780_DDR &= ~HD44780_DATABITS;
if (rs)
HD44780_PORTOUT |= _BV(HD44780_RS);
else
HD44780_PORTOUT &= ~_BV(HD44780_RS);
x = hd44780_pulse_e(true);
HD44780_DDR |= HD44780_DATABITS;
HD44780_PORTOUT &= ~_BV(HD44780_RW);

return (x & HD44780_DATABITS) >> HD44780_D4;
}
Функция «hd44780_inbyte» для чтения байта данных:
uint8_t
hd44780_inbyte(uint8_t rs)
{
uint8_t x;
x = hd44780_innibble(rs) << 4;
x |= hd44780_innibble(rs);
return x;
}

Вспомогательная функция «hd44780_wait_ready», которая ожидает ответа от дисплея:
void
hd44780_wait_ready(void)
{
while (hd44780_incmd() & HD44780_BUSYFLAG) ;
}

На основе всего этого теперь легко написать функцию «hd44780_init», которая инициализирует дисплей:
void
hd44780_init(void)
{
HD44780_DDR = _BV(HD44780_RS) | _BV(HD44780_RW) | _BV(HD44780_E)
| HD44780_DATABITS;
_delay_ms(15); /* 40 ms needed for Vcc = 2.7 V */
hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
_delay_ms(4.1);
hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
_delay_ms(0.1);
hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);

hd44780_outnibble(HD44780_FNSET(0, 1, 0) >> 4, 0);
hd44780_wait_ready();
hd44780_outcmd(HD44780_FNSET(0, 1, 0));
hd44780_wait_ready();
hd44780_outcmd(HD44780_DISPCTL(0, 0, 0));
hd44780_wait_ready();
}

Все эти функции были помещены в файл «hd44780.c», который представляет из себя модуль низкоуровневой работы с дисплеем. Более высокоуровневые функции размещены в модуле «lcd.c».

Полная инициализация дисплея:
void
lcd_init(void)
{
hd44780_outcmd(HD44780_CLR);
hd44780_wait_ready();
hd44780_outcmd(HD44780_ENTMODE(1, 0));
hd44780_wait_ready();
hd44780_outcmd(HD44780_DISPCTL(1, 0, 0));
hd44780_wait_ready();
}

Было решено использовать собственный текстовый буфер, в который будут предварительно заноситься данные. Сделано это для того, чтобы в любой момент можно было вывести на дисплей произвольный текст, сохранив при этом то, что было на экране ранее.
Для вывода буфера используется функция «lcd_update»:
void lcd_update()
{
unsigned char c;
hd44780_wait_ready();
hd44780_outcmd(HD44780_DDADDR(0));
for (c = 0; c<24; c++)
{
hd44780_wait_ready();
hd44780_outdata(MainBuff[c]);
}
hd44780_wait_ready();
hd44780_outcmd(HD44780_DDADDR(40));
for (c = 24; c<48; c++)
{
hd44780_wait_ready();
hd44780_outdata(MainBuff[c]);
}
}

А для записи в буфер используется функция «lcd_putchar»:
int lcd_putchar(char c)
{
c = RusEncode(c);
if (c == '\n')
{
iBuffPos = 24;
} else {
if (iBuffPos == -1) return 0;
MainBuff[iBuffPos] = c;
iBuffPos++;
if ((iBuffPos == 24) || (iBuffPos == 48)) iBuffPos = -1;
}
return 0;
}


Для записи данных в буфер была написана функция «lcd_print»:
void lcd_print(char* text)
{
while (*text)
{
lcd_putchar(*text);
text++;
}
}

Таким образом, можно вывести текст на дисплей, используя всего два вызвова: «lcd_print(‘Текст’)» и «lcd_update()», но лучше так не делать. Дело в том, что изначально все константы хранятся в оперативной памяти программы, а у микроконтроллера ATMEGA16 её всего два килобайта. Поэтому следует использовать специальную директиву компилятора «PROGMEM», чтобы хранить данные в программной области. Делается это так:
char Text[] PROGMEM = ‘Текст’;

Однако, это накладывает некоторые ограничения – эти данные нельзя использовать напрямую, необходимо вызывать специальные функции для их чтения: «pgm_read_byte», «pgm_read_word» и т.д. Поэтому была написана ещё и функция, которая выводит на экран текст, автоматически читая его из программной области памяти:
void lcd_print_pgm(char* text)
{
char c;
while (c = pgm_read_byte(text), c)
{
lcd_putchar(c);
text++;
}
}

2.1.3. Работа с USART контроллером
Дисплей используется для взаимодействия устройства с человеком. Для связи с другими устройствами было решено использовать USART контроллер, который уже встроен в ATMEGA16.
Универсальный синхронный и асинхронный последовательный приемопередатчик (USART) предназначен для организации гибкой последовательной связи.
Отличительные особенности:
• Полнодуплексная работа (раздельные регистры последовательного приема и передачи)
• Асинхронная или синхронная работа
• Ведущее или подчиненное тактирование связи в синхронном режиме работы
• Высокая разрешающая способность генератора скорости связи
• Поддержка формата передаваемых данных с 5, 6, 7, 8 или 9 битами данных и 1 или 2 стоп-битами
• Аппаратная генерация и проверка бита паритета (четность/нечетность)
• Определение переполнения данных
• Определение ошибки в структуре посылки
• Фильтрация шума с детекцией ложного старт-бита и цифровым ФНЧ
• Три раздельных прерывания по завершении передачи, освобождении регистра передаваемых данных и завершении приема
• Режим многопроцессорной связи
• Режим удвоения скорости связи в асинхронном режиме

Краткий обзор.
Ниже представлена упрощенная функциональная схема USART. На рисунке жирным шрифтом выделены регистры и выводы USART.

Рисунок 16 – Передача одного байта информации через USART


Рисунок 17 – Функциональная схема USART контроллера

Пунктирной линией выделены три основных блока USART: тактовый генератор, передатчик и приемник. Регистры управления используются всеми блоками. Логика тактового генератора состоит из логики синхронизации, связанной с внешним тактовым входом (используется в подчиненном режиме) и генератора скорости связи. Вывод XCK (синхронизация передачи) используется только в режиме синхронной передачи. Передатчик состоит из одного буфера записи, последовательного сдвигового регистра, генератора паритета и управляющей логики, которая поддерживает различные форматы последовательной посылки. Буфер записи позволяет непрерывно передавать данные без каких-либо задержек между передачей посылок. Приемник является более сложным блоком USART, т.к. в его состав входят модули обнаружения данных и синхронизации. Модули обнаружения необходимы для асинхронного приема данных. Помимо модулей обнаружения в приемник входит устройство проверки паритета, сдвиговый регистр, и двухуровневый приемный буфер (UDR). Приемник поддерживает те же последовательные форматы, что и передатчик, и может определить ошибку в посылке (кадре), переполнение данных и ошибку паритета.

Инициализация.
Инициализация USART осуществляется через регистры UCSR и UBRR. Для этого была написана функция «USART_init»:
void USART_init(void)
{
#if F_CPU < 2000000UL && defined(U2X)
UCSRA = _BV(U2X);
UBRRL = (F_CPU / (8UL * UART_BAUD)) - 1;
#else
UBRRL = (F_CPU / (16UL * UART_BAUD)) - 1;
#endif
UCSRB = _BV(TXEN) | _BV(RXEN) | _BV(RXCIE);
}

Эта функция универсальная за счёт использования в ней формул с константой F_CPU, которая равна текущей тактовой частоте микроконтроллера в герцах.
Для передачи данных используется функция «USART_TransmitByte»:
void USART_TransmitByte( unsigned char data )
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = data;
}

Она передаёт один байт данных, ожидая перед этим завершения предыдущей передачи. Для приёма данных используется прерывание RXC, которое вызывается автоматически.

2.1.4. Работа с датчиками температуры
Датчики температуры DS1820 работают на основе протокола «1-Wire». Интерфейс 1-Wire разработан фирмой Dallas Semiconductor. Этот протокол привлекателен малым количеством выводов микроконтроллера, требующихся для подключения практически неограниченного количества микросхем. В самом деле, двусторонний обмен требует всего 1 линию. Кроме того, ассортимент устройств с этим интерфейсом весьма широк. Наконец, протокол обмена по этому интерфейсу очень прост и легко реализуется программно практически на любых микроконтроллерах.

Рисунок 18 – Схема подключения 1-Wire устройств
На рисунке показана упрощенная схема аппаратной реализации интерфейса 1-Wire. Вывод DQ устройства представляет собой вход КМОП-логического элемента, который может быть зашунтирован (замкнут на общий провод) полевым транзистором. Сопротивление канала этого транзистора в открытом состоянии - около 100 Ом. Когда транзистор заперт - имеется небольшой ток утечки (примерно 5 мкА) на общий провод.
Шина 1-Wire должна быть подтянута отдельным резистором к напряжению питания устройств (которое, кстати, может быть от 3 до 5В - уточняется по характеристикам конкретного устройства). Сопротивление этого резистора 4.7 К, однако, это значение рекомендовано только для достаточно коротких линий. Если шина 1-Wire используется для подключения удаленных на большое расстояние устройств, то сопротивление этого резистора следует уменьшить. Минимально допустимое его сопротивление - около 300 Ом, а максимальное - около пары-тройки десятков килоом.
Подключение шины 1-Wire к микроконтроллеру показано условно в двух вариантах: с использованием 2 отдельных выводов микроконтроллера (один в качестве выхода, а другой в качестве входа), так и одного, работающего и на ввод и на вывод. Разделение этих способов показано пунктирной линией, условно обозначающей границу корпуса микроконтроллера. Очевидно, что передача какой-либо информации при этом возможна только выдачей низкого уровня в линию, т.е. замыканием ее на общий провод, а в высокий логический уровень линия вернется сама, благодаря наличию внешнего подтягивающего резистора. Так же очевидно, что одновременная передача нескольких устройств обречена на неудачу из-за полного искажения информации (все передаваемые единицы одного устройства будут подавлены передаваемыми нулями от другого устройства).
Как происходит обмен информацией по шине 1-Wire.
• Обмен всегда ведется по инициативе одного ведущего устройства, которое в нашем случае является микроконтроллером.
• Любой обмен информацией начинается с подачи импульса сброса («Reset Pulse» или просто «RESET») в линию 1-Wire ведущим устройством.
• Для интерфейса 1-Wire в общем случае предусматривается "горячее" подключение и отключение устройств.
• Любое устройство, подключенное к 1-Wire после получения питания выдает в линию DQ импульс присутствия, называемый «Presence pulse» (или просто «PRESENCE»). Этот же импульс устройство всегда выдает в линию, если обнаружит сигнал «RESET».
• Появление в шине 1-Wire импульса PRESENCE после выдачи RESET однозначно свидетельствует о наличии хотя бы одного подключенного устройства.
• Обмен информации ведется так называемыми тайм-слотами: один тайм-слот служит для обмена одним битом информации.
• Данные передаются побайтно, бит за битом, начиная с младшего бита. Достоверность переданных/принятых данных (проверка отсутствия искажений) гарантируется путем подсчета циклической контрольной суммы.

На следующем рисунке показана диаграмма сигналов RESET и PRESENCE, с которых всегда начинается любой обмен данными. Кстати, выдача импульса RESET в процессе обмена служит для досрочного завершения процедуры обмена информацией.

Рисунок 19 – Имульс RESET
Как видим, длительность большинства временных интервалов очень приблизительная и имеет только ограничение только по минимуму (не меньше указанного). Условные обозначения линий, показанные на рисунке, будут использоваться и далее.
Импульс RESET формирует микроконтроллер, переводя в низкий логический уровень шину 1-Wire и удерживая ее в этом состоянии минимум 480 микросекунд. Затем микроконтроллер должен "отпустить" шину. Через некоторое время, зависящее от емкости линии и сопротивления подтягивающего резистора, в линии установится высокий логический уровень. Протокол 1-Wire ограничивает это время "релаксации" диапазоном от 15 до 60 микросекунд, что и является определяющим для выбора подтягивающего резистора (как правило, емкость линии мы менять существенно не можем, а именно она оказывает существенное влияние на время возврата линии к высокому уровню).
Обнаружив импульс RESET, ведомое устройство приводит свои внутренние узлы в исходное состояние и формирует ответный импульс PRESENCE, как следует из рисунка - не позже 60 микросекунд после завершения импульса RESET. Для этого устройство переводит в низкий уровень линию DQ и удерживает ее в этом состоянии от 60 до 240 микросекунд. Конкретное время удержания зависит от многих параметров, но всегда находится в указанном диапазоне. После этого устройство так же "отпускает" шину. Но после завершения импульса PRESENCE устройству дается еще некоторое время для завершения внутренних процедур инициализации, таким образом, микроконтроллер должен приступить к любому обмену с устройством не ранее, чем через 480 микросекунд после завершения импульса RESET. Итак, процедура инициализации интерфейса, с которой начинается любой обмен данными между устройствами, длится минимум 960 микросекунд, состоит из передачи от микроконтроллера сигнала RESET и приему от устройства сигнала PRESENCE. Если сигнал PRESENCE не обнаружен - значит на шине 1-Wire нет готовых к обмену устройств.
Теперь рассмотрим процедуры обмена битами информации, которые осуществляются определенными тайм-слотами. Тайм-слот - это по существу определенная, довольно жестко лимитированная по времени последовательность смены уровней сигнала в линии 1-Wire. Различают 4 типа тайм-слотов: передача «1» от микроконтроллера, передача «0» от микроконтроллера, прием «1» от устройства и прием «0» от устройства.
Любой тайм-слот всегда начинает микроконтроллер путем перевода шины 1-Wire в низкий логический уровень. Длительность любого тайм-слота должна находиться в пределах от 60 до 120 микросекунд. Между отдельными тайм-слотами всегда должен предусматриваться интервал не менее 1 микросекунды (конкретное значение определяется параметрами ведомого устройства).
Тайм-слоты передачи отличаются от тайм-слотов приема поведением микроконтроллера: при передаче он только формирует сигналы, при приеме, кроме того, еще и опрашивает (т.е. принимает) уровень сигнала в линии 1-Wire. Следующий рисунок демонстрирует временные диаграммы тайм-слотов всех четырёх типов: вверху показаны тайм-слоты передачи от микроконтроллера, внизу - приема от устройства.

Рисунок 20 – Структура тайм-слотов
Тайм-слот передачи «0» заключается просто в удержании шины 1-Wire в низком уровне в течение всей длительности тайм-слота. Передача «1» осуществляется путем "отпускания" шины 1-Wire со стороны микроконтроллера не ранее чем через 1 микросекунду после начала тайм-слота, но не позже чем через 15 микросекунд. Ведомое устройство опрашивает уровень в шине 1-Wire в течение временного интервала, условно показанного в виде серого прямоугольника, т.е. начиная с 15-й микросекунды от начала тайм-слота и заканчивая 60-й микросекундой от начала. Типичный момент ввода уровня в устройство (т.е. характерный для большинства устройств) - около 30-й микросекунды от начала тайм-слота. Заштрихованная область - это область "нарастания" уровня в шине 1-Wire, которая зависит от емкости линии и сопротивления подтягивающего резистора, она приведена для справки.
Тайм-слоты приема информации отличаются тем, что микрокотроллер формирует только начало тайм-слота (абсолютно так же, как при передаче «1»), а затем управление уровнем шины 1-Wire берет на себя устройство, а микроконтроллер осуществляет ввод этого уровня так же в определенной зоне временных интервалов. Зона эта, как видно из рисунка, довольно мала. Как и раньше, заштрихованная область - область неопределенности, поэтому для ввода контроллеру остается даже не промежуток, а скорее конкретный момент, когда он должен ввести уровень сигнала из линии. Этот момент времени - 14-я или 15-я микросекунда от начала тайм-слота. Если линия имеет малую емкость, а подтягивающий резистор мал, зона опроса несколько расширяется.
Микроконтроллера начинает тайм слот с выдачи в шину 1-Wire "0" в течение 1 микросекунды. Последующий уровень зависит от типа тайм слота: для приема и передачи "1" уровень должен стать высоким, а для передачи "0" - оставаться низким вплоть до конца тайм-слота, т.е. не менее 60 и не более 120 микросекунд. Если микроконтроллер принимает данные, то опрос уровня в шине он должен сделать на промежутке от 13-й до 15-й микросекунде тайм-слота. Микроконтроллер должен обеспечить интервал между отдельными тайм-слотами не менее 1 микросекунды. Важно понимать, что следует очень тщательно подходить к обеспечению в шине 1-Wire требуемых временных интервалов, т.к., например, увеличение длительности тайм-слота вывода "0" свыше рекомендованного значения может привести к ошибочному восприятию этого тайм-слота, как сигнала RESET. Следует учитывать влияние самой линии на длительность фронтов импульсов. Все сигналы, которые должен формировать микроконтроллер, следует формировать по принципу необходимого минимума длительности (т.е. немного больше, чем указанная минимальная длительность), а от устройства следует ожидать сигналов по принципу наихудшего (т.е. ориентироваться на самые худшие варианты временных параметров сигнала). Мною проверено, что соединение по свитым вручную обычным монтажным проводам при типовом подтягивающем резисторе однозначно возможно на расстоянии до 9м, для подключения датчиков температуры этого более, чем достаточно.
Разобравшись с процедурами обмена битами, пора приступать к более высокому уровню протокола обмена информацией, и для этого необходимо рассмотреть принципы адресации устройств и управления ими.
Каждое устройство 1-Wire обладает уникальным идентификационным 64-битным номером, программируемым на этапе производства микросхемы. Уникальным - это значит, что фирма-производитель гарантирует, что не найдется двух микросхем с одинаковым идентификационным номером (по крайней мере в течении нескольких десятков лет при существующих темпах производства).
При рассмотрении протокола обмена мы будем исходить из принципа, что на шине 1-Wire имеется более одного устройства. В этом случае перед микроконтроллером встают 2 проблемы: определение количества имеющихся устройств и выбор (адресация) одного конкретного из них для обмена данными. Решение первой проблемы осуществляется двумя путями: универсальным и гибким, но требующим довольно сложного программно-реализуемого алгоритма, и простым, но с большими ограничениями. Более простой заключается в том, что номера всех используемых в схеме 1-Wire-устройств известны заранее, и они просто используются как константы в программе. Эти номера нанесены прямо на корпусе датчиков, но в любом случае узнать их просто, написав не сложную программу. Все номера устройств 1-Wire на шине уже известны, поэтому алгоритм следующий. Микроконтроллер посылает, импульс RESET, и все датчики выдают PRESENCE. Затем микроконтроллер посылает в шину команду, которую принимают все устройства. Команд определено несколько общих для всех типов 1-Wire-устройств, а так же могут быть команды, уникальные для отдельных типов, в нашем случае это команды для чтения температуры. Среди общих команд нас интересуют следующие:
Таблица 13 – Общие команды для 1-Wire устройств
Команда Значение байта Описание
SEARCH ROM 0xF0 Поиск адресов - используется при универсальном алгоритме определения количества и адресов подключенных устройств
READ ROM 0x33 Чтение адреса устройства - используется для определения адреса единственного устройства на шине
MATCH ROM 0x55 Выбор адреса - используется для обращения к конкретному адресу устройства из многих подключенных
SKIP ROM 0xCC Игнорировать адрес - используется для обращения к единственному устройству на шине, при этом адрес устройства игнорируется (можно обращаться к неизвестному устройству)

В случае с датчиками температуры мы будет использовать также:
Таблица 14 – Команды датчиков температуры
Команда Значение байта Описание
CONVERT 0x44 Конвертирование температуры в цифровой формат
READ SCRATCHPAD 0xBE Чтение температуры

Получаем, что алгоритм работы с датчиками такой:
1. Посылаем сигнал RESET.
2. Ожидаем сигнала PRESENSE.
3. Посылаем команду «0xCC», т.е. адресуем дальнейшие команды всем датчикам ни линии
4. Посылаем команду «0x44», т.е. команду получить текущую температуру в цифровом виде.
5. В течении нескольких секунд удерживаем линию в состоянии высокого уровня, чтобы датчиках хватило питания.

После этого для каждого из датчиков выполняем следующую последовательность:
1. Посылаем сигнал RESET.
2. Ожидаем сигнала PRESENSE.
3. Посылаем команду «0x55», указывая, что обращаемся к конкретному датчику.
4. Посылаем серийный номер опрашиваемого датчика.
5. Посылаем команду «0xBE» для чтения данных.
6. Читаем 9 байт данных.
7. Декодируем полученные данные и получаем температуру.

Отрывок из получившейся программы:
void DS1820_Update()
{
iButtonDDR &= ~((1 << MasterPinTX) + (1 << MasterPinRX));
iButtonPORT &= ~((1 << MasterPinTX) + (1 << MasterPinRX));

unsigned int res, i, sens, b;
unsigned char Data[9];

// Чтение данных с сенсоров
for (sens = 0; sens < SensorsCount; sens++)
{
iButton_Master_TX(500);
res = 0;
for (i = 0; i < 500; i++)
{
if (iButton_Master_RX) res = 1;
_delay_us(1);
}
if (res == 0)
{
DS1820_temp[sens][0] =
DS1820_temp[sens][1] = 0xAA;
} else {
cli();
SendByte(0x55); // Match ROM
for (b = 0; b < 8; b++)
SendByte(pgm_read_byte(&SensorsSerials[sens][b])); SendByte(0xBE);
for (i = 0; i < 9; i++) Data[i] = ReadByte();
sei();
if (CheckCRC(Data, 9))
{
DS1820_temp[sens][0] = Data[0];
DS1820_temp[sens][1] = Data[1];
} else
DS1820_temp[sens][0] = DS1820_temp[sens][1] = 0xAA;
}
}

// Конвертирование данных,
// которые мы прочитаем при следующем опросе
iButton_Master_TX(500);
res = 0;
for (i = 0; i < 500; i++)
{
if (iButton_Master_RX) res = 1;
_delay_us(1);
}
if (res > 0)
{
cli();
SendByte(0xCC); // Skip ROM command
SendByte(0x44); // Convert!
iButton_StrongPullup;
sei();
}
}

На время опроса датчиков прерывания отключаются вызовом «cli» и включаются вызовом «sei». Делается это для того, чтобы не было искажений при отсчёте времени, которое в данном случае критично.
Для декодирования данных была написана функция «DS1820_GetTemp». Некоторые затруднения возникли в связи с тем, что микроконтроллер ATMEGA16 не поддерживает работу с дробными числами, а единица измерения у датчиков – 0,5°C. Поэтому моя функция выводит температуру уже в текстовом виде. Используется это только для вывода температуры на дисплей, при передаче через USART температура передаётся в не декодированном виде.

2.1.5. Работа с ДУ приёмником
ДУ приёмник TSOP1736 выдаёт на выходе низкий сигнал, когда в зону его действия попадает инфракрасный свет от пульта ДУ. Со стороны микроконтроллера остаётся только декодировать последовательность этих сигналов. Было реализовано декодирование протокола RC5, т.к. он самый распространённый на сегодняшний день и используется почти в любой бытовой технике. Исключение составляет только продукция компании SONY, которая использует свой собственны протокол. При необходимости можно доработать программу для работы и с их пультами.
В стандарте RC5 используется бифазное кодирование, также известное как код Манчестер. Частота несущей равна 36кГц. Начало передачи определяют 2 стартовых бита. Следом идет «toggle» бит. Если нажать кнопку на пульте и держать, будут генерироваться посылки (DataWord) с одинаковым значением toggle bit. Если отпустить кнопку и нажать снова, пойдут те же посылки, но уже с инверсным значением toggle bit. Следующие 5 бит - адрес источника, остальные 6 - код команды. Длина пакета (dataword) равна 24.9мс, период повторения пакета 114мс. Длина одного битового интервала ~ 1.8мс (Рисунок 22).

Рисунок 21 – Структура данных


Рисунок 22 – Манчестерское кодирование

Основной трудностью было то, что временные интервалы очень маленькие, т.е. надо очень часто опрашивать приёмник. Поэтому было решено воспользоваться встроенным таймером, который позволяет вызывать прерывание через строго определённый момент времени. Для работы с ДУ приёмником был написан модуль «tsopir.c», который предоставляет функции для опроса датчика, выдающие коды кнопок в числовом виде.

2.1.6. Разработка протокола для обмена данными.
Для обмена данными между основным блоком и другими устройствами необходимо выбрать определённый формат данными, чтобы не было неопределённости. Было решено разработать свой собственный протокол, удовлетворяющий требованиям нашей системы. Каждый пакет данных состоит при этом из трёх частей:

Таблица 15 – Структура пакета
Инициализирующая часть, состоящая из трёх символов «+», указывает на начало нового пакета. Соответственно длина части равна трём байтам. Код пакета. Указывается на тип передаваемых данных. Длина этой части всегда равна одному байту. Данные, смысл которых зависит от кода пакета. Длина данных варьируется.

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

Таблица 16 – Команды для основного блока
Код пакета Длина данных Значение данных
1 3 Синхронизация часов, три байта – это соответственно часы, минуты и секунды.
2 1 Запрос на получение основных данных от блока, это список доступных устройств, их состояние и пр.
3 48 Вывод произвольного текста на дисплей, 48 байт – это соответственно 48 символов. После получения команду происходит переключение на соответствующий буфер.
4 1 Возвращение на основной буфер, т.е. вызывает стирание текста, который был выведен на дисплей предыдущей командой. Один байт данных игнорируется.
5 48 Вывод второстепенной информации на дисплей, которая будет отображаться только одну секунду. 48 байт – это соответственно 48 символов.
6 2 Команда на включение или выключение устройства. Первый байт – номер устройства, второй определяет задание: «0» - выключение, «1» - включение.
7 1 Команда, сбрасывающая таймер отсутствия движения. Применяется для уведомления основного блока о том, что в помещении кто-то есть, чтобы предотвратить ложные срабатывания датчика движения. Один байт игнорируется.
8 1 Команда указывает, что кнопки управления основным блоком на пульте ДУ надо игнорировать. Используется для управления другими устройствами и ПО. Один байт данных игнорируется.
9 1 Команда обратная предыдущей, возвращает кнопки в обычный режим работы. Один байт данных игнорируется.
При передаче пакетов от микроконтроллера другим устройствам используется уже совсем другие команды:
Таблица 17 – Команды основного блока
Код пакета Длина данных Значение данных
1 1 Сигнал, который посылается после включения блока, указывая на начало работы. Данные – любой байт.
2 4 Данные о температуре. По два байта на каждый датчик, в моём случае это соответственно 4 байта.
3 1 Пакет указывает, что на основном блоке была нажата кнопка. Один байт данных – номер кнопки.
4 4 Команда указывает, что на пульте ДУ была нажата кнопка. 4 байта данных – код кнопки.
5 5 Команда указывает, что на пульте ДУ удерживается кнопка. 4 байта данных – код кнопки.
6 1 В этом пакете содержится информация о состоянии устройств. Один байт данных разделяется на восемь бит, каждый из которых относится к соответствующему устройству.
7 1 В этом пакете содержится информация о наличии устройств. Один байт данных разделяется на восемь бит, каждый из которых относится к соответствующему устройству.
8 23 Названия устройств. Первый байт – номер устройства, остальные 22 байта – название.
9 1 Информация о движении в комнате. Один байт данных, «1» - движение есть, «0» - движение отсутствует.

В итоге прерывание, обрабатывающее входящие данные, выглядит так:
ISR(USART_RXC_vect)
{
unsigned char b;
while (UCSRA & (1<<RXC))
{
b = UDR;
if (b == '+')
{
command_pluscount++;
if (command_pluscount >= 3)
{
command_state = 1;
command_pluscount = 0;
}
} else command_pluscount = 0;
switch (command_state)
{
case 1: command_state = 2; break;
case 2:
command_state = 3;
command_num = b;
command_len = 0;
command_complete = 0;
break;
case 3:
if (command_len < 64)
{
command_buf[command_len] = b;
command_len++;
}
if (
((command_num == 1) && (command_len >= 3 )) || (command_num == 2) ||
((command_num == 3) && (command_len >= 48 )) ||
(command_num == 4) ||
((command_num == 5) && (command_len >= 48 )) ||
((command_num == 6) && (command_len >= 2 )) ||
(command_num == 7) ||
(command_num == 8) ||
(command_num == 9)
) command_complete = 1;
break;
}
}
}

Здесь переменные «command_pluscount», «command_state», «command_num» и «command_len» - это глобальные целочисленные переменные, которые определяют на какой стадии происходит получение данных. «command_buf» - это буфер, в который принимаются сами данные. Возвращение из прерывания в основную программу должно происходить как можно быстрее, поэтому выполнение полученной команды происходит в основном коде программы, где с очень небольшим интервалом времени происходит проверка на новые команды (переменная «command_complete»).

2.1.7. Функции основного блока
Подведу итоги, пояснив какие функции выполняет основной блок, и по какой схеме он работает:
• Непосредственно управление устройствами и техникой, включение и выключение управляющих реле.
• Отображение на дисплее текущего времени и температуры.
• Возможность управлять устройствами непосредственно с основной панели блока, используя интуитивно понятные меню на дисплее.
• Возможность управлять устройствами с пульта ДУ.
• Автоматическое отключение определённых устройств при долговременном отсутствия движения в помещении.
• Полное взаимодействие с другими устройствами через RS-232: произвольный вывод текста на дисплей, передача нажимаемых кнопок.

Более полный листинг исходных текстов представлен в приложении А.

2.2. Разработка серверного и клиентского программного обеспечения
В третьей части своей дипломной работы раскрывается вопрос разработки программного обеспечения, которое будет работать с комплексом. Серверная часть будет работать на устройстве с ОС «Linux», для этого был выбран роутер «ASUS WL-500gP», который прошёл модернизацию по установке в него последовательных портов типа RS-232. Таким образом, было сделано идеальное устройство для работы с основным блоком. Способствуют этому следующие факторы:
• Маленький размер
• Низкое электропотребление
• Полное отсутствие шума
• Возможность подключать дополнительные устройства

Клиентское программное обеспечение легко разработать под любую платформу и операционную систему, которая может работать с сетью. Далее будет рассмотрен пример разработки такого приложения для ОС «Microsoft Windows».

2.2.1. Разработка серверной части для ОС «Linux».
Операционная система Linux уже давно зарекомендовала себя для серверных решений, когда программному обеспечению необходимо работать круглосуточно без вмешательства человека. Далее это рассматривается более подробно на примере rrdtool.
Серверная часть представляет собой программу, которая читает и пишет в последовательный порт, обмениваясь, таким образом, командами с основным блоком, передавая эти команды по сети подключившимся клиентам, число которых теоретически не ограничено (Рисунок 23).

Рисунок 23 – Схема взаимодействия модулей сервера

2.2.2. Модификация роутера для работы с комплексом.
Внутри роутера ASUS WL-500gP тоже есть два USART порта, аналогичных тем, что встроены в микроконтроллер. Они идеально подходят для работы с основным блоком, но этому препятствуют два фактора:
• Порты находятся внутри роутера и наружу не выведены
• Для совместимости USART с интерфейсом RS-232 необходимо установить конвертер уровней.

Эти проблемы легко решаются аппаратной модификацией роутера. Было решено использовать конвертер напряжений MAX3232, т.к. в роутере используется процессор с пониженным напряжением в 3.3 вольта. Таким образом, задача свелась к разработке и установке дополнительного модуля внутрь корпуса роутера. Для этих целей была разработана плата (см. рис. 24).


Рисунок 24 – Печатная плата для конвертера напряжений

На этой плате была размещена микросхема MAX3232 в SOIC корпусе и пять конденсаторов. Затем она была установлена в корпус роутера и соединена проводами с выводами USART и гнёздами DB-9, которые являются стандартными для интерфейса RS-232. Первый вывод используется роутером для подключения консоли, второй же можно использовать для произвольных целей, что и было сделано.
В Linux все устройства представляются в виде файлов. В случае с этими портами это:
• /dev/tts/0
• /dev/tts/1
Если в эти файлы производить запись или чтение, то соответственно будет производиться запись в порт или чтение из порта. С точки зрения ОС «Linux» всё это «прозрачно». Таким образом, проверить работоспособность модификации можно простой командой «echo test > /dev/tts/1». Если всё работает, то произойдёт запись в порт, и подключенное к нему устройство получит строку «test». Единственное отличие от работы с обычными файлами заключается в том, что у портов есть ряд параметров: скорость, чётность, контроль передачи и пр. Поэтому перед началом работы с портом необходимо его инициализировать, задав нужные настройки. В данном проекте используется скорость 38400 бод, 8 бит данных и один стоповый бит.

2.2.3. Разработка клиентского ПО для Microsoft Windows
Рассмотрим разработку клиентской программы, которая позволяет управлять бытовой техникой с использованием компьютера под управлением ОС «Microsoft Windows». Основной целью было разработать программу, которая выполняет следующие функции:
• Подключение к серверу, который работает под ОС «Linux» и синхронизация, получение информации о состоянии устройств, их названиях и пр.
• Возможность включать и выключать устройства, используя простой и приятный интерфейс.
• Получение от сервера информацию о кнопках, нажимаемых на пульте ДУ и последующей рассылке их программам, работающим в системе, используя протокол WinLIRC.
• Приём произвольных DDE сообщений от других программ и передача их серверу для вывода на дисплей основного блока.
• Передача серверу уведомлений о том, что пользователь сейчас за компьютер, подтверждая, что он находится в помещении. Для предотвращения ложного отключения устройств, когда датчик движения не срабатывает долгое время.

Клиентское программное обеспечение напрямую взаимодействует с пользователем, поэтому к разработке интерфейса надо отнестись с повышенным вниманием.
Моя программа запускается в фоне при запуске системы, проявляя себя только значков в системном трее. Через пять секунд она подключается к серверу. Двойным кликом по значку вызывается основное окно программы (Рисунок 25).


Рисунок 25 – Основное окно клиентской программы


Главное окно программы разделено на несколько вкладок. В первой вкладке можно увидеть самые основные данные:
• Есть ли соединение с сервером
• Названия и состояния устройств
• Показания датчиков температуры
• Последняя нажатая кнопка на ПДУ (для проверки)
• Есть ли в помещении движение
• Подробный отчёт о движении в помещении

На второй и третьей вкладке можно настроить пульт ДУ – ассоциировать коды кнопок с названиями кнопок и сделать отдельные режимы для разных приложений (Рисунок 26).

Рисунок 26 – Настройка кнопок ПДУ
2.2.4. Пример использования сторонних приложений
ОС Linux на роутере позволяет устанавливать дополнительные приложения и писать скрипты, чтобы сделать весь комплекс более удобным для пользователя. Рассмотрим это на примере установки утилиты веб-сервера и утилиты «rrdtool».
В качестве веб-сервера был выбран «lighttpd», он не очень требователен к аппаратной части роутера и при этом поддерживает всё, что нам нужно, включая язык PHP.
Серверная часть комплекса при получении пакета с температурой выполняет скрипт «tempstats.sh», передавая ему в параметрах командной строки данные датчиков. Вот содержимое скрипта:
/opt/bin/rrdtool update /opt/home/Cluster/tempstats/temp.rrd -t temp_out:temp_in N:$1:$2
date > /opt/home/Cluster/tempstats/tempnow
echo $1 >> /opt/home/Cluster/tempstats/tempnow
echo $2 >> /opt/home/Cluster/tempstats/tempnow

Первая строка вызывает утилиту «rrdtool», о ней написано чуть ниже. Остальные строки осуществляют запись текущей температуры в текстовый файл, который мы можем открыть внешней программой.
Теперь рассмотрим отрывок из PHP скрипта, который доступен через веб-сервер:
$temp = file('/opt/home/Cluster/tempstats/tempnow');
echo ("Данные по температуре ( за " . $temp[0]. "):<br>");
echo ("Температура на улице: <b>" . $temp[1] . "</b><br>");
echo ("Температура в комнате: <b>" . $temp[2] . "</b><br>");

Эти несколько строк позволяют получить данные с датчиков с помощью простого запроса к веб-серверу, т.е. открыв соответствующую страничку. Сделать это можно даже с помощью сотового телефона.
Помимо этого данные о температуре передаются утилите «rrdtool». Эта утилита позволяет генерировать различные графики, исходя из произвольных данных.

Следующий CGI скрипт производит генерацию таких графиков по запросу к веб-серверу:
#!/opt/bin/rrdcgi
<RRD::GRAPH temp1.png --lazy --imgformat PNG --end now
--start end-86000s --width 480 --height 400 DEF:temp_out=/opt/home/Cluster/tempstats/temp.rrd:temp_out:AVERAGE CDEF:zero=temp_out,0,* LINE1:zero#000000 LINE2:temp_out#0000FF:"Outside temperature" DEF:temp_in=/opt/home/Cluster/tempstats/temp.rrd:temp_in:AVERAGE LINE2:temp_in#00FF00:"Inside temperature ололо пыщь пыщь">
<RRD::GRAPH temp2.png --lazy --imgformat PNG --end now
--start end-7d --width 480 --height 400 DEF:temp_out=/opt/home/Cluster/tempstats/temp.rrd:temp_out:AVERAGE CDEF:zero=temp_out,0,* LINE1:zero#000000 LINE2:temp_out#0000FF:"Outside temperature (avg)" DEF:temp_in=/opt/home/Cluster/tempstats/temp.rrd:temp_in:AVERAGE LINE2:temp_in#00FF00:"Inside temperature (avg)">
<RRD::GRAPH temp3.png --lazy --imgformat PNG --end now
--start end-30d --width 480 --height 400 DEF:temp_out=/opt/home/Cluster/tempstats/temp.rrd:temp_out:AVERAGE CDEF:zero=temp_out,0,* LINE1:zero#000000 LINE2:temp_out#0000FF:"Outside temperature (avg)" DEF:temp_in=/opt/home/Cluster/tempstats/temp.rrd:temp_in:AVERAGE LINE2:temp_in#00FF00:"Inside temperature (avg)">

Генерируются соответственно графики температуры за сутки, за неделю и за месяц. Внешний вид такого графика показан на следующем рисунке.

Рисунок 27 – Внешний вид графика
3. Оценка экономической эффективности проекта
3.1. Определение затрат на разработку проекта
В данном разделе определяется эффективность реализации первого этапа разработки комплекса.
Основными факторами, влияющими на стоимость разработки, являются:
• затраты на оплату труда разработчиков;
• затраты на детали для устройств;
• количество амортизационных отчислений на срок разработки;
• стоимость машинного времени на срок разработки.
Расходы на помещение рассчитываются по формуле:
Зпом = Кпл * Кчел * Дразр * Сар ,
где Зпом - затраты на помещение, руб.;
Кпл — площадь, приходящаяся на одного оператора ПЭВМ, м2/чел.;
Кчел — количество человек, занятых разработкой, чел.;
Дразр — длительность разработки, лет;
Сар — амортизация здания, руб/год*м
Затраты на машинное время рассчитываются по формуле:
Змвр = Скомп * Ккомп * Драз ,
где Змвр — затраты на машинное время, руб.;
Скомп — стоимость машинного времени, руб./год*шт.
Ккомп — количество компьютеров, шт.
Затраты на оплату труда разработчиков рассчитываются по формуле:
Зтр = ЗПразр * Дразр * Кчел ,
где Зтр — затраты на оплату труда разработчиков, руб.;
ЗПразр — зарплата разработчика, руб./год*чел.
При оценке стоимости разработки используются данные представленные в таблице 18.

Таблица 18 - Данные для оценки стоимости разработки
Количество человек, занятых в разработке 1 чел
Длительность разработки:
1 этап
1/4 года
Стоимость оплаты труда разработчика - (включая выплаты) 20 000 руб/мес.
Стоимость аренды одного квадратного метра помещения 1 000 руб./год
Стоимость машинного времени одного компьютера 4 000 руб./год
Площадь, приходящаяся на одного оператора ПВЭМ 3 м2


Таким образом, стоимость разработки составит:
20000 * 12 * ¼ * 1 + 3 * ½ * 1 * 1000 + 4000 * ½ * 1 = 63500
Таким образом, стоимость разработки составляет 63500 рублей.


3.2. Определение затрат на производство
Стоимость производства системы может варьироваться и зависит от следующих факторов:
• используемые компоненты и их цена;
• количество устройств, управление которыми осуществляется;
• количество и тип используемых датчиков;
• платформа, которая будет осуществлять работу ОС «Linux».

В случае использования описанных компонентов общая их стоимость составляет примерно 2000 руб.
В случае использования ротуера ASUS WL-500gP для запуска ОС «Linux» цена платформы составляет 4000 руб.
Стоимость производства макетной платы и сборки составляет около 1000 руб.
Итого: 2000+4000+1000 = 7000 руб.
Стоимость производства комплекса составляет 7000 руб.
4. Безопасность жизнедеятельности
4.1. Санитарно-гигиенические требования при работе с ПЭВМ
В соответствии с СанПиН: 2.2.2.542-96 "Гигиенические требования к ВДТ и ПЭВМ. Организация работы"
Все вредности возникающие при работе ВДТ и ПЭВМ можно разделить на три группы:
• Параметры рабочего места и рабочей зоны
• Визуальные факторы (яркость, контрастность, мерцание изображения, блики)
• Излучения (рентгеновское, электромагнитное излучение ВЧ и СВЧ диапазона, гамма-излучение, электростатические поля)
Внедрение ЭВМ имеет как положительные, так и отрицательные моменты. С одной стороны, это обеспечение более высокой эффективности производства за счет совершенствования технологического процесса и повышение производительности труда, а с другой - увеличение нагрузки на работающих в связи с интенсификацией производственной деятельности и специфическими условиями труда.
Условия труда работающих с ЭВМ характеризуются возможностью воздействия на них следующих производственных факторов: шума, тепловыделений, вредных веществ, статического электричества, ионизирующих и неионизирующих излучений, недостаточной освещенности, параметров технологического оборудования и рабочего места.
Основными источниками шума в помещениях, оборудованных вычислительной техникой, являются принтеры, плоттеры, множительная техника и оборудование для кондиционирования воздуха, вентиляторы систем охлаждения, трансформаторы.
Для снижения шума и вибрации в помещениях вычислительных центров оборудование, аппараты необходимо устанавливать на специальные фундаменты и амортизирующие прокладки, предусмотренные нормативными документами.
Уровень шума на рабочих местах не должен превышать 50 дБА. Нормируемые уровни шума обеспечиваются путем использования малошумного оборудования, применением звукопоглощающих материалов (специальные перфорированные плиты, панели, минераловатные плиты). Кроме того, необходимо использовать подвесные акустические потолки.
В помещениях с избытком тепла необходимо предусматривать регулирование подачи теплоносителя для соблюдения нормативных параметров микроклимата. Микроклиматические условия на рабочих местах в помещениях с вычислительной техникой должны соответствовать требованиям, указанным в таблице 19.
Таблица 19 - Микроклиматические условия
Период года Температура воздуха, oС Скорость движения воздуха, м/с Относительная влажность воздуха, %
Холодный 22-24 до 0,1 40-60
Теплый 23-25 0,1-0,2 40-60

Воздух, поступающий в рабочие помещения операторов ЭВМ, должен быть очищен от загрязнений, в том числе от пыли и микроорганизмов. Патогенной микрофлоры быть не должно.
Кондиционирование воздуха должно обеспечивать поддержание параметров микроклимата в необходимых пределах в течение всех сезонов года, очистку воздуха от пыли и вредных веществ, создание необходимого избыточного давления в чистых помещениях для исключения поступления неочищенного воздуха. Температура подаваемого воздуха должна быть не ниже 19oС.
Температуру в помещении следует регулировать с учетом тепловых потоков от оборудования. Предпочтение должно отдаваться оборудованию с малой электрической мощностью. Оборудование надо устанавливать так, чтобы тепловые потоки от него не были направлены на операторов. Следует также ограничивать количество вычислительной техники в помещении и избегать напольных отопительных систем.
Для предотвращения образования и защиты от статического электричества необходимо использовать нейтрализаторы и увлажнители, а полы должны иметь антистатическое покрытие. Допустимые уровни напряженности электростатических полей не должны превышать 20 кВ в течение 1 часа.
ПЭВМ являются источниками широкополостных электромагнитных излучений:
• мягкого рентгеновского;
• ультрафиолетового 200-400 нм;
• видимого 400-750 нм;
• ближнего ИК 750-2000 нм;
• радиочастотного диапазона 3кГц;
• электростатических полей.
Экспозиционная мощность дозы рентгеновского излучения в любой точке пространства на расстоянии 5 см от поверхности ПЭВМ не должна превышать 7,74•10-12 А/КГ, что соответствует эквивалентной дозе 0,1 мБэр/ч или 100 мкр/ч, согласно санитарным нормам и правилам работы с источниками рентгеновского излучения. Ультрафиолетовое излучение в диапазоне 200-315 нм не должно превышать 10 мкВт/м2, излучение в диапазоне 315-400 нм и видимом диапазоне 400-750 нм -0,1 Вт/м2, в ближнем ИК-диапазоне - 2000нм - 1мм-4 Вт/м2. Уровни напряженности электростатического поля не должны превышать 15 кВ/м.
В целях предосторожности следует обязательно использовать защитные экраны, а также рекомендуется ограничивать продолжительность работы с экраном ВДТ, не размещать их концентрированно в рабочей зоне и выключать их, если на них не работают.
Наряду с этим нужно устанавливать в помещении с ВДТ ионизаторы воздуха, чаще проветривать помещение и хотя бы один раз в течение рабочей смены очищать экран от пыли.
Важное место в комплексе мероприятий по созданию условий труда, работающих с ПЭВМ , занимает создание оптимальной световой среды, т.е. рациональная организация естественного и искусственного освещения помещения и рабочих мест.
Предусматриваются меры ограничения слепящего воздействия светопроемов, имеющих высокую яркость (8000 кд/м2 и более), и прямых солнечных лучей для обеспечения благоприятного распределения светового потока в помещении и исключения на рабочих поверхностях ярких и темных пятен, засветки экранов посторонним светом, а также для снижения теплового эффекта от инсоляции.
Для работы на ЭВМ с ВДТ рекомендуются помещения с односторонним боковым естественным освещением с северной, северо-восточной или северо-западной ориентацией светпроемов. Площадь световых проемов должна составлять 25% площади пола. Удовлетворительное естественное освещение проще создать в небольших помещениях на 5-6 рабочих мест, а больших помещений с числом работающих более 20, лучше избегать. В случае, если экран ПЭВМ обращен к окну, должны быть предусмотрены специальные экранизирующие устройства.
Искусственное освещение в помещениях и на рабочих местах должны создавать хорошую видимость информации на экране ЭВМ. При этом в поле зрения работающих должны быть обеспечены оптимальные соотношения яркости рабочих и окружающих поверхностей. Наиболее оптимальной для работы с экраном является освещенность 200 лк, при работе с экраном в сочетании с работой над документами - 400 лк.
На рабочем месте необходимо обеспечивать возможно большую равномерность яркости, исключая наличие ярких и блестящих предметов, для снижения монотонности в поле зрения рекомендуется отдельные пестрые поверхности.
Для освещения рабочих мест применяется комбинированное освещение (общее плюс местное), хотя более предпочтительно общее освещение из-за большего перепада яркостей на рабочем месте при использовании светильников местного освещения.
Для общего освещения используются в основном потолочные или встроенные светильники с люминесцентными лампами. Яркость должна быть не более 200 кд/м2. Источники света лучше использовать нейтрально-белого или "теплого" белого цвета с индексом цветопередачи не менее 70. Для исключения засветки экранов прямыми световыми потоками светильники общего освещения располагают сбоку от рабочего места, параллельно линии зрения оператора.
Наиболее подходящими светильниками являются светильники типа ЛПО 36, ЛБ, ЛПО 36 с ВУПРА и другие аналогичные. При использовании светильников с люминесцентными лампами необходимо принимать меры по ограничению пульсации освещенности в пределах до 5 %.
Местное освещение на рабочих местах обеспечивается светильниками, устанавливаемыми непосредственно на рабочем столе или на вертикальных панелях специального оборудования. Они должны иметь непросвечивающий отражатель и располагаться ниже или на уровне линии зрения операторов, чтобы не вызывать ослепления.
Так как при работе на компьютере основная нагрузка ложится на глаза, поэтому большие требования предъявляются к видеотерминальным устройствам (экранам). Предпочтительным является плоский экран, позволяющий избежать наличие на нем ярких пятен за счет отражения световых потоков. Особенно важен цвет экрана. Он должен быть нейтральным. Допустимы ненасыщенные светло-зеленые, желто-зеленые, желто-оранжевые, желто-коричневые тона.
О качестве экранов судят по отсутствию мерцания и постоянству яркости. При прямом контрасте (темные символы на светлом фоне) частота мельканий должна быть не менее 80Гц. Оптимальная высота расположения экрана должна соответствовать направлению взгляда оператора в секторе 5-35o по отношению к горизонтали. Большой наклон экрана может привести к появлению бликов от светильников. При работе с ЭВМ взгляд должен падать на экран под прямым углом и отклоняться от горизонтали на 20o.
Условия зрительного восприятия информации на экране зависят от параметров экрана, плотности их размещения, контраста и соотношения яркостей символов и фона экрана.
Видеотерминальное устройство должно отвечать следующим техническим требованиям:
• яркость свечения экрана - не менее 100 кд/м2;
• минимальный размер светящейся точки - не более 0,4 мм для монохромного дисплея и не более 0,6 мм - для цветного;
• контрастность изображения знака - не менее 0,8;
• частота регистрации изображения при работе с позитивным контрастом в режиме обработки текста - не менее 72 Гц;
• количество точек на строке - не менее 640;
• низкочастотное дрожание изображения в диапазоне 0,05-1,0 Гц должно находиться в пределах 0,1 мм;
• экран должен иметь антибликовое покрытие;
• размер экрана должен быть не менее 31 см по диагонали, а высота символов на экране не менее 3,8 мм, при этом расстояние от газ оператора до экрана должно быть в пределах 40-80 см.
Клавиатура дисплея не должна быть жестко связана с монитором. Она должна располагаться на расстоянии 600-700 мм. В клавиатуре необходимо предусмотреть возможность звуковой обратной связи от включения клавиш с возможностью регулировки. Размер клавиш - в пределах 13-15 мм, сопротивление - 0,25-1,5 Н. Поверхность клавиш должна быть вогнутой, расстояние между ними - не менее 3мм. Наклон клавиатуры должен находиться в пределах 10-15o. Клавиатура располагается на поверхности стола на расстоянии 100-300 мм от края.
Видеомонитор должен быть оборудован поворотной площадкой, позволяющей перемещать ВДТ в горизонтальной и вертикальной плоскостях в пределах 130-220 мм и изменять угол наклона экрана на ╠ 30o во фронтальной плоскости.
При работе с текстовой информацией (в режиме ввода данных, редактирования текста и чтения с экрана ВДТ) наиболее физиологичным является предъявление черных знаков на светлом фоне.
При расстоянии от глаз до экрана - 600-700 мм, высота знака должна быть не менее 3-4 мм, расстояние между знаками - 15-20; от его высоты. Количество точек на строке - не менее 640.
Яркость символов на экране должна согласовываться с яркостью фона экрана и окружающим освещением. Нижней границей уровня яркости светящихся символов считается 30 кд/м2, верхняя определяется значением слепящей яркости. При прямом контрасте яркостный контраст должен составлять 75-80% с возможностью регулировки яркости фона экрана, а при обратном контрасте (светлые символы на темном фоне) - 85-90% с возможностью регулировки яркости фона экрана. Коэффициент контрастности символов на экране при их оптимальных размерах считается благоприятным в пределах 5-10 для обратного контраста и в пределах 8-12 - для прямого.
Для устранения бликов и снижения влияния электромагнитного излучения экраны ВДТ должны быть снабжены защитными фильтрами.

4.2. Требования к оборудованию рабочих мест
Рабочий стол должен регулироваться по высоте в пределах 680-800 мм; при отсутствии такой возможности его высота должна составлять 725 мм. Оптимальные размеры рабочей поверхности столешницы - 1400х1000 мм. Под столешницей рабочего стола должно быть свободное пространство для ног с размером по высоте не менее 600 мм, по ширине - 500 мм, по глубине - 650 мм. На поверхности рабочего стола для документов необходимо предусматривать размещение специальной подставки, расстояние которой от глаз должно быть аналогично расстоянию от глаз до клавиатуры, что позволяет снизить зрительное утомление.
Рабочий стул (кресло) должен быть снабжен подъемно-поворотным устройством, обеспечивающим регуляцию высоты сидений и спинки; его конструкция должна предусматривать также изменение угла наклона спинки. Рабочее кресло должно иметь подлокотники.
Регулировка каждого параметра должна легко осуществляться, быть независимой и иметь надежную фиксацию. Высота поверхности сидения должна регулироваться в пределах 400-500 мм. Ширина и глубина сиденья должна составлять не менее 400 мм.
Высота опорной поверхности спинки должна быть не менее 300 мм, ширина - не менее 380мм. Радиус ее кривизны в горизонтальной плоскости - 400 мм. Угол наклона спинки должен изменяться в пределах 90-110o к плоскости сиденья. Материал покрытия рабочего стула должен обеспечивать возможность легкой очистки от загрязнения. Поверхность сиденья и спинки должна быть полумягкой, с нескользящим, не электризующим и воздухопроницаемым покрытием.
На рабочем месте необходимо предусматривать подставку для ног. Ее длина должна составлять 400 мм ширина - 300 мм. Необходимо предусматривать регулировку высоты в пределах от 0 - 150 мм и угла её наклона в пределах 0 - 200. Она должна иметь рифленое покрытие и бортик высотой 10 мм по нижнему краю.
Режим труда и отдыха при работе с ПЭВМ и ВДТ должен организовываться в зависимости от вида и категории деятельности.
Виды деятельности подразделяются на следующие группы:
• группа А - работа по считыванию информации с ВДТ или ПЭВМ с предварительным запросом;
• группа Б - работа по вводу информации;
• группа В - творческая работа в режиме диалога.
Для видов деятельности устанавливаются три категории (I, II, III) тяжести и напряженности работы с ПЭВМ и ВДТ
Время непрерывной работы для I кат. - 2 часа; для II и III категории 1,5-2 часа. Сумма времени регламентированных перерывов при 8 - часовом рабочем дне составляет для I кат. - 30 мин.; для II кат. - 50 мин.; для III кат. - 70 мин.
Режим труда и отдыха операторов, работающих с ЭВМ, должен быть следующим: через каждый час интенсивной работы необходимо устраивать 15 - минутный перерыв, при менее интенсивной через каждые 2 - часа. Эффективность регламентируемых перерывов повышается при их сочетании с производственной гимнастикой. Производственная гимнастика должна включать комплекс упражнений, направленных на восполнение дефицита двигательной активности, снятие напряжения мышц шеи, спины, снижение утомления зрения. Она проводится в течение 5 - 7 мин. 1 - 2 раза в смену.
При профессиональном отборе работников ЭВМ основное внимание обращается на состояние органов зрения: состояния мышечного равновесия глаз, положительный запас аккомодации, цветовую чувствительность, остроту зрения, рефракционную способность глаз, контрастную чувствительность и поле зрения.

Заключение
В дипломной работе разработан программно-аппаратный комплекс позволяющий удалённо производить управление бытовой техникой, а также вести контроль за помещением.
В рамках дипломного проекта было проведено:
• исследование и анализ предметной области;
• исследование и анализ электронных компонентов;
• исследование протоколов взаимодействия;
• разработка микропрограммы для микроконтроллера AVR;
• разработка серверного программного обеспечения для ОС «Linux»;
• разработка клиентского программного обеспечения;
• согласование различных элементов комплекса.
В проекте также содержится экономическое обоснование разработки и рекомендации по охране труда с учетом требований эргономики.

Список источников информации
1. Арнольд Роббинс: Linux, программирование в примерах. Москва: издательство «Кудиц-образ», 2006.
2. Пауло Франка: C++, учебный курс. Москва: издательский дом «Питер», 2003.
3. П. Хоровиц, У. Хилл: Искусство схемотехники. Мир, 2006.
4. Юкио Сато: Обработка сигналов, первое знакомство. Додэка, 2002.
5. Официальная техническая документация Atmel, 2007.
6. Б С. Послед: Borland C++ Builder 6. Разработка приложений баз данных. Москва: ДиаСофтЮП, 2003.
7. Сергей Сабуров: Языки программирования C и C++. Москва: издательский дом «Питер», 2006.
8. Стефан Р. Дэвис: C++ Для чайников. Москва: издательский дом «Питер», 2007.
9. А. П. Побегайло: Системное программирование в Windows. СПб.: «БХВ-Петербург», 2006.
10. А.В. Петюшкин: HTML. Экспресс-курс. СПб.: «БХВ-Петербург», 2003.
11. Алексей Гончаров: Самоучитель HTML. Москва: издательский дом «Питер», 2000.

Приложение А
#include "defines.h"
#define TicsPerSec 3899
#define PC_LCD_TIMEOUT 30
#define NOPC_LCD_TIMEOUT 30
#define NOTICE_TIME 3000
#define TIMER_TIME 60
#define MENU_TIMEOUT 5000
#define ENABLED_DEVICES 0b0011111
#define LIGHT_DEVICES 0b0000111
#define DEVICE_NAME_1 "Левая лампа"
#define DEVICE_NAME_2 "Правая лампа"
#define DEVICE_NAME_3 "Люстра"
#define DEVICE_NAME_4 "Спец. розетка #1"
#define DEVICE_NAME_5 "Спец. розетка #2"
#define MOTION_TIME_UNTIL_REBOOT 600
#define MOTION_TIMEOUT 180
#define MOTION_SSAVER_TIMEOUT 120
#define IGNORERC_TIMEOUT 90

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
#include "lcd.h"
#include "hd44780.h"
#include "usart.h"
#include "tsopir.h"
#include "ds1820.h"

volatile unsigned short int time_tics = 0;
volatile unsigned short int time_secs = 0;
volatile unsigned short int time_mins = 0;
volatile unsigned short int time_hours = 0;
unsigned short int time_is_set = 0;
unsigned short int time_lastmin = 61;
unsigned short int time_lastsec = 61;
char DS1820_temp1[6];
char DS1820_temp2[6];
unsigned char command_state = 0;
unsigned char command_pluscount = 0;
unsigned char command_num = 0;
unsigned char command_len = 0;
unsigned char command_buf[64];
unsigned char command_complete = 0;
unsigned char PC_lcd[48];
unsigned short int PC_lcd_timeout = 0;
unsigned short int NOPC_lcd_timeout = 0;
unsigned short int Timer_timeout = 0;
unsigned short int IgnoreRC_timeout = 0;
unsigned int Notice_timeout = 0;
unsigned short int Button_Newpress = 0;
unsigned short int Button_NewpressOld = 0xFF;
unsigned long int RC_Button_Newpress = 0;
unsigned long int RC_Buttons[8];
unsigned long int RC_DeviceButtonsOn[5];
unsigned long int RC_DeviceButtonsOff[5];
unsigned int Motion_WorkTime = 0;
unsigned int Motion_NoMotionTime = 0;
unsigned char Motion_Exists = 1;
unsigned int Motion_SSaverTimeout = 0;
unsigned char Motion_Enabled = 1;
unsigned char pacdir;

short int DevicesState = 0;
const short int EnabledDevices = ENABLED_DEVICES;
const short int LightDevices= LIGHT_DEVICES;
char DeviceName1[] PROGMEM = DEVICE_NAME_1;
char DeviceName2[] PROGMEM = DEVICE_NAME_2;
char DeviceName3[] PROGMEM = DEVICE_NAME_3;
char DeviceName4[] PROGMEM = DEVICE_NAME_4;
char DeviceName5[] PROGMEM = DEVICE_NAME_5;

ISR(USART_RXC_vect)
{
unsigned char b;
while (UCSRA & (1<<RXC))
{
b = UDR;
if (b == '+')
{
command_pluscount++;
if (command_pluscount >= 3)
{
command_state = 1;
command_pluscount = 0;
}
} else command_pluscount = 0;
switch (command_state)
{
case 1: command_state = 2; break;
case 2:
command_state = 3;
command_num = b;
command_len = 0;
command_complete = 0;
break;
case 3:
if (command_len < 64)
{
command_buf[command_len] = b;
command_len++;
}
if (
((command_num == 1) && (command_len >= 3 )) ||
(command_num == 2) ||
((command_num == 3) && (command_len >= 48 )) ||
(command_num == 4) ||
((command_num == 5) && (command_len >= 48 )) ||
((command_num == 6) && (command_len >= 2 )) ||
(command_num == 7) ||
(command_num == 8) ||
(command_num == 9)
) command_complete = 1;
break;
}
}
}

ISR(TIMER1_COMPA_vect)
{
TSOP_Check();
time_tics++;
if (time_tics >= TicsPerSec)
{
time_tics = 0;
time_secs++;
}
if (time_secs >= 60)
{
time_secs = 0;
time_mins++;
}
if (time_mins >= 60)
{
time_mins = 0;
time_hours++;
}
if (time_hours >= 24) time_hours = 0;
}

//FILE lcd_str = FDEV_SETUP_STREAM(lcd_putchar, NULL, _FDEV_SETUP_WRITE);

void timer_init()
{
// Устанавливаем прерывания
TIMSK = 1 << OCIE1A;
// Обнуляем таймер
TCNT1=0;
// Максимальное значение для таймера
// OCR1A = 0x1000;
OCR1A = 0x800;
// Параметры таймера - перскалер, режим, верхний лемит...
TCCR1B = (1 << CS10) | (1 << WGM12);
// Включаем прерывания
sei();
}

void CommandToPC(unsigned char commnum)
{
USART_TransmitText("+++");
USART_TransmitByte(commnum);
}


char Text_Loading[] PROGMEM = " Cluster Control v2.1\n Пожалуйста подождите...";
char Text_Version[] PROGMEM = "Cluster Control v2.1";

void SetFont()
{
hd44780_wait_ready();
hd44780_outcmd(HD44780_CGADDR(0x0008));
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00001110);
hd44780_wait_ready();
hd44780_outdata(0b00011111);
hd44780_wait_ready();
hd44780_outdata(0b00011111);
hd44780_wait_ready();
hd44780_outdata(0b00011111);
hd44780_wait_ready();
hd44780_outdata(0b00011111);
hd44780_wait_ready();
hd44780_outdata(0b00001110);
hd44780_wait_ready();
hd44780_outdata(0b00000000);

hd44780_wait_ready();
hd44780_outcmd(HD44780_CGADDR(0x0010));
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00001110);
hd44780_wait_ready();
hd44780_outdata(0b00011111);
hd44780_wait_ready();
hd44780_outdata(0b00011100);
hd44780_wait_ready();
hd44780_outdata(0b00011100);
hd44780_wait_ready();
hd44780_outdata(0b00011111);
hd44780_wait_ready();
hd44780_outdata(0b00001110);
hd44780_wait_ready();
hd44780_outdata(0b00000000);

hd44780_wait_ready();
hd44780_outcmd(HD44780_CGADDR(0x0018));
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00001110);
hd44780_wait_ready();
hd44780_outdata(0b00011100);
hd44780_wait_ready();
hd44780_outdata(0b00011000);
hd44780_wait_ready();
hd44780_outdata(0b00011000);
hd44780_wait_ready();
hd44780_outdata(0b00011100);
hd44780_wait_ready();
hd44780_outdata(0b00001110);
hd44780_wait_ready();
hd44780_outdata(0b00000000);

hd44780_wait_ready();
hd44780_outcmd(HD44780_CGADDR(0x0020));
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00001100);
hd44780_wait_ready();
hd44780_outdata(0b00011000);
hd44780_wait_ready();
hd44780_outdata(0b00011000);
hd44780_wait_ready();
hd44780_outdata(0b00011000);
hd44780_wait_ready();
hd44780_outdata(0b00011000);
hd44780_wait_ready();
hd44780_outdata(0b00001100);
hd44780_wait_ready();
hd44780_outdata(0b00000000);

hd44780_wait_ready();
hd44780_outcmd(HD44780_CGADDR(0x0028));
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00001100);
hd44780_wait_ready();
hd44780_outdata(0b00001100);
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00000000);
hd44780_wait_ready();
hd44780_outdata(0b00000000);
}

void main_init()
{
lcd_init();
SetFont();
lcd_newscreen();
lcd_print_pgm(Text_Loading);
lcd_update();
USART_init();
TSOP_Init(0x20, 2, 0x200);
DS1820_Update();
DS1820_GetTemp(0, DS1820_temp1);
DS1820_GetTemp(1, DS1820_temp2);
DDRB = 0;
PORTB = 0xFF;
DDRC = 0xFF;
DDRD &= 0b00000000;
PORTD &= 0b10000000;
eeprom_read_block((void*)RC_Buttons, (void*)0, 4*8); // Кнопки ПДУ
DevicesState = eeprom_read_byte((void*)0x20); // Состояния девайсов
eeprom_read_block((void*)RC_DeviceButtonsOn, (void*)0x21, 4*5); // Кнопки ПДУ для девайсов
eeprom_read_block((void*)RC_DeviceButtonsOff, (void*)0x35, 4*5);

/*
// UART test
int les;
PORTC = 0b00011111;
while (1)
for (les = 0; les < 256; les++)
{
lcd_newscreen();
lcd_printnum(les, 3);
lcd_update();
USART_TransmitByte(les);
_delay_ms(100);
}
*/

PORTC = 0b00011111 & DevicesState & EnabledDevices;
timer_init();
WDTCR = (1<<WDE) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0); // Watchdog
CommandToPC(1); // Запуск!
USART_TransmitByte(0);
}

char DeviceModeOn[] PROGMEM = "Устройство включено";
char DeviceModeOff[] PROGMEM = "Устройство выключено";

void UpdateDevices()
{
PORTC = (PORTC & 0b11100000) | (DevicesState & EnabledDevices & 0b00011111 & (Motion_Exists ? 0b00011111 : (Motion_Enabled ? ~LIGHT_DEVICES : 0b00011111)));
DevicesState &= EnabledDevices & 0b00011111;
eeprom_write_byte((void*)0x20, DevicesState);
CommandToPC(6); // Текущее состояние девайсов
USART_TransmitByte(DevicesState);
}

void DeviceMode(short int device, short int state)
{
if (state)
{
Motion_Exists = 1;
Motion_NoMotionTime = 0;
}
if (!((EnabledDevices >> device) & 1)) return;
if (((DevicesState >> device) & 1) != (state & 1))
{
lcd_newscreen();
switch (device)
{
case 0: lcd_print_pgm_center(DeviceName1, 0); break;
case 1: lcd_print_pgm_center(DeviceName2, 0); break;
case 2: lcd_print_pgm_center(DeviceName3, 0); break;
case 3: lcd_print_pgm_center(DeviceName4, 0); break;
case 4: lcd_print_pgm_center(DeviceName5, 0); break;
}

if (state)
{
DevicesState |= 1 << device;
lcd_print_pgm_center(DeviceModeOn, 1);
} else {
DevicesState &= ~(1 << device);
lcd_print_pgm_center(DeviceModeOff, 1);
}
lcd_update();
Notice_timeout = NOTICE_TIME;
}
UpdateDevices();
}

void ExecCommand()
{
unsigned short int i, i2;
switch (command_num)
{
case 1:
time_hours = command_buf[0]; // 1 - Синхронизация времени (3 байта)
time_mins = command_buf[1];
time_secs = command_buf[2];
time_tics = 0;
time_is_set = 1;
break;
case 2: // 2 - Обновление данных (1 байт, любой)
CommandToPC(7); // 7 - Список доступных девайсов - 1 байт
USART_TransmitByte(EnabledDevices);
for (i = 0; i < 5; i++)
{
CommandToPC(8); // 8 - Названия девайсов - 1 + 22 байта
USART_TransmitByte(i);
int eol = 0;
for (i2 = 0; i2 < 22; i2++)
{
char* DName = 0;
switch (i)
{
case 0: DName = DeviceName1; break;
case 1: DName = DeviceName2; break;
case 2: DName = DeviceName3; break;
case 3: DName = DeviceName4; break;
case 4: DName = DeviceName5; break;
}
char c = pgm_read_byte(&DName[i2]);
if (!c) eol = 1;
if (!eol) USART_TransmitByte(c); else USART_TransmitByte(0);
}
}
UpdateDevices();
CommandToPC(2); // Температура
USART_Transmit(DS1820_GetRawTemp(), 4);
CommandToPC(9); // Движение
USART_TransmitByte(Motion_Exists);
break;
case 3: // 3 - Вывод текста на дисплей (48 байт)
for (i = 0; i < 48; i++) PC_lcd[i] = RusEncode(command_buf[i]);
PC_lcd_timeout = PC_LCD_TIMEOUT;
break;
case 4: // 4 - Выход из PC режима (1 байт, любой)
PC_lcd_timeout = 0;
break;
case 5: // 5 - Вывод нотиса на дисплей (48 байт)
lcd_newscreen();
for (i = 0; i < 24; i++) lcd_putchar(command_buf[i]);
lcd_putchar('\n');
for (i = 24; i < 48; i++) lcd_putchar(command_buf[i]);
lcd_update();
Notice_timeout = NOTICE_TIME;
break;
case 6: // Включение/выключение устройства (1 байт - номер устройства и 1 - команда)
DeviceMode(command_buf[0], command_buf[1]);
break;
case 7: // Комп говорит, что я сижу за компом, т.е. свет не вырубать! (1 байт, любой)
Motion_SSaverTimeout = MOTION_SSAVER_TIMEOUT;
break;
case 8: // Комп говорит, что надо игнорировать кнопки управления самим девайсом, отдадим их под софт на PC (1 байт, любой);
IgnoreRC_timeout = IGNORERC_TIMEOUT;
break;
case 9: // Комп говорит, что уже НЕ надо игнорировать кнопки управления самим девайсом, отдадим их под софт на PC (1 байт, любой);
IgnoreRC_timeout = 0;
break;
}
command_complete = 0;
command_state = 0;
}

void MainUpdate(char mode)
{
wdt_reset();
unsigned char b;
unsigned long RC_Button;
RC_Button_Newpress = TSOP_GetNewpress(); // Не нажата ли кнопка на ПДУ?
if (RC_Button_Newpress > 0)
{
CommandToPC(4); // Нажата кнопка на ПДУ
USART_Transmit((void*)&RC_Button_Newpress, 4); // Шлём её на комп
}
RC_Button = TSOP_GetRepeat(); // А может ЗАжата?
if ((TSOP_GetButton() == 1) && (RC_Button > 0))
{
CommandToPC(5); // Держится кнопка на ПДУ
USART_Transmit((void*)&RC_Button, 4);
}
Button_Newpress = 0;
for (b = 0; b < 7; b++) // Читаем кнопки
{
if ((((PINB>>b) & 1) == 0) && (((Button_NewpressOld>>b) & 1) == 1))
Button_Newpress = b + 1;
if ((IgnoreRC_timeout == 0) && (RC_Button_Newpress > 0) && (RC_Button_Newpress == RC_Buttons[b])) Button_Newpress = b + 1;
}
if ((IgnoreRC_timeout == 0) && (RC_Button_Newpress > 0) && (RC_Button_Newpress == RC_Buttons[7])) Button_Newpress = 6; // Дублируем кнопку OK
Button_NewpressOld = PINB;
for (b = 0; b < 5; b++) // Что-то включаем?
{
if ((RC_Button_Newpress > 0) && (RC_Button_Newpress == RC_DeviceButtonsOn[b])) DeviceMode(b, 1);
if ((RC_Button_Newpress > 0) && (RC_Button_Newpress == RC_DeviceButtonsOff[b])) DeviceMode(b, 0);
}

if ((time_mins != time_lastmin) || ((time_secs == 30) && (time_secs != time_lastsec)))
{
DS1820_Update();
DS1820_GetTemp(0, DS1820_temp1);
DS1820_GetTemp(1, DS1820_temp2);
time_lastmin = time_mins;
}
if ((time_secs == 30) && (time_secs != time_lastsec)) // Каждую минуту шлём на комп температуру
{
CommandToPC(2); // Температура
USART_Transmit(DS1820_GetRawTemp(), 4);
UpdateDevices(); // И состояние девайсов...
CommandToPC(9); // Движение
USART_TransmitByte(Motion_Exists);
}
if (time_secs != time_lastsec) // Счётчики
{
time_lastsec = time_secs;
if (PC_lcd_timeout > 0) PC_lcd_timeout--;
if (NOPC_lcd_timeout > 0) NOPC_lcd_timeout--;
if (IgnoreRC_timeout > 0) IgnoreRC_timeout--;
if (Timer_timeout > 0)
{
Timer_timeout--;
if (Timer_timeout == 0)
{
DevicesState &= ~LightDevices;
UpdateDevices();
}
}
if (Motion_WorkTime < 30000) Motion_WorkTime++;
if (Motion_NoMotionTime < 30000) Motion_NoMotionTime++;
if (Motion_WorkTime < 3) PORTC &= 0b10111111; // Выключаем датчик движения
if (Motion_WorkTime == 3) PORTC |= 0b01000000; // Включаем
if (Motion_Exists && (Motion_NoMotionTime >= MOTION_TIMEOUT) && (Motion_SSaverTimeout == 0)) // Нет движения тут!
{
Motion_Exists = 0;
UpdateDevices();
CommandToPC(9); // Движение
USART_TransmitByte(0);
}
if (Motion_SSaverTimeout > 0) Motion_SSaverTimeout--;
}
if (Notice_timeout > 0) Notice_timeout--;

if (command_complete) ExecCommand(); // Выполняем команду от компа, если нужно
if (mode || (PC_lcd_timeout == 0) || (NOPC_lcd_timeout > 0)) // Какой режим?
{
if (Notice_timeout == 0) lcd_update();
if ((Button_Newpress == 1) && (mode == 0)) NOPC_lcd_timeout = 0;
if (Button_Newpress > 1) NOPC_lcd_timeout = NOPC_LCD_TIMEOUT;
} else {
if (Notice_timeout == 0) lcd_spec_update(PC_lcd);
if (Button_Newpress == 1) NOPC_lcd_timeout = NOPC_LCD_TIMEOUT;
if (Button_Newpress > 1)
{
CommandToPC(3); // Нажали кнопку
USART_Transmit((void*)&Button_Newpress, 1);
}
Button_Newpress = 0;
}

if ((PIND >> 7) || (!Motion_Enabled))
{
if (!Motion_Exists)
{
Motion_Exists = 1;
UpdateDevices();
CommandToPC(9); // Движение
USART_TransmitByte(1);
}
Motion_NoMotionTime = 0;
if (Motion_WorkTime >= MOTION_TIME_UNTIL_REBOOT) Motion_WorkTime = 0;
}
// if (!Motion_Exists && (time_secs % 2 == 0)) PORTC |= (1 << 7);
}


char Text_Temp1[] PROGMEM = "Темп-ра на улице: ";
char Text_Temp2[] PROGMEM = "Темп-ра в комнате: ";
char Text_TimerOn[] PROGMEM = "Активирован таймер";
char Text_TimerLeft[] PROGMEM = "\n Осталось ";
char Text_TimerLeft2[] PROGMEM = " секунд";

int glukipause(unsigned long c)
{
unsigned long int i;
for (i = 0; i < c; i++)
{
MainUpdate(0);
if (Button_Newpress > 2) return 1;
}
return 0;
}

char Text_GlukiFace1[] PROGMEM = "=O.o=";
char Text_GlukiFace2[] PROGMEM = "=o.O=";
char Text_GlukiFace3[] PROGMEM = "=0.o=";
char Text_GlukiFace4[] PROGMEM = "=o.0=";
char Text_GlukiFace5[] PROGMEM = "=O.0=";
char Text_GlukiFace6[] PROGMEM = "=^_^=";
char Text_GlukiFace7[] PROGMEM = "=O_o=";
char Text_GlukiCC[] PROGMEM = "Cluster Control";
char Text_GlukiCC2[] PROGMEM = "Йа Кластер Контролко!";
char Text_GlukiPreved[] PROGMEM = "Превед медвед!";
char Text_GlukiPreved2[] PROGMEM = "Я кластерное чудо!";
char Text_GlukiRobot1[] PROGMEM = "Убить всех людей!";
char Text_GlukiRobot2[] PROGMEM = "Слава роботам";
char Text_GlukiLost[] PROGMEM = ">: 4 8 15 16 23 42 ";
char Text_GlukiBase[] PROGMEM = "All your base are belong to us!";

inline int gluki(int type) // :))
{
char* Faces[5] = {Text_GlukiFace1, Text_GlukiFace2, Text_GlukiFace3, Text_GlukiFace4, Text_GlukiFace5};
int i;
switch (type)
{
case 0:
for (i = 0; i < 5; i++)
{
lcd_newscreen();
lcd_print_pgm(Faces[rand()%5]);
lcd_goto(10, 0);
lcd_print_pgm(Faces[rand()%5]);
lcd_goto(19, 0);
lcd_print_pgm(Faces[rand()%5]);
lcd_goto(4, 1);
lcd_print_pgm(Faces[rand()%5]);
lcd_goto(16, 1);
lcd_print_pgm(Faces[rand()%5]);
if (glukipause(50)) return 1;
}
lcd_newscreen();
lcd_print_pgm_center(Text_GlukiCC, 0);
lcd_print_pgm_center(Text_GlukiFace6, 1);
if (glukipause(300)) return 1;
break;
case 1:
lcd_newscreen();
lcd_print_pgm_center(Text_GlukiCC2, 0);
lcd_print_pgm_center(Text_GlukiFace7, 1);
if (glukipause(300)) return 1;
break;
case 2:
lcd_newscreen();
lcd_print_pgm_center(Text_GlukiPreved, 0);
lcd_print_pgm_center(Text_GlukiPreved2, 1);
if (glukipause(300)) return 1;
break;
case 3:
lcd_newscreen();
lcd_print_pgm_center(Text_GlukiRobot1, 0);
lcd_print_pgm_center(Text_GlukiRobot2, 1);
if (glukipause(300)) return 1;
break;
case 4:
for (i = 0; i < 3; i++)
{
lcd_newscreen();
lcd_print_pgm(Text_GlukiLost);
if (glukipause(200)) return 1;
lcd_newscreen();
lcd_print_pgm(Text_GlukiLost);
lcd_putchar('\\');
if (glukipause(200)) return 1;
}
break;
}
return 0;
}

unsigned char nextframe(unsigned char pacman)
{
if (pacdir) pacman++; else pacman--;
if (pacman == 4) pacdir = 0;
if (pacman == 1) pacdir = 1;
return pacman;
}

char Text_Time[] PROGMEM = "А у нас сейчас: ";
char Text_TimeIsNotSet[] PROGMEM = " Время не установлено ";

inline void main_idle()
{
const char separator = ':';
unsigned long int i, c, c2, c3;
unsigned char pacman;
int glukitype = 0;

while (Timer_timeout > 0)
{
lcd_newscreen();
lcd_print_pgm_center(Text_TimerOn, 0);
lcd_print_pgm(Text_TimerLeft);
lcd_printnum(Timer_timeout, 2);
lcd_print_pgm(Text_TimerLeft2);
MainUpdate(0);
if (Button_Newpress > 2) return;
}

while (1)
{
pacman = 1;
pacdir = 1;

for (c = 0; c <= 23; c++)
{
for (c2 = 0; c2 < 6; c2++)
{
pacman = nextframe(pacman);
lcd_newscreen();
lcd_goto(c,1);
lcd_putchar(pacman);
for (c3 = c+1; c3 <= 23; c3++) lcd_putchar(5);

if ((c / 3) % 4 <= 1)
{
if (time_is_set)
{
lcd_goto(0, 0);
lcd_print_pgm(Text_Time);
lcd_printnum(time_hours, 2);
lcd_putchar(separator);
lcd_printnum(time_mins, 2);
lcd_putchar(separator);
lcd_printnum(time_secs, 2);
} else lcd_print_pgm_center(Text_TimeIsNotSet, 0);
} else
if ((c / 3) % 4 == 2)
{
lcd_goto(0, 0);
lcd_print_pgm(Text_Temp1);
if (strlen(DS1820_temp1) < 5) lcd_putchar(' ');
lcd_print(DS1820_temp1);
} else
if ((c / 3) % 4 == 3)
{
lcd_goto(0, 0);
lcd_print_pgm(Text_Temp2);
if (strlen(DS1820_temp2) < 5) lcd_putchar(' ');
lcd_print(DS1820_temp2);
}
/*
else {
lcd_print_pgm_center(Text_Version, 0);
}
*/

for (i = 0; i < 30; i++)
{
MainUpdate(0);
if (Button_Newpress > 2) return;
}
}
}
if (gluki(glukitype)) return;
glukitype++;
if (glukitype > 4) glukitype = 0;
}

}

char Text_DevicesMenuOff[] PROGMEM = "выкл";
char Text_DevicesMenuOn[] PROGMEM = "вкл";
char Text_DevicesMenuOFF[] PROGMEM = "ВЫКЛЮЧЕНО";
char Text_DevicesMenuON[] PROGMEM = "ВКЛЮЧЕНО";

inline int devices_menu()
{
const short int ItemsCount = 5;
short int CurItem = 0;
unsigned long int MenuTimeout = 0;

while (Button_Newpress != 2)
{
lcd_newscreen();
lcd_putchar('<'); lcd_goto(23, 0); lcd_putchar('>');
lcd_goto(1, 0);
if (CurItem >= ItemsCount) CurItem = 0;
while (!((EnabledDevices >> CurItem) & 1))
{
CurItem++;
if (CurItem >= ItemsCount) CurItem = 0;
}
switch (CurItem)
{
case 0: lcd_print_pgm_center(DeviceName1, 0); break;
case 1: lcd_print_pgm_center(DeviceName2, 0); break;
case 2: lcd_print_pgm_center(DeviceName3, 0); break;
case 3: lcd_print_pgm_center(DeviceName4, 0); break;
case 4: lcd_print_pgm_center(DeviceName5, 0); break;
}
lcd_goto(0, 1);
lcd_print_pgm(Text_DevicesMenuOff);
lcd_goto(21, 1);
lcd_print_pgm(Text_DevicesMenuOn);
if ((DevicesState >> CurItem) & 1) lcd_print_pgm_center(Text_DevicesMenuON, 1); else lcd_print_pgm_center(Text_DevicesMenuOFF, 1);
MainUpdate(1);
if (Button_Newpress == 3)
{
CurItem--;
if (CurItem < 0) CurItem = ItemsCount - 1;
while (!((EnabledDevices >> CurItem) & 1))
{
CurItem--;
if (CurItem < 0) CurItem = ItemsCount - 1;
}
}
if (Button_Newpress == 4) CurItem++;
if (Button_Newpress == 5) DeviceMode(CurItem, 0);
if (Button_Newpress == 7) DeviceMode(CurItem, 1);
if (Button_Newpress > 0) MenuTimeout = 0;
MenuTimeout++;
if (MenuTimeout > MENU_TIMEOUT) return 1;
}
return 0;
}

char Text_RC_SettingsMenu[] PROGMEM = " Настройка ПДУ\n< >";
char Text_RC_SettingsMenu1[] PROGMEM = "Основные кнопки";
char Text_RC_SettingsMenu2[] PROGMEM = "Включающие кнопки";
char Text_RC_SettingsPress[] PROGMEM = "Жми на пульте кнопку\n";
char Text_RC_SettingsPress1[] PROGMEM = "режим";
char Text_RC_SettingsPress2[] PROGMEM = "назад";
char Text_RC_SettingsPress3[] PROGMEM = "влево";
char Text_RC_SettingsPress4[] PROGMEM = "вправо";
char Text_RC_SettingsPress5[] PROGMEM = "вниз-влево";
char Text_RC_SettingsPress6[] PROGMEM = "OK";
char Text_RC_SettingsPress7[] PROGMEM = "вниз-вправо";
char Text_RC_SettingsPress8[] PROGMEM = "вниз";
char Text_RC_SettingsPressOk[] PROGMEM = " - ";
char Text_RC_SettingsPressOn[] PROGMEM = "Жми кнопку включения\n";
char Text_RC_SettingsPressOff[] PROGMEM = "Жми кнопку выключения\n";

inline void RC_settings_menu()
{
const short int ItemsCount = 2;
short int CurItem = 0;
unsigned long int MenuTimeout = 0;

while (Button_Newpress != 2)
{
lcd_newscreen();
lcd_print_pgm(Text_RC_SettingsMenu);
lcd_goto(1, 1);
switch (CurItem)
{
case 0: lcd_print_pgm_center(Text_RC_SettingsMenu1, 1); break;
case 1: lcd_print_pgm_center(Text_RC_SettingsMenu2, 1); break;
}
MainUpdate(1);
if (Button_Newpress == 3) CurItem--;
if (Button_Newpress == 4) CurItem++;
if (CurItem < 0) CurItem = ItemsCount - 1;
if (CurItem >= ItemsCount) CurItem = 0;
if (Button_Newpress > 0) MenuTimeout = 0;
if (Button_Newpress > 4)
{
int i;
switch (CurItem)
{
case 0:
for (i = 0; i < 8; i++) RC_Buttons[i] = 0;
for (i = 0; i < 8; i++)
{
do {
lcd_newscreen();
lcd_print_pgm(Text_RC_SettingsPress);
switch (i)
{
case 0: lcd_print_pgm(Text_RC_SettingsPress1); break;
case 1: lcd_print_pgm(Text_RC_SettingsPress2); break;
case 2: lcd_print_pgm(Text_RC_SettingsPress3); break;
case 3: lcd_print_pgm(Text_RC_SettingsPress4); break;
case 4: lcd_print_pgm(Text_RC_SettingsPress5); break;
case 5: lcd_print_pgm(Text_RC_SettingsPress6); break;
case 6: lcd_print_pgm(Text_RC_SettingsPress7); break;
case 7: lcd_print_pgm(Text_RC_SettingsPress8); break;
}
MainUpdate(1);
} while (RC_Button_Newpress == 0);
RC_Buttons[i] = RC_Button_Newpress;
lcd_print_pgm(Text_RC_SettingsPressOk);
lcd_printnum(RC_Buttons[i], 10);
MainUpdate(1);
_delay_ms(500);
}
eeprom_write_block((void*)RC_Buttons, (void*)0, 4*8);
break;
case 1:
for (i = 0; i < 5; i++) { RC_DeviceButtonsOn[i] = 0; RC_DeviceButtonsOff[i] = 0; }
for (i = 0; i < 5; i++)
{
if ((EnabledDevices >> i) & 1)
{
do {
lcd_newscreen();
lcd_print_pgm_center(Text_RC_SettingsPressOn, 0);
switch (i)
{
case 0: lcd_print_pgm_center(DeviceName1, 1); break;
case 1: lcd_print_pgm_center(DeviceName2, 1); break;
case 2: lcd_print_pgm_center(DeviceName3, 1); break;
case 3: lcd_print_pgm_center(DeviceName4, 1); break;
case 4: lcd_print_pgm_center(DeviceName5, 1); break;
}
MainUpdate(1);
} while (RC_Button_Newpress == 0);
RC_DeviceButtonsOn[i] = RC_Button_Newpress;
MainUpdate(1);
while (RC_Button_Newpress == 0)
{
lcd_newscreen();
lcd_print_pgm_center(Text_RC_SettingsPressOff, 0);
switch (i)
{
case 0: lcd_print_pgm_center(DeviceName1, 1); break;
case 1: lcd_print_pgm_center(DeviceName2, 1); break;
case 2: lcd_print_pgm_center(DeviceName3, 1); break;
case 3: lcd_print_pgm_center(DeviceName4, 1); break;
case 4: lcd_print_pgm_center(DeviceName5, 1); break;
}
MainUpdate(1);
}
RC_DeviceButtonsOff[i] = RC_Button_Newpress;
}
}
eeprom_write_block((void*)RC_DeviceButtonsOn, (void*)0x21, 4*5); // Кнопки ПДУ для девайсов
eeprom_write_block((void*)RC_DeviceButtonsOff, (void*)0x35, 4*5);
break;
}
}
MenuTimeout++;
if (MenuTimeout > MENU_TIMEOUT) return;
}
}

char Text_MainMenu[] PROGMEM = " Главное меню\n< >";
char Text_MainMenu1[] PROGMEM = "Управление девайсами";
char Text_MainMenu2[] PROGMEM = "Показать температуру";
char Text_MainMenu3[] PROGMEM = "Включить таймер";
char Text_MainMenu4[] PROGMEM = "Настройка ПДУ";
char Text_MainMenu5[] PROGMEM = "Датчик движения";

inline void main_menu()
{
const short int ItemsCount = 5;
short int CurItem = 0;
unsigned long int MenuTimeout = 0;

while (1)
{
lcd_newscreen();
lcd_print_pgm(Text_MainMenu);
lcd_goto(1, 1);
switch (CurItem)
{
case 0: lcd_print_pgm_center(Text_MainMenu1, 1); break;
case 1: lcd_print_pgm_center(Text_MainMenu2, 1); break;
case 2: lcd_print_pgm_center(Text_MainMenu3, 1); break;
case 3: lcd_print_pgm_center(Text_MainMenu5, 1); break;
case 4: lcd_print_pgm_center(Text_MainMenu4, 1); break;
}
MainUpdate(1);
if (Button_Newpress == 2) return;
if (Button_Newpress == 3) CurItem--;
if (Button_Newpress == 4) CurItem++;
if (CurItem < 0) CurItem = ItemsCount - 1;
if (CurItem >= ItemsCount) CurItem = 0;
if (Button_Newpress > 0) MenuTimeout = 0;
if (Button_Newpress > 4)
{
unsigned char temp_time_lastsec = 0;
switch (CurItem)
{
case 0:
if (devices_menu()) return;
break;
case 1:
do {
lcd_newscreen();
if (time_secs != time_lastsec)
{
temp_time_lastsec = time_secs;
if ((time_secs != 0) && (time_secs != 30) && (time_secs % 5 == 0))
{
DS1820_Update();
DS1820_GetTemp(0, DS1820_temp1);
DS1820_GetTemp(1, DS1820_temp2);
}
}
lcd_goto(0, 0);
lcd_print_pgm(Text_Temp1);
lcd_print(DS1820_temp1);
lcd_goto(0, 1);
lcd_print_pgm(Text_Temp2);
lcd_print(DS1820_temp2);
MainUpdate(1);
} while (Button_Newpress != 2);
break;
case 2:
lcd_newscreen();
lcd_print_pgm_center(Text_TimerOn, 0);
lcd_update();
Notice_timeout = NOTICE_TIME;
Timer_timeout = TIMER_TIME;
break;
case 3:
do {
lcd_newscreen();
lcd_print_pgm_center(Text_MainMenu5, 0);
lcd_goto(0, 1);
lcd_print_pgm(Text_DevicesMenuOff);
lcd_goto(21, 1);
lcd_print_pgm(Text_DevicesMenuOn);
if (Motion_Enabled) lcd_print_pgm_center(Text_DevicesMenuON, 1); else lcd_print_pgm_center(Text_DevicesMenuOFF, 1);
MainUpdate(1);
if (Button_Newpress == 5) Motion_Enabled = 0;
if (Button_Newpress == 7) Motion_Enabled = 1;
if (Button_Newpress > 0) MenuTimeout = 0;
MenuTimeout++;
if (MenuTimeout > MENU_TIMEOUT) return;
} while (Button_Newpress != 2);
break;
case 4:
RC_settings_menu();
break;
}
}
MenuTimeout++;
if (MenuTimeout > MENU_TIMEOUT) return;
}
}

int main(void)
{
main_init();
while(1)
{
main_idle();
main_menu();
}
}

 




Комментарий:

Дипломная работа - отлично!


Рекомендовать другу
50/50         Партнёрка
Отзывы