РадиоКот :: Автомат управления освещением санузла (продолжение).
Например TDA7294

РадиоКот >Лаборатория >Цифровые устройства >

Теги статьи: Добавить тег

Автомат управления освещением санузла (продолжение).

Автор: Валерий Парусов
Опубликовано 02.12.2008

Привет, хвостатые! Я наконец добрался до обещанного вот тут продолжения на тему автомата управления освещением санузла.
Предупреждаю сразу, что работающий у меня уже в течение года экземпляр немного отличается от приведенного. Здесь программа немного переработана и несколько оптимизирована.
Тестировалось только на PROTEUS-е !!! Частота МК = 1 МГц
При разработке данного устройства я ставил перед собой следующие задачи: - отслеживать геркон туалета, как и раньше;
- так же отслеживать геркон ванны;
- включать вентилятор в туалете, если свет горит и время паузы перед включением истекло;
- выключать вентилятор в туалете, если время его работы истекло;
- измерять температуру воздуха в ванной и если она выше порога включения и выключать, если температура ниже порога выключения;
- настраивать всевозможные времена-задержки с помощью кнопочек и LCD.
Почему, спросите вы, вентилятор в ванне работает от такого странного датчика? А потому что не было у меня датчика влажности, да и стоимость его (870р в одном известном магазине - хватит нам уже бесплатную рекламу делать. Кот.) пугает изрядно. В месте с тем было замечено, если изрядно мыться, то обязательно температура в помещении поднимется - вот тут то мы и включим вентилятор. Если у кого будут какие - ни будь мысли на этот счет, то обязательно поделитесь!
Дисплей я использовал DV-16230 и подключил его немножко не так как сказано в CodeVisionARV с целью разобраться как все же им управлять на уровне ножек-сигналов. Для этого пришлось внимательно прочитать datasheet и написать несколько функций, которые располагаются в файле led.c.
Для понимания всего процесса давайте рассмотрим написанный мною код. Начнем с файла common.h, в котором находятся большинство определений. В первую очередь видим закомментированное определение:

//#define _EEPROM

Если убрать комментарии, то большая часть переменных будет определена как хранимые в EEPROM микропроцессора. Это освободит FLASH - память и позволит настройкам сохраняться при отключении питания.
Но у меня не получилось сделать так, что бы PROTEUS воспринимал бинарный файл EEPROM, который я делал следующим образом:
- CVAVR формирует после компиляции файл main.eep, имеющий формат HEX
- выбираем Project->Configure->After Make ставим галку "Execute User"s Program" и жмем кнопку "Program Settings", после чего указываем файл eep.bat.

- данный файл после компиляции вызывает утилиту SwapBinHex.exe, которая формирует из формата HEX формат BIN;
- в PROTEUS в свойствах МК выставляем источник, откуда грузить EEPROM при симуляции

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

typedef struct _Time_struct{
unsigned char hr;
unsigned char mm;
unsigned char ss;
} _Time;

В принципе она осталась от предыдущего варианта, когда на LCD выводилось время пока горел свет. Собственно для облегчения вывода время и было разбито на 3 части, хотя это и потребовало реализации дополнительных процедур по инкременту и очистке. В новом варианте я не стал переделывать - пусть будет.
Теперь файл led.c, в котором реализованы функции по работе с LCD. Все команды взяты из даташита на DV-16230, а порядок применения подсмотрен в Интернете и выявлен опытным путем.
Инициализация LCD:

void init_LCD(){
   // Установить 4-битный режим на 2-х строчном индикаторе
   PORTD = 0b00101000;
   #asm("nop");
   #asm("nop");
   //Установить OE=0 и ждать
   PORTD &= ~OE;
   // подождать
   delay_ms(3);

   // Установить 4-битный режим на 2-х строчном индикаторе
   LCD_CMD(0b00101000);
   // Очистить дисплей
   LCD_CMD(0b00000001);
   // подождать
   delay_ms(3);
   // Установить направление сдвига курсора (вправо)
   LCD_CMD(0b00000110);
   // Задать режим LCD=on, Курсор=off Мерцание курсора=off
   LCD_CMD(0b00001100);
   delay_us(50);
}

Функции LCD_CMD (выдать команду) и LCD_CHAR (отобразить символ) вызывают функцию LCD_func, различия в порядке выдачи сигналов на LCD в обоих случаях них минимальны и заключаютсч в том, что для выдачи команды необходимо на время устанавливать сигнал RS в 1, а для отображения символа - нет. В 4-х битном режиме на LCD сначала надо выдать старшие 4 бита, а потом младшие 4 бита.

