Современные информационные технологии/Компьютерная инженерия

 

Мясищев А.А.

Хмельницкий национальный университет, Украина

О практическом использовании микроконтроллеров 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