Современные информационные
технологии/Компьютерная инженерия
Мясищев А.А.
Хмельницкий национальный
университет, Украина
Использование контроллеров AVR для дозвона через модем
Для построения
охранно-информационных систем широко используются микроконтроллеры, например
фирмы AVR. Предположим, что необходимо практически реализовать устройство,
которое информирует по мобильному телефону о прекращении подачи электроэнергии
в какое-то подразделение, о срабатывании датчика, изменении каких либо
параметров (температуры) и т.д. Причем дозвон должен выполняться с помощью
модема, подключенного к городской телефонной линии связи. Микроконтроллер при
срабатывании датчиков в этом случае посылает на модем AT – команды для выполнения дозвона по заданному
номеру мобильного телефона. Посылка данных от микроконтроллера должна выполняться
через интерфейс RS232, который реализован в модеме. Таким образом,
спроектированное устройство должно выполнять дозвон для следующих событий:
1.Срабатывание реле, замыкающего контакты, например, при пропадании
напряжения в осветительной сети (один звонок на мобильный телефон).
2.Превышение температуры в помещении 30 градусов (два
звонка).
3.Время на микроконтроллере соответствует 10 часам дня (один
звонок).
Вывод времени и температуры, должно выполняться на индикатор
LCD 16х2. В качестве микроконтроллера используется ATmega16.
Частота кварцевого резонатора, тактирующего работу микроконтроллера выбрана
равной 7,3728 MHz.
В работе рассматривается использование отладочного
комплекса AVR – EASY для построения заданного устройства [1]. В качестве датчика температуры используется микросхема DS18B20 фирмы DALLAS
На рис.1 представлена схема устройства,
собранная на отладочном комплексе AVR – EASY.
Рис.1
Программа, по которой работает
микроконтроллер, написана на C, откомпилирована для ATmega16 с помощью компилятора CodeVision AVR
фирмы HP InfoTech,
Румыния (http://www.hpinfotech.ro/html/cvavr.htm). Он популярен тем, что включает в себя:
- Кросс-компилятор С, обеспечивающий выполнение почти
всех элементов языка Си, разрешенных архитектурой AVR;
- Интегрированную среду разработки, в состав которой
входит программатор чипов AVR для
автоматической пересылки кодов после компиляции в микроконтроллерный чип через
адаптер, а также набор библиотек языка C для работы с LCD модулями, температурными датчиками, часами реального времени и т.д.;
- Автоматический генератор программ CodeWizardAVR, позволяющий написать за несколько минут весь код,
необходимый для выполнения таких функций, как инициализация таймеров/счетчиков,
инициализация LCD, инициализация АЦП и др.
Рассмотрим этапы работы с компилятором.
1. Запускаем CodeVision AVR и выбираем
пункт CodeWizardAVR:
2.Выбираем тип микроконтроллера и частоту (скриншот с ATmega8 представлен как пример, в
действительности выбирается ATmega16):
3.Выбираем LCD и
подключаем его к порту D:
Видно, что автоматически устанавливается соответствие
между подключаемыми битами микроконтроллера и выводами LCD модуля.
4.Инициализируем шину 1Wire и температурный датчик DS1820, хотя по заданию используется датчик DS18B20. Это
делается для подсказки вызова необходимых библиотек. Впоследствии в программе
будут произведены необходимые замены. Датчик устанавливаем на 3-й бит порта C:
5.Заходим во вкладку Timers. Выбираем для ATMega16 Timer 1:
В качестве источника тактовой частоты (Clock Source)
выбираем System Clock, т.е. таймер будет тактироваться с частотой, на
которой работает микроконтроллер (7,3728MHz). Выберем тактовую частоту для таймера-счетчика (Clock Value)
равную 7,200kHz. Она получается делением
частоты работы микроконтроллера на коэффициент деления(1024). Включаем
прерывание (Interrupt on), которое должно произойти, если в регистре A
появиться значение, указанное в
поле Comp.A. Поле Value определяет
начальное значение таймера-счетчика. Таким образом, наш таймер должен «тикнуть»
7200 раз, чтобы прошла ровно 1 секунда, если кварцевый резонатор идеально
настроен на частоту 7,3728 MHz. Исходя из
практических соображений для увеличения точности работы часов в поле Comp.A поставим 7199
тактов (1c1f для шестнадцатеричной системы исчисления). В этом
случае опережение времени будет только
на 2 секунды в сутки.
6.Выбираем вкладку USART. Устанавливаем режимы его работы, как показано ниже:
7.Заходим
последовательно во вкладки File -> Generate, Save and Exit:
Поменяв все на то, что имеем на реальной
схеме (рис.1), получим следующую программу:
/*****************************************************
Охранно
- информационное устройство.
Работает
совместно с модемом по телефонной линии связи.
Выполняет
дозвон для событий:
1.Срабатывание
концевого выключателя, например срабатывание реле при отключении напряжения в
сети (один звонок)
2.Превышение
температуры в помещении 30 градусов (два звонка)
3.Время
на микроконтроллере соответствует 10 часам дня (один звонок)
Температура,
время - на LCD.
Chip
type : ATmega16
Clock frequency
: 7,372800 MHz
*****************************************************/
#include <mega16.h>
#include <1wire.h>
#include <ds18b20.h>
#include <delay.h>
#include <stdio.h>
#define
TIME 40
//
Вставка ассемблерного кода для снятия показаний
// с датчика DS18B20
#asm
.equ
__w1_port=0x12; PORTD
.equ
__w1_bit=6
#endasm
unsigned int s=0;
unsigned int m=0;
unsigned int h=0;
unsigned
int temp=0;
//-----------Функция
задержки времени --
void pause(unsigned int a) // a-длительность
паузы
{ unsigned int cn; // cn-счетчик времени
for
(cn=a;cn>0;cn--); // Цикл
задержки
времени
}
//-----------Функция записи
команды LCD--
void lcd_com(unsigned char p) // p-байт команды
{
PORTC.2=0; // Сигнал RS=0 (Запись команд)
PORTC.3=1; // Сигнал EN=1
PORTC
&= 0x0F; PORTC |= (p & 0xF0); // Установка старшей части байта
pause(TIME); // Длительность сигнала EN
PORTC.3=0; // Сигнал EN=0 - запись старшей части
байта в LCD
pause(TIME); // Длительность сигнала EN
PORTC.3=1; // Сигнал EN=1
PORTC
&= 0x0F; PORTC |= (p << 4); // Установка младшей части байта
pause(TIME); // Длительность сигнала EN
PORTC.3=0; // Сигнал EN=0 - запись младшей части байта в
LCD
pause(5
* TIME); // Пауза для выполнения команды
}
//--------Функция
записи данных в LCD---
void lcd_dat(unsigned char p) // p-байт данных
{
PORTC.2=1; // Сигнал RS=1(Запись данных)
PORTC.3=1; // Сигнал EN=1
PORTC
&= 0x0F; PORTC |= (p & 0xF0); // Установка старшей части байта
pause(TIME);
// Длительность сигнала EN
PORTC.3=0; // Сигнал EN=0 - запись старшей части байта
в LCD
pause(TIME); // Длительность сигнала EN
PORTC.3=1; // Сигнал EN=1
PORTC
&= 0x0F; PORTC |= (p << 4); // Установка младшей части байта
pause(TIME); // Длительность сигнала EN
PORTC.3=0; // Сигнал EN=0 - запись младшей части байта
в LCD
pause(5
* TIME); // Пауза для выполнения команды
}
//---------Функция
инициализации LCD-----
void
lcd_init(void)
{
lcd_com(0x30);delay_ms(5);
// Инициализация по DATASHEET на HD44780
lcd_com(0x30);delay_ms(1);
// Инициализация по DATASHEET на HD44780
lcd_com(0x30);
// Инициализация по DATASHEET на HD44780
lcd_com(0x01);delay_ms(2);
// Очистка дисплея (по опыту)
lcd_com(0x02);delay_ms(2);
// Возврат курсора в начало (по опыту)
lcd_com(0x20);
// Инициализация по DATASHEET на HD44780
lcd_com(0x28);
// 4-е линии данных, двухстрочный LCD
lcd_com(0x08);
// Выключение дисплея
lcd_com(0x01);
delay_ms(2); // Очистка дисплея
lcd_com(0x02);
delay_ms(2); // Возврат курсора в начало
(по опыту)
lcd_com(0x06);
// Сдвиг курсора вправо
lcd_com(0x0c);
// Включение дисплея, выключение курсора
}
//
Вызов функции обработки прерывания Timer1
interrupt
[TIM1_COMPA] void timer1_compa_isr(void)
{
char lcd_t[17];
unsigned int a;
TCNT1H=0;
TCNT1L=0;
//
Увеличиваем секунду на 1 в случае появления
//
в регистре A числа 7200 (изменено на 7199)
s++;
//
Установка часов
if (PINA.0==0) // Если нажата кнопка m+
{
m++; } // к числу минуты прибавляется единица
// (для выполнения установки времени на
устройстве локально)
if (PINA.1==0) // Если нажата кнопка h+
{ h++;} // к числу часов прибавляется
единица
// Условия часов
if(s==60)
// Если число секунд = 60
{ m++; s=0;} // к минутам добавляется 1
if(m==60) // Если число минут = 60
{h++;
m=0;} // к часам добавляется 1
if
(h==24) // Если число часов = 24
{
h=0;m=0;s=0;} // к дням добавляется 1
//
Переводим C2...7 в режим вывода
DDRC = 0xFC;
//
Устанавливаем PC4...7 в 1
PORTC = 0xF0;
//
Инициализация LCD
lcd_init();
//
Выполнить в 1-й строке LCD распечатку по примеру
//
" ВРЕМЯ=10:11:15 "
//{
lcd_dat('
');
lcd_dat(0x42);lcd_dat(0x70);lcd_dat(0x65);lcd_dat(0xBC);
lcd_dat(0xC7);lcd_dat('=');
lcd_dat(h/10+0x30);
lcd_dat(h%10+0x30);
lcd_dat(':');
lcd_dat(m/10+0x30);
lcd_dat(m%10+0x30);
lcd_dat(':');
lcd_dat(s/10+0x30);
lcd_dat(s%10+0x30);
//
Определение температуры каждые 15 секунд
if ( s==0 || s==15 || s==30 || s==45 )
{
temp=ds18b20_temperature(0);}
// Переход на 2-ю строку LCD
lcd_com(0xc0);
//
Выполнить во 2-й строке LCD распечатку по примеру
//
" t=26C"
for(a=0;a<17;a++){lcd_t[a]=' ';}
sprintf(lcd_t,"t=%2dC",temp);
for(a=0;a<6;a++) {lcd_dat(' ');}
for(a=0;a<5;a++){lcd_dat(lcd_t[a]);}
}
void main(void)
{
PORTA=0xFF;
DDRA=0x00;//Порт
А работает на ввод
PORTB=0xFF;
//Потушить диоды
DDRB=0xFF;
//Порт B работает на вывод
PORTC=0x00;
DDRC=0x00;
PORTD=0xFF;
DDRD=0xFF;
//Порт D работает на вывод
//
Timer/Counter 0 initialization
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
//
Clock value: 7,200 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
//
OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
//
Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
//
Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x1C;
// Частота работы таймера
OCR1AL=0x1F;
// скорректирована на 7,199(0x1C1F).Была 7,200(0x1C20)
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;
//Разрешить прерывание по таймеру
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
//
USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
//
USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x2F;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1:
Off
ACSR=0x80;
SFIOR=0x00;
//
Разрешить прерывания
#asm("sei")
// 1 Wire Bus initialization
w1_init();
while
(1)
{
if (PINA.2==0) // Однократный дозвон при
срабатывании концевого выключателя
{
PORTB.0=0; // Включить светодиод 0
printf("ATM1N7DP0679735581\r\n");
// AT - AT команда; M1 - включить динамик; N7
- max громкость динамика
// DP - импульсный набор номера; 0679735581 -
номер телефона
// \r\n - передать команду модему.
// Модем звонит только тогда, когда подключен
к линии.
delay_ms(30000);
printf("a");
goto end;
}
if
( temp>=30 ) // Двукратный дозвон при превышении температура 30 градусов
{
PORTB.1=0; //Включить светодиод 1
printf("ATM1N7DP0679735581\r\n");
delay_ms(30000);
printf("a");
delay_ms(3000);
printf("ATM1N7DP0679735581\r\n");
delay_ms(30000);
printf("a");
goto end;
}
if (h==10 && m==0 && s==0 )
// Однократный дозвон в 10 часов 0 сек. дня
{
printf("ATM1N7DP0679735581\r\n");
delay_ms(30000);
printf("a");
delay_ms(35000);//
выждать 35 секунд после того, как модем положит трубку
}
};
// Выход из цикла и блокирование, пока не
будет нажата кнопка RESET
end:
При
программировании LCD индикатора необходимо учесть
следующее. Для индикации данных на экране необходимо, чтобы
микроконтроллер посылал по правилам, определенным контроллером
индикатора, соответствующие команды и синхронизирующие импульсы. Сигнал RS должен быть установлен в 0, когда необходимо в LCD передать команды, и в 1 – при передаче данных.
Поэтому в листинге программ выделяются две функции: lcd_com – запись команд и lcd_dat – запись данных. По перепаду
сигнала EN с 1 в 0 выполняется запись в LCD команды. Сигнал RD равен 0 при записи данных в LCD и 1 при чтении данных с LCD. Так как данные для устройства всегда записываются в LCD, вывод RD занулен. В
таблице 1 представлены некоторые команды LCD на базе HD44780, которые
используются в программе.
Таблица 1
Команды
LCD |
HEX код |
Время
в мкс |
Очистка
дисплея |
0x01 |
1640 |
Возврат
курсора в начало |
0x02 |
1640 |
Сдвиг
курсора вправо |
0x06 |
40 |
Выключение
дисплея |
0x08 |
40 |
Интерфейс
связи 8 бит, 1 строка на дисплее |
0x30 |
40 |
Интерфейс
связи 4 бит, 1 строка на дисплее |
0x20 |
40 |
Выключение
курсора |
0x0C |
40 |
Интерфейс
связи 4 бит, 2 строки на дисплее |
0x28 |
40 |
Из таблицы 1 видно, что LCD может
использовать две ширины интерфейса связи – 8 бит и 4 бита. Согласно рис.1 LCD подключен к микроконтроллеру по шине связи шириной 4
бита. Поэтому байты необходимо передавать двумя порциями. На рис.2 показаны
временные диаграммы выполнения команды 0xC0 “Установка курсора в первое знакоместо второй строки
экрана” и индикация в нем буквы “Д” пересылкой команды 0xE0.
Рис.2
В
листинге программы в соответствии с диаграммой представлены отдельно функция
передачи команд (lcd_com, RS=0), функция передачи данных (lcd_dat, RS=1) и функция инициализации LCD (lcd_init) согласно DATASHEET на HD44780 http://www.gaw.ru/pdf/lcd/Chips/Hitachi/hd44780u.pdf.
По опыту работы с LCD для вывода информации на экран без «мусора»
необходимо было дополнительно добавить
две команды - lcd_com(0x01) и lcd_com(0x02) (см. листинг программы).
Компиляция исправленной программы выполняется
в следующей последовательности:
1.Компилируем
проект (команда Compile):
2. Собираем проект командой Make:
В каталоге, где расположена программы на
Си, появится файл с расширением .hex, который
необходимо будет переслать в микроконтроллер с помощью адаптера и
программатора. Для этой цели воспользуемся программой-программатором PonyProg, которая должна быть предварительно установлена на
компьютере со свободным LPT портом.
После установки PonyProg должна быть выполнена
процедура ее калибровки. Для этого необходимо зайти в закладки Setup->Calibration и нажать на Yes.
Рассмотрим следующие этапы использования программы PonyProg.
1.Запускаем программу и настраиваем интерфейс связи
между компьютером и микроконтроллером:
Указываем
использование адаптера для связи с LPT
портом:
2.Открываем
файл с расширением .hex
3.После загрузки файла заходим в закладку Command->Security
and Configuration Bits и
устанавливаем фьюз-биты (биты
конфигурации). Ниже на рисунке представлена заводская конфигурация фьюз-битов
для ATMega8 Для ATmega16
необходимо снять все галочки и нажать на Write.
4.Выполняем передачу файла микроконтроллеру по команде
Ctrl-P. Или можно
зайти во вкладку Command и курсором мышки выбрать Program. В случае
успешной передачи программы в микроконтроллер должно появиться окно с надписью Program successful.
При программировании необходимо на устройство подать напряжение (10…15В). После
ввода программы устройство сразу начинает работать.
Литература
1.Отладочный
комплекс AVR-EASY.
http://www.kosmodrom.com.ua/data/avr-easy.php
2.
Рюмик С.М. Микроконтроллеры AVR. Ступень 1. http://forum.radiospec.ru/index.php?showtopic=5612 - 2007
3. Мясищев А.А.
Использование
контроллеров AVR для
управления технологическим оборудованием через
TCP/IP сети. Материали за 6-а международна научна
практична конференция, «Найновите постижения на европейската наука»,
-2010. Съвременни технологии на
информации. Математика. Здание и архитектура София .«Бял ГРАД-БГ» ООД – 104 стр.