void LCD_func(unsigned char CH, unsigned char isCMD){
  unsigned char TEMP;
   //Загрузить символ/команду во временную переменную
   TEMP=CH;
   //Сбросить в о младшие 4 бита
   TEMP &= 0xF0;
   // Бит OE=1
   TEMP |= OE;
   //Если выдаем команду, то RS=1
   if (!isCMD) TEMP |= RS;
   //Выдать старшие 4 бита в LCD
   PORTD = TEMP;
   //Короткая задержка перед снятием OE
   #asm("nop");
   #asm("nop");
   //OE=0
   PORTD &= ~OE;

   //Загрузить символ/команду во временную переменную
   TEMP=CH;
   //Переместиь младшие 4 бита на место старших
   TEMP=TEMP<<4;
   // OE=1
   TEMP |= OE;
   //Если выдаем команду, то RS=1
   if (!isCMD) TEMP |= RS;
   //Выдать младшие 4 бита в LCD
   PORTD = TEMP;
   //Короткая задержка перед снятием OE
   #asm("nop");
   #asm("nop");
   //OE=0
   PORTD &= ~OE;
   //Подождать
   delay_us(50);
}

Ну и собственно функции-обертки:

void LCD_CMD(unsigned char CMD){
  LCD_func(CMD,1);
}
void LCD_CHAR(unsigned char CH){
  LCD_func(CH,0);
}

Очистка дисплея:

void LCD_clear(){
   LCD_CMD(0b00000001);
   delay_ms(3);
}

Вывод строки на LCD:

#ifdef _EEPROM
//Данная функция нужна только если строки храним в EEPROM
void LCD_stre(eeprom char *str){
  eeprom char *ptr;
  ptr=str;
  while (*ptr!="")LCD_CHAR(*ptr++);
}
#endif
void LCD_str(char *str){
  char *ptr;
  ptr=str;
  while (*ptr!="")LCD_CHAR(*ptr++);
}

Разобрались, теперь основная программа main.c.
В начале файла имеем следующие строки:

#define xtal 1000000L
// 1 Wire Bus functions
#asm
  .equ __w1_port=0x18 ;PORTB
  .equ __w1_bit=7
#endasm
#include <1wire.h>
// DS1820 Temperature Sensor functions
#include
// maximum number of DS1820 devices
// connected to the 1 Wire bus
#define MAX_DS1820 8
// number of DS1820 devices
// connected to the 1 Wire bus
unsigned char ds1820_devices;
// DS1820 devices ROM code storage area,
// 9 bytes are used for each device
// (see the w1_search function description in the help)
unsigned char ds1820_rom_codes[MAX_DS1820][9];

Это нам добрый CVAVR сгенерировал код поддержки DS1820 (но не DS18B20, сейчас это не важно, но потом будут отличия!). Далее идут объявления переменных и констант. Опять обращаем внимание на #ifdef _EEPROM , означающее генерацию кода, только если хотим использовать EEPROM микропроцессора для хранения всякого разного. И добираемся до строчек:

//Значок градуса CODE=1
#ifdef _EEPROM
eeprom
#endif
char S0[]={
   0b01100,
   0b10010,
   0b01100,
   0b00000,
   0b00000,
   0b00000,
   0b00000
};

и т.д. А это у нас личные символы, которые загрузим в знакогенератор вместо первых четырех. Я там значок градуса, двери, часов и вентилятора нарисовал, убогонькие, но какие есть - кто хочет перерисует.
Основная программа работает следующим образом:
- производим настройку портов и таймеров. Будем использовать Timer0 (прерывание через 1 ms) для совершения разных действий по включению/выключению лампочек и вентиляторов и Timer2 (прерывание через 1 ms) для считывания температуры;
- загружаем наши символы в CGRAM :

//Устанавливаем адрес CGRAM (там они хранятся)
LCD_CMD(0x48);
delay_us(50);
//Записать
for (old_state=0; old_state<8; old_state++) LCD_CHAR(S0[old_state]);
for (old_state=0; old_state<8; old_state++) LCD_CHAR(S1[old_state]);
for (old_state=0; old_state<8; old_state++) LCD_CHAR(S2[old_state]);
for (old_state=0; old_state<8; old_state++) LCD_CHAR(S3[old_state]);
//Устанавливаем адрес DDRAM (отсюда символы выводятся на экран)
LCD_CMD(0x80);
delay_us(50);

- выводим на экран состояние оконечных устройств:

InvalidateVN();
InvalidateWC();

- бесконечный цикл, в котором опрашиваем состояние кнопок и герконов. Как только что - ни будь изменится (нажата/отпущена кнопка или герконы сработают) запускаются соответствующие обработчики, которые изменяют соответствующие флаги;
- в прерывании Timer0 эти флаги анализируются и в зависимости от этого начинается/заканчивается отсчет времени или включаются/выключаются лампочки-вентиляторы.
Отдельно отметим кнопку Enter, которая включает/выключает режим корректировки настроек. Если устройство находится в режиме настроек, то обработка герконов не прекращается, только результат этой работы на экран не выводится.
В режиме настроек работает функция doSettings, в которой кнопками "Вправо" и "Влево" выбирает параметры (по кругу), а кнопками "Вверх" и "Вниз" изменяют значение выбранного параметра.
Вот модель в работе:

Расписывать все не буду, в коде достаточно комментариев. Плату не разводил, кто сделает и сюда выложит - тот молодец! Схема заточена под корпус DIP.

Файлы:
Прошивка, исходники, файлы для Proteus.

Вопросы, как всегда в Форум.




Как вам эта статья?

Заработало ли это устройство у вас?

4 2 0