Современные информационные
технологии/Компьютерная инженерия
Мясищев А.А.
Хмельницкий национальный
университет, Украина
О практическом использовании микроконтроллеров AVR
В
настоящее время при построении систем управления различным технологическим
оборудованием все чаще стали использовать микроконтроллеры. Причем наиболее
распространенными из них являются микроконтроллеры фирмы ATMEL. В работе рассматривается один из
подходов практического использования микроконтроллера ATmega8 для решения трех практических
задач:
1.Определение температуры с
использованием датчика DS18B20 и в зависимости от ее значения моделирование
управлением оборудованием.
2.Измерение постоянного напряжения
в диапазоне от 0 до 15 вольт.
3. Измерение времени (цифровые
часы).
Принципиальная
схема устройства для решения перечисленных задач представлена на рис.1.
Рис.1
Для
отображения информации о времени, измеряемом напряжении, температуре,
используется жидкокристаллический индикатор с числом столбцов и строк 16х2 соответственно (LCD 16x20), который поддерживает систему
команд, совместимую с контроллером HD44780 (фирма Hitachi) и его аналогами, например, KS0066 (фирма Samsung), SED1278 (фирма Epson), ST7066 (фирма Sitronix). В качестве микроконтроллера
выбран ATmega8-16 или ATmega8L-8.
Последняя модель отличается меньшей тактовой частотой (8МГц) и меньшим
энергопотреблением. Для измерения температуры используется цифровой датчик DS18B20 температуры с точностью до 0,0625 C (при разрешающей способности температурного преобразователя 12 бит) и
диапазоном от -55 до +125 С. Датчик с микроконтроллером
сопрягается по протоколу 1wire. Иначе
1wire – это однопроводной интерфейс, позволяющий подключить к одной
линии данных практически неограниченное количество периферии. Каждое устройство
имеет уникальный 64-х битный
идентификационный номер.
При
включении устройство на индикаторе отображает в течение 5 секунд свое
назначение и далее в бесконечном цикле отображает время, постоянное напряжение
любого подключенного источника питания в пределах от 0 до 15 вольт и
температуру. Если температура превысит 32 градуса C (по представленной программе),
загорается светодиод (моделирование
управлением оборудования). Если температура опускается ниже 32 градусов,
светодиод гаснет (оборудование отключается).
После
изготовления устройства по схеме на рис.1. в микроконтроллер должна быть
загружена программа с помощью программатора. В качестве программатора был использован простой, но надежно
работающий адаптер для COM порта (рис.2) и программа PonyProg ( http://www.lancos.com/prog.html )
Рис.2
Программирование
устройства (рис.1) выполнялось на языке Си.
И если учесть, что в
архитектуру AVR изначально были заложены принципы оптимизации Си-процедур, то
альтернативы этому алгоритмическому языку нет.
Для
программирования микроконтроллера ATMega8 воспользуемся компилятором языка
Си CodeVision AVR фирмы HP InfoTech, Румыния (http://www.hpinfotech.ro/html/cvavr.htm).
Он популярен тем, что включает в себя
- Кросс-компилятор Си,
обеспечивающий выполнение почти всех элементов языка Си, разрешенных
архитектурой AVR;
- Интегрированную среду разработки,
в состав которой входит программатор чипов AVR для автоматической пересылки кодов
после компиляции в микроконтроллерный чип через адаптер, а также набор
библиотек Си для работы с LCD модулями, температурными датчиками, часами реального времени и т.д.;
- Автоматический генератор программ
CodeWizardAVR, позволяющий написать за несколько минут весь код
необходимый для выполнения таких функций, как инициализация таймеров/счетчиков,
инициализация LCD, инициализация АЦП и др.
Рассмотрим
последовательно этапы программирования микроконтроллера для решения
представленной выше задачи. Предположим, что пакет CodeVision AVR установлен на компьютере. В работе
в качестве примера используется CodeVision AVR Version
1.25.8 Professional. Перед запуском программы CodeVision AVR создаем каталог, где будут
храниться файлы.
1. Запускаем CodeVision AVR и выбераем пункт CodeWizardAVR:
2.Выбираем тип микроконтроллера и частоту:
3.Выбираем LCD и подключаем его к порту D:
Видно, что автоматически
устанавливается соответствие между подключаемыми битами микроконтроллера и
выводами LCD модуля.
4.Инициализируем шину 1Wire и температурный датчик DS1820, хотя по заданию используется
датчик DS18B20. Это делается для подсказки
вызова необходимых библиотек. Впоследствии в программе будут произведены
необходимые замены. Датчик устанавливаем на 3-й бит порта C:
5.Заходим во вкладку Timers. Выбираем для ATMega8 Timer 1:
В качестве источника тактовой частоты
(Clock Source) выбираем System Clock, т.е. таймер будет тактироваться с
частотой, на которой работает микроконтроллер (8MHz). Выберем тактовую частоту для
таймера-счетчика (Clock Value) равную 7,813kHz. Она получается делением частоты
работы микроконтроллера на коэффициент деления(1024). Включаем прерывание (Interrupt on), которое должно произойти, если в
регистре A появиться значение, указанное в поле Comp.A. Поле Value
определяет начальное значение таймера-счетчика. Таким образом, наш
таймер должен «тикнуть» 7813 раз, чтобы прошла ровно 1 секунда, если кварцевый
резонатор идеально настроен на частоту 8 MHz. Однако при делении 8 MHz на делитель частоты 1024
получается 7.8125kHz. Поэтому в поле Comp.A необходимо поставить или 7812 или 7813 тактов (1e84 или 1e85 для шестнадцатеричной системы
исчисления). Однако, как показал опыт с практически используемым кварцевым
резонатором на 8 MHz, значение 7811 тактов оказалось наилучшим, что привело к опережению
времени только на 1 секунду в сутки. Эта величина и установлена в программе
после практической корректировки. Для получения наибольшей точности часов можно
программно через каждые 24 часа от полученного времени отнимать 1 секунду.
6.Заходим последовательно в вкладки File -> Generate, Save and Exit:
Даем имена проекту и исходному
файлу. В результате появится окно с текстом программы на языке Си:
7. Корректируем программу в окне
текстом программы, который представлен ниже:
#include <mega8.h>
#include <stdio.h>
#include <math.h>
#include <ds18b20.h>
// Вставка ассемблерного кода (1 wire)
#asm
.equ __w1_port=0x15 ;PORTC
.equ
__w1_bit=3
#endasm
#include <1wire.h>
// Вставка ассемблерного кода (LCD)
#asm
.equ __lcd_port=0x12 ;PORTD
#endasm
#include <lcd.h>
#include <delay.h> // подключаем библиотеку задержки
#define VREF 5000 // Определяем опорное напряжение в
миливольтах
unsigned int s; // переменная сек.
unsigned int m; // пересенная мин.
unsigned int h; // переменная часов
// Вызов функции обработки прерывания Timer 1
output compare A interrupt service routine
interrupt [TIM1_COMPA] void
timer1_compa_isr(void)
{
// Увеличиваем секунду на 1 в случае появления в регистре A
числа 7813(изм. на 7811)
TCNT1H=0;
TCNT1L=0;
s++;
}
void main(void)
{
// Declare your local
variables here
int temp,temp3;
float temp1,temp2,volt1;
unsigned long volt;
char
lcd_volt[8],znak[2],lcd_buffer[16];
// Input/Output Ports
initialization
// Port B initialization
// Func7=Out Func6=Out
Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0
State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0xFF;
DDRB=0xFF;
// Port C initialization
// Func6=In Func5=In
Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T
State4=T State3=T State2=T State1=T State0=T
PORTC=0x03;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In
Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T
State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0
initialization
// Clock source: System
Clock
// Clock value: Timer 0
Stopped
TCCR0=0x00;
TCNT0=0x00;
// Timer/Counter 1
initialization
// Clock source: System
Clock
// Clock value: 7,813 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=0x1E; //
Частота работы таймера
OCR1AL=0x84; // Скорректирована на 7812 (1E84)
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2
initialization
// Clock source: System
Clock
// Clock value: Timer 2
Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s)
initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;
// Timer(s)/Counter(s)
Interrupt(s) initialization
TIMSK=0x10;
// Analog Comparator
initialization
// Analog Comparator: Off
// Analog Comparator Input
Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// LCD module initialization
lcd_init(16); //
Инициализация LCD
// Глобальное разрешение прерываний
#asm("sei")
w1_init(); // Инициализация линии 1 wire
lcd_gotoxy(0,0);
// Позиционируем вывод на начало 1-й строки
lcd_putsf(" Time Voltmetr"); // Выполняем вывод
lcd_gotoxy(0,1); // Позиционируем на начало 2-й строки
lcd_putsf(" Termoregulator"); // Выполняем вывод
DDRB.0=1; // Переводим в режим вывода 0-й бит
порта B
PORTB.0=1; // Устанавливаем на выходе 0 порта B
логическую единицу
delay_ms(5000); //
Удерживаем вывод в течении 5 секунд
lcd_clear(); // Очищаем экран LCD
m=0; // Обнуляем минуты
h=0; // и часы
// Устанавливаем
режим работы АЦП
ADMUX &= 0xDF
& 0x7F & 0xF2; ADMUX |= 0x40 |
0x02; // Разрядность 10бит, опорное напряжение AVCC Вольт,
// внутренний
источник опорного напряжения, линия PC2
// ADCSRA &=
0xFE;
ADCSRA |= 0x80 |
0x40 | 0x20 | 0x07; // Включить АЦП, запуск нового замера, постоянное
измерение,
//частота
АЦП=8.0МГц/128
while (1) // Запуск бесконечного цикла измерений
{
if
(PINC.0==0) // если нажата первая кнопка (порт C бит 0)
{
m++;
// к значению минуты добавляем единицу
}
if
(PINC.1==0) // если нажата вторая кнопка
(порт C бит 1)
{
h++; // к значению часов добавляем
единицу
}
// Условия часов.
if(s==60) // если сек = 60
{
m++;
// добавляем 1 к переменной "минута"
s=0;
// зануляем переменную "секунда"
}
if(m==60) // если мин = 60
{
h++;
// добавляем 1 к переменной "час"
m=0;
// зануляем переменную "минута"
}
if (h==24) //
так как у нас часы имеют 24 часовый формат
{ // при
достыжении 24 часов, зануляем все переменные.
h=0;
m=0;
s=0;
}
// Выводим
переменные (время)
lcd_gotoxy(0,0);
lcd_putchar(h/10+0x30);
lcd_putchar(h%10+0x30);
lcd_putchar(':');
lcd_putchar(m/10+0x30);
lcd_putchar(m%10+0x30);
lcd_putchar(':');
lcd_putchar(s/10+0x30);
lcd_putchar(s%10+0x30);
//
Определяем напряжение
volt=ADCL;
volt += ((int)ADCH
<< 8);
volt=volt*VREF/1024;
volt1=volt/1000.0;
volt1=3.224*volt1;
// Вычисляем напряжение в соответсвии с выбранным делителем напряжения
// Выводим
напряжение
sprintf(lcd_volt," U=%5.2f",volt1);
lcd_puts(lcd_volt);
// Определяем и
выводим температуру
temp1=ds18b20_temperature(0); //
Функция определения температуры для одног датчика
sprintf(znak,"+");
if (temp1
< 0.0 ){ // Определяем знаки температуры
temp1=-temp1;
sprintf(znak,"-");
}
// Формируем
дробное значение температура при работе с целыми числами (это полезно
// в целях
экономии памяти)
temp=temp1;
temp2=temp1-temp;
temp3=100*temp2;
if
(temp>=32){ // Если температура больше или равна 32 град.
PORTB.0=0; // Выставит ноль на нулевом выходе порта B
(включится светодиод)
}
if
(temp<32){ // Если температура
меньше 32 град.
PORTB.0=1;
// Выставит единицу на нулевом выходе порта B (выключится светодиод)
}
// Вывод температуры
lcd_gotoxy(0,1);
sprintf(lcd_buffer," temp =
%s%i.%i",znak,temp,temp3);
lcd_gotoxy(0,1);
lcd_puts(lcd_buffer);
}; //
Закрыть бесконечный цикл
} // Закрыть
программу main()
8.
Выбираем закладку
Project->Configure->C Compile и устанавливаем в поле
(s)printf Features значения
float,width,precision
9.Компилируем проект (команда Compile):
10. Собираем проект командой Make:
В каталоге, где расположена
программы на Си, появится файл с расширением .hex, который необходимо будет
переслать в микроконтроллер с помощью адаптера и программатора. Для этой цели
воспользуемся программой-программатором PonyProg, которая должна быть
предварительно установлена на компьютере со свободным COM портом. После установки PonyProg должна быть выполнена процедура ее
калибровки. Для этого необходимо зайти в закладки Setup->Calibration
и нажать на Yes.
Рассмотрим следующие этапы
использования программы PonyProg.
1.Запускаем программу и настраиваем
интерфейс связи между компьютером и
микроконтроллером:
Указываем использование адаптера для связи с COM портом:
2.Открываем файл с расширением .hex
3.После загрузки файла заходим в
закладку Command->Security and Configuration Bits и устанавливаем фьюз-биты (биты конфигурации). Ниже на
рисунке представлена заводская конфигурация фьюз-битов для ATMega8. Для нашей конфигурации
необходимо снять все галочки и нажать на Write.
4.Выполняем передачу файла
микроконтроллеру по команде Ctrl-P. Или можно зайти во вкладку Command и курсором мышки выбрать Program.
В случае успешной передачи программы в микроконтроллер должно появиться
окно с надписью Program succesful. При программировании необходимо
не забыть на устройство подать напряжение (10…15В). После ввода программы
устройство должно сразу же заработать.
Выводы.
1.Показан на простом примере
возможный способ управления с помощью
распространенных и недорогих микроконтроллеров технологическим
оборудованием на основе таймера, температуры, напряжения.
2.На основании используемого
пакета CodeVision AVR показано, как просто и прозрачно
на языке Си создается программное обеспечение для функционирования
микроконтроллера фирмы Atmel.
3.Приведена схема простейшего
надежно работающего адаптера и последовательность работы с программатором для
пересылки откомпилированной программы в микроконтроллер.
Литература.
1. Рюмик С.М. Микроконтроллеры AVR. Ступень 1. http://forum.radiospec.ru/index.php?showtopic=5612 - 2007