4.2. Компилятор языка С CodeVision AVR

CodeVision представляет собой кросс-компилятор языка С, графическую оболочку и автоматический генератор программ, ориентированные на работу с семейством микроконтроллеров AVR фирмы Atmel. Внешний вид окна программы показан на рис. 4.5.

Рис. 4.5. Внешний вид окна программы CodeVision AVR

Программа представляет собой 32-разрядное приложение для работы в операционных системах Windows 95, 98, NT4.0 и 2000.

Кросс-компилятор включает в себя почти все элементы, соответствующие стандарту ANSI. Также в компилятор включены дополнительные возможности, ориентированные на использование архитектурных особенностей микроконтроллеров этого семейства и встроенных систем в целом.

Объектные файлы COFF позволяют осуществлять отладку программ с просмотром содержимого переменных. Для этого следует применять свободно распространяемый фирмой Atmel (www.atmel.com) отладчик AVR Studio debugger версии 3.5 или более поздний.

Для отладки систем, использующих последовательную передачу данных, в графической оболочке имеется встроенный Terminal.

Кроме стандартных библиотек языка С, компилятор имеет библиотеки для работы с:

• ЖКИ индикаторами со встроенным контроллером;

• шиной I2C фирмы Philips;

• датчиком температуры LM75 фирмы National Semiconductor;

• часами реального времени PCF8563 и РС8583 фирмы Philips, DS1302 и DS1307 фирмы Dallas Semiconductor;

• однопроводным протоколом фирмы Dallas Semiconductor;

• датчиками температуры DS1820 и DS1822 фирмы Dallas Semiconductor;

• датчиком температуры/термостатом DS1621 фирмы Dallas Semiconductor;

• памятью EEPROM DS2430 и DS2433 фирмы Dallas Semiconductor;

• шиной SPI;

• управлением режимами пониженного потребления энергии;

• временными задержками.

Также в CodeVision имеется автоматический генератор программ, который позволяет в течение считанных минут получить готовый код для следующих функций:

• настройка доступа к внешней памяти;

• определение источника прерывания Reset;

• инициализация портов ввода/вывода;

• инициализация внешних прерываний;

• инициализация таймеров/счетчиков;

• инициализация сторожевого таймера;

• инициализация UART;

• инициализация аналогового компаратора;

• инициализация встроенного АЦП;

• инициализация интерфейса SPI;

• инициализация поддерживаемых библиотеками CodeVision микросхем, работающих с однопроводным интерфейсом и шиной I2С;

• инициализация модуля ЖКИ-индикатора со встроенным контроллером.

Среда CodeVision AVR включает в себя программное обеспечение для работы с совместимым с платой STK200 программатором. После компиляции исходной программы на языке С полученный код может быть непосредственно запрограммирован в микроконтроллер. Этот программатор использует всего четыре сигнала: MOSI, MISO, SCK, RESET. Известно много простейших программаторов, соединяющихся с последовательным или параллельным портом IBM совместимого персонального компьютера.

Читателям предлагается на примере простейшей схемы познакомиться с применением демонстрационной версии компилятора языка С CodeVisionAVR, Для этого придется изготовить простой совместимый с STK200 кабель внутрисхемного программирования и несложную схему с микроконтроллером AT90S2313. В итоге проделанную работу можно будет проверить, запустив простую программу на языке С.

Изготовление кабеля для внутрисхемного программирования «STK200/300»

На рис. 4.6 показана электрическая принципиальная схема кабеля. Микросхема 74НС244 представляет собой буфер с тремя состояниями на выходах, что позволяет избежать влияния кабеля на схему после программирования микроконтроллера, не отключая кабеля.

Адаптер получил свое название от комплектующихся им отладочных плат фирмы Atmel для быстрого начала работы с микроконтроллерами At90s8515 и Atmega103 соответственно. На самом деле приведенная схема соответствует одновременно обеим адаптерам, в ней присутствуют перемычки для определения наличия как адаптера STK200 (выводы 2-12 разъема XI), так и STK300 (выводы 3-11).

Разводка колодки Х2 на приведенной схеме соответствует принятой фирмой Atmel для производимых ею плат.

Рис. 4.6. Простой кабель для внутрисхемного программирования

Простая демонстрационная схема на микроконтроллере AT90S8535

Чтобы проверить эту схему в работе, вам нужно иметь только один микроконтроллер AT90S2313, источник питания +5 В и кварцевый резонатор частотой 4 МГц. Кроме этого, потребуется несколько пассивных элементов — конденсаторов и резисторов. Электрическая принципиальная схема устройства изображена на рис. 4.7.

Для управления светодиодом в схеме использован всего один вывод микроконтроллера — PD1.

Рис. 4.7. Простейшая схема с микроконтроллером AT90S2313

Пример программы

Для проверки работы кабеля внутрисхемного программирования и демонстрационной схемы предлагается несложная программа, которая заставляет мигать светодиод. Оттранслированный код для этой программы можно найти на прилагаемом к книге компакт диске в файле blink.hex.

Текст программы:

// blink.с

#include <90s2313.h>

#include <delay.h>

void main()

{

// инициализация порта D

DDRD=0xff; // Порт D работает на вывод

PORTD=0x00;

while(1)

{

   PORTD.1=0;

   delay_ms(1000);

   PORTD.1=1;

   delay_ms(1000);

} // while(1)

// main

Использование встроенного программатора CodeVision

Простейший способ работы с прорамматором — использование команды меню Project, подменю CONFIGURE. Если осуществить указанные на рис. 4.8 установки, оттранслированный код программы будет загружен в микроконтроллер непосредственно после успешной компиляции.

Рис. 4.8. Окно настройки проекта

Перед работой следует указать тип используемого программатора. На рис. 4.9 показан вид окна выбора типа программатора.

Рис. 4.9. Окно выбора типа программатора

После успешной трансляции должно появиться окно, подобное показанному на рис. 4.10. Для занесения программы в микроконтроллер, следует нажать кнопку «Program».

Рис. 4.10. Окно, появляющееся после успешной трансляции программы

Примеры программ для компилятора CodeVision AVR С

Процедуры работы со встроенным АЦП AT90S8535 без прерываний

Текст программы:

// В данном примере определяются две функции для работы с АЦП:

// void ImtADC(void) инициализация АЦП

// int fieadADC(unsigned char) чтение значения напряжения на заданном входе

#include <ioB535.h>

void InitADC(void)

{

    ADMUX = 0; // выбрать вход номер 0

    ADCSfi = 0xC0; // включить АЦП и запустить первое "пустое" преобразование

}

int ReadADC(unsigned char channel)

{

    int i;

    ADMUX = channel; // Выбрать номер входа

    ADCSR |= 0x40; // Начать преобразование

    while (!(ADCSR & 0x10)); // Проверка завершения преобразования

    ADCSR |= 0x10; //Очистка бита "Преобразование завершено" при помощи записи в него "1"

    i = ADCL; // Чтение младших 8 битов ПЕРВЫМИ

   i += (int)ADCH << 8; // Чтение старших 2 битов, умножение их на 256 и сложение с младшим байтом

    return i;

}

void main(void)

{

    unsigned int temp;

    InitADC(); // Инициализация АЦП

    temp=ReadADC(0); // Измерить напряжение на нулевом входе АЦП (линия РАО порта А)

}

Пример вызова написанных на ассемблере функций из С программы

Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.

Текст программы:

// Определение функции на ассемблере. Эта функция возвращает а+Ь+с

#pragma warn- // Запретить предупреждения

int sum_abc(int a, int b, unsigned char с) {

#asm

    ldd r30, у+3;R30=LSB а

    Idd r31,у+4;R31=MSB а

    Idd r26,у+1;R26=LSB b

    Idd r27,у+2;R27=MSB b

    add r30,r26;(R31,R30)=a+b

    adc r31,r27

    Id r26,у;R26=c

    clr r27; Преобразование с типа unsigned char в тип int

    add r30,r26; (R31,R30)=(R31,R30)+C

    adc r31,r27

#endasm

}

#pragma warn+ // Разрешить предупреждения

void main(void) {

int r;

// Теперь вызовем функцию и сохраним результат в r

r=sum_abc(2,4,6);

}

Некоторые пояснения.

Компилятор передает параметры функции с помощью стека данных. Первым он передаст целый параметр а, затем b и в завершение с типа unsigned char. При каждой передаче регистровая пара Y увеличивается на размер параметра (4 для типа long, 2 для int, 1 для char).

В случае параметров, состоящих из нескольких байтов, первым передается старший байт. Как вы видите, стек растет вниз. После того как все параметры функции были записаны в стек (pushed), регистр Y указывает на последний параметр с, поэтому мы можем прочитать его значение в R26, воспользовавшись командой Id r26,у.

Параметр b был записан в стек перед с, поэтому он находится по более высокому адресу в стеке данных. Мы можем прочитать его значение, воспользовавшись командами ldd r27,у+2 (старший байт) и ldd r26,у+1 (младший байт).

Старший байт был записан в стек первым, поэтому он находится по более высокому адресу.

Параметр а был записан в стек перед Ь, поэтому он находится по более высокому адресу в стеке данных. Мы можем прочитать его значение, воспользовавшись командами ldd r27,у+4 (старший байт) и ldd r26,у+3 (младший байт).

Старший байт был записан в стек первым, поэтому он находится по более высокому адресу.

Функции возвращают свои значения в следующих регистрах:

R30 для типов char & unsigned char;

R30, R31 для типов int & unsigned int;

R30, R31, R22, R23 для типов long & unsigned long.

Поэтому наша функция должна вернуть ее результат в регистрах R30, R31.

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

Директива #pragma warn запрещает компилятору генерировать предупреждения о том, что функция не возвращает результат.

Это необходимо, потому что компилятору не известно, что мы делаем в нашей написанной на ассемблере функции.

Использование встроенного EEPROM

Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.

Текст программы:

// Контроллер: AT90S2313

// Модель памяти: TINY

// Размер стека данных: 64 bytes

flash char f[]="This is a test";

#pragma warn-

eeprom char e[16];

#pragma warn+

char r[16];

void main (void)

{

Char flash *ptr_to_flash;

char eeprom *ptr_to_eeprom;

char *ptr_to_ran;

// Копировать строку f из FLASH в

// Строку e в EEPROM

ptr_to_flash=f;

ptr_to_eeprom=e;

while (*ptr_to_flash)

     *ptr_to_eeprom++=*ptr_to_flash++;

// Копировать строку e из EEPROM в

// строку г в оперативной памяти

ptr_to_eeprom=e;

ptr_to_ram=r;

while (*ptr_to_eeprom)

     *ptr_to_ram++=* ptr_to_eeprom++;

// Стоп (бесконечный цикл)

while (1);

}

Работа с клавиатурой 4x4

Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.

Рис. 4.11. Схема соединения клавиатуры 4x4

Для индикации использован 2х16 алфавитно-цифровой ЖКИ, подсоединенный к порту PORTC следующим образом:

Текст программы:

#asm

.equ __lcd_port=0x15

#endasm

#include <lcd.h>

#include <stdio.h>

#include <delay.h>

#include <90sB515.h>

// Частота кварцевого резонатора [Гц]

#define F_XTAL 4000000L

// Линии PINDO…3 будут входами строк

#define KEYIN PIND

// Линии PORTD4..7 будут выходами столбцов

#define KEYOUT P0RTD

// Инициализация использованного таймера TIMER0

#define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L

#define FIRST_COLUMN 0x80

#define LAST_COLUMN 0x10

typedef unsigned char byte;

// Здесь в виде бита сохраняется состояние каждой нажатой клавиши,

// бит 0 будет KEY0, бит 1 KEY1….

unsigned keys;

// Буфер ЖКИ-индикатора

char buf[33];

// Прерывание по таймеру TIMER 0 каждые 2 мс

interrupt [TIM0_OVF] void timer0_int(void)

{

static byte key_pressed_counter=20;

static byte key_released_counter,column=FIRST_COLUMN;

static unsigned row_data,crt_key;

// Перезагрузить таймер TIMERO

INIT_TIMER0;

row_data<<=4;

// Получить группу из 4 клавиш в переменной row_data

row_data|=¯KEYIN&0xf;

column>>=1;

if (column==(LAST_C0LUHN>>1))

   {

   column=FIRST_COLUHN;

   if (row_data==0) goto new_key;

   if (key_released_counter) — key_released_counter;

   else

     {

     if (-key_pressed_counter==9) crt_key=row_data;

     else

        {

        if (row_data!=crt_key)

          {

          new_key:

          key_pressed_counter=10;

          key_released_counter=0;

          goto end_key;

          };

        if (!key_pressed_counter)

          {

          keys=row_data;

          key_released_counter =20;

          };

        };

     };

   end_key:;

   row_data=0;

   };

// Выбрать следующий столбец, входы будут притянуты к 5 В

KEY0UT=¯column;

}

// Проверить, были ли нажаты клавиши

unsigned inkey(void)

{

unsigned k;

if (k=keys) keys=0;

return k;

}

void init_keypad(void)

{

DDRD=0xf0;

INIT_TIHERO;

TCCR0=3;

TIMSK=2;

#asm("sei")

}

main() {

unsigned k;

init_keypad();

lcd_init(16);

lcd_putsf("CVAVR Keypad");

// Читать состояние клавиш и индицировать код клавиши

while (1)

     {

     lcd_gotoxy(0,1);

     if (k=inkey())

        {

        sprintf(buf,“Key code=%Xh“,k);

        lcd_puts(buf);

        }

     else lcd_putsf("NO KEY ");

     delay_ms(500);

  }

}

Работа с алфавитно-цифровым ЖК-индикатором 2x16

Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.

Использован ЖК-индикатор со встроенным контроллером, подсоединенный к порту PORTC следующим образом:

Текст программы:

// ЖК-индикатор подсоединен к выходам порта P0RTC

// смотри файл lcd.h в директории..inc

#asm

.equ __lcd_port=0x15;PORTC

#endasm

// Включить в состав программы описания и процедуры для работы с ЖК-индикатором

#include <lcd.h>

void main(void)

{

// Инициализировать ЖК-индикатор для работы

// с 2 строками по 16 символов

lcd_init(16);

// Перейти на 2-ю строку ЖК-индикатора

lcd_gotoxy(0,1);

// Отобразить сообщение

lcd_putsf("Hello world'');

// Остановиться (бесконечный цикл)

while (1);

}

Использование определенных пользователем символов при работе с ЖК-индикатором со встроенным контроллером

Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.

Использован алфавитно-цифровой ЖК-индикатор. Соединения между ЖК-индикатором и платой со схемой должны быть как можно короче.

Текст программы:

// Включить в программу определения и процедуры для работы со ЖК-индикатором

// в плате STK200/300

#include <lcdstk.h>

typedef unsigned char byte;

// Таблица для определенного пользователем символа

// стрелка, указывающая на верхний правый угол

flash byte char0[8]={

0b0000000,

0Ь0001111,

0b0000011,

0b0000101,

0b0001001,

0b0010000,

0b0100000,

0b1000000};

// Функция, использованная для определения заданного пользователем символа

void define_char(byte flash *рс. byte char_code)

{

byte i,a;

a=(char_code«3)|0x40;

for (i=0; i<8; i++) lcd_write_byte(a++,*pc++);

}

void main(void)

{

// Инициализация ЖКИ для работы

// с 2 строками по 16 символов в строке

lcd_init(16);

// Определить символ 0

define_char(char0,0);

// Переключиться в режим записи в память отображения (Display RAM)

lcd_gotoxy(0,0);

// Отобразить определенный пользователем символ

lcd_putsf("User defined char 0:");

// Отобразить определенный пользователем символ 0

lcd_putchar(0);

// Стоп (бесконечный цикл)

while (1);

}

Бегущий огонь на светодиодах

Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.

8 светодиодов соединены с выходами порта PORTB и +5 В через резисторы сопротивлением 270 Ом, ограничивающие гок. Аноды светодиодов соединены с линией +5 В.

Текст программы:

// Определение регистров ввода-вывода для ATS0S8515

#include <90sS815.h>

// Частота кварцевого резонатора [Гц]

#define xtal 4000000

// Частота переключения светодиодов [Гц]

#define fmove 2

// Включить светодиод на линии 0 порта P0RTB

unsigned char led_status=0xfe;

// Процедура обработки прерывания по переполнению таймера TIMER1

// вызывается каждые 0,5с

interrupt [TIM1_OVF] void timer1_overflow(void)

{

// preset again TIMER1

TCNT1=0x10000-(xtal/1024/fmove);

// move the LEO

led_status<<=1;

led_status|=1;

if (led_status==0xff) led_status=0xfe;

// turn on the LED

P0RTB=led_status:

}

void main(void)

{

// Инициализация портов ввода-вывода

// Все выводы порта PORTB настроены на вывод информации

DDRB=0xff;

// Включить первый светодиод

PORTB=led_status,

// Инициализация таймера TIMER1

// Таймер TIHER1 отсоединен or линии OC1

// не включен режим широтно-импульсной модуляции PWM

TCCR1А=0;

// Частога таймера TIMER1 xtal/1024

TCCR1B=5;

// Предустановим значение таймера TIMER1

TCNT1=0x10000-(xtal/1024/fmove);

// Очистить флаги прерываний по таймеру

TIMER1 TIFR=0;

// Разрешить прерывания по переполнению таймера TIMER1

TIMSK=0x80;

// Все остальные виды прерываний запрещены

GIMSK=0;

// Разрешение глобальных прерываний

#fasm

sei

#endasm

// Бесконечный цикл, при этом возможно возникновение прерываний по переполнению таймера TIMER1

while (1);

}

Цифровой вольтметр с использованием АЦП фирмы Maxim типа МАХ1241

Измеренное значение передается с помощью интерфейса RS232. Параметры интерфейса: 9600 8N1.

Материал взят из демонстрационной версии компилятора CodeVisionAVR С Compiler, автором которого является Pavel Haiduc, HP InfoTech S.R.L.

Частота кварцевого резонатора: 4,000 МГц.

Подсоединение МАХ 1241 KAT90S8515.

Программатор после программирования контроллера должен быть отсоединен.

Текст программы:

#include <90s8515.h>

// Стандартная библиотека ввода/вывода

#include <stdio.h>

// Библиотека SPI-функций

#include <spi.h>

// Библиотека для формирования задержек

#include <delay.h>

// Опорное напряжение для МАХ1241 [мВ]

#define VREF 5000

// Определение управляющих сигналов для МАХ1241

#define NSHON P0RTB.0

#define NCS P0RTB.1

#define DOUT PINB.6

union adcu

{

unsigned char byte[2];

unsigned int word;

};

// Произвести одно аналого-цифровое преобразование и

// вернуть его результат unsigned

int max1241_read(void)

{

union adcu adc_data;

// Вывести микросхему MAX1241 из режима shutdown

NSHDN=1;

// Подождать 5 мкс для приведения МАХ1241 в рабочее состояние

delay_us(5);

// Теперь выбрать чип для начала преобразования

NCS=0;

// Ждать, пока преобразование не завершится

// DOUT будет равен 0 в процессе преобразования

while (DOUT==0);

// DOUT=1 —> преобразование завершено

// Прочитать младший байт (MSB)

adc_data.byte[1]=spi(0);

// Прочитать старший байт (LSB)

adc_data.byte[0]=spi(0);

// Снять сигнал выбора чипа

NCS=1;

// Перевести АЦП в режим shutdown

NSHDN=0:

// Форматировать результат преобразования и возврат результата

return (adc_data.word»3)&0xfff;

}

void main(void)

{

// Переменная для хранения результата преобразования

unsigned n;

// Инициализация портов ввода/вывода

// Port А

DDRA=0x00;

P0RTA=0x00;

// Port В

// Линия /SS установлена на вывод информации

// на уровне 1, это необходимо для работы

// SPI-порта в режиме мастер

DDRB=0xA3;

P0RTB=0x12;

// Port С

DDRC=0x00;

P0RTC=0x00;

// Port D

DDRD=0x00;

P0RTD=0x00;

// Инициализация UART (интерфейс RS-232)

// Параметры интерфейса: 8 битов данных, 1 стоп бит, без проверки четности

// приемник UART: отключен

// передатчик UART: включен

UCR=Ox08;

// Скорость передачи данных: 9600

UBRR=0x19;

// Инициализация SPI

// Режим работы SPI: мастер

// Тактовая частота SPI: 1000 000 кГц

// Порядок передачи данных: младший бит первый

SPCR=0x50;

putsf("MAX1241 Demo using the CodeVisionAVR С Compiler");

pUtSf ("******************************************* ");

// Произвести аналого-цифровое преобразование и передать результаты

// через интерфейс RS-232

while (1)

     {

     n=max1241_read();

     printf("HAX1241-> N=%4u U=964umV ",n,(unsigned) ((long) n*VREF/4096));

     // 0.3 sec. delay

     delay_ms(300);

     };

}

Использование ЖК-индикатора МТ10Т7-7

Микроконтроллер: AT90S8535-8PI.

Кварцевый резонатор: 4 МГц.

Подсоединение индикатора к порту Port С:

Текст программы:

void delay(void)

{

asm("del1: ldi r24,0x01");

asm("dl: dec r24");

asm('brne dl");

asm("dec r25");

asm("brne del1");

}

void STR0B_WR1(void)

{

asm("sbi 0x18,5");

delay();

asm("cbi 0x18,5");

}

void STR0B_ADR(void)

{

   asm("cbi 0x18,4"):

   delay();

   asm("sbi 0x18,5");

   delay();

   asm("cbi 0x18,5");

   delay();

   asm("sbi 0x18,4");

}

void Set_Bus(unsigned char A)

{

   If ((A&0x01)==0x01) asm("sbi 0x18,0");

                             else asm("cbi 0x18,0");

   If ((A&0x02)==0x02) asmC'sbi 0x18,1");

                             else asm("cbi 0x18,1");

   if ((А&0х04)==0х04) asm("sbi 0x18,2");

                             else asm("cbi 0x18,2");

   if ((А&0х08)==0х0в) asm("sbi 0x18,3");

                             else asmC'cbi 0x18,3");

}

void Init_LCD(void)

{

unsigned char temp;

   Set_Bus(0x0f);

   STR0B_ADR();

   Set_Bus(0x01);

   STR0B_WR1();

   Set_Bus(0);

   STR0B_ADR();

   for (temp=0;temp<20;temp++) STR0B_WR1();

}

unsigned char code7(unsigned char code)

{

   switch(code)

       {

            case 0: return 0xee;

            case 1: return 0x60;

            case 2: return 0x2f;

            case 3: return 0x6d;

            case 4: return 0xe1;

            case 5: return 0xcd;

            case 6: return 0xcf;

            case 7: return 0x68;

            case 8: return 0xef;

            case 9: return 0xed;

            case 10: return 0;

       }

return 0;

}

void out(unsigned char num)

{

   num=code7(num);

   Set_Bus(num);

   STR0B_WR1();

   delay0;

   asm("swap %num"); Set_Bus(num);

   STR0B_WR1();

   delay();

}

void display(unsigned int N, unsigned int N1, unsigned int N2)

{// NN N1N1N1N1 N2N2N2N2

   Set_Bus(0);

   STR0B_ADR();

   out((unsigned int)(N/10)-10*(unsigned int)(N/100));

   out(N-10*(unsigned int)(N/10));

   out((unsigned int)(N1/1000)-10*(unsigned int)(N1/10000));

   out((unsigned int)(N1/100)-10*(unsigned int)(N1/1000));

   out((unsigned int)(N1/10)-10-(unsigned int)(N1/100));

   out(N1-10*(unsigned int)(N1/10));

   out((unsigned int)(N2/1000)-10*(unsigned int)(N2/10000));

   out((unsigned int)(N2/100)-10*(unsigned int)(N2/1000));

   out((unsigned int)(N2/10)-10*(unsigned int)(N2/100));

   out(N2-10*(unsigned int)(N2/10));

}

«include <io8535.h>

void main()

{

          DDRB = 0xFF; /* Port С настроен на вывод */

          P0RTB = 0xff; /* Все линии порта С = 1 */

          Init_LCD();

          display(0,1,7);

          while(1);

}

Динамическая индикация

Динамическая индикация с применением прерывания по переполнению таймера Timer 0. Вывод на индикатор происходит каждые 65 мс. Прерывания по таймеру 1 происходят с периодом примерно 1 с. При этом на единицу увеличивается значение на индикаторе. При достижении значения 20 происходит обнуление значения для вывода.

Микроконтроллер: AT90S2313.

Кварцевый резонатор: 4 МГц.

Текст программы:

#include <90s2313.h>

#include "HG.h"

// Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void)

{

// Reinitialize Timer's 0 value

TCNT0=0xFF;

// Place your code here

HG12();

}

// Timer 1 overflow interrupt service routine

interrupt [TIM1_0VF] void timer1_ovf_isr(void)

{

// Reinitialize Timer's 1 value

TCNT1H=0xf0;

TCNT1L=0xbe;

// Place your code here

N++;

if (N==20) N=0;

// Declare your global variables here

void main(void)

{

unsigned int temp,temp1,temp2;

// Input/Output Ports initialization

// Port В

P0RTB=0x00;

DDRB=0xFF;

// Port D

P0RTD=0x00;

DDRD=0x00;

// Timer/Counter 0 initialization

// Clock source: System Clock

// Clock value: 3906 kHz

// Mode: Output Compare

// OCD output: Disconnected

TCCR0=0x05;

TCNT0=0xFF;

// Timer/Counter 1 initialization

// Clock source: System Clock

// Clock value: 3,906 kHz

// Mode: Output Compare

// OC1 output: Discon.

// Noise Canceler: Off

// Input Capture on Falling Edge

TCCR1A=0x00;

TCCR1B=0x05:

TCNT1H=0xf0;

TCNT1L=0xbe;

0CR1H=0x00;

0CR1L=0x11;

// External Interrupt(s) initialization

// INT0: Off

// INT1: Off

GIMSK=0x00;

MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization

TIMSK=0x82;

// Analog Comparator initialization

// Analog Comparator: Off

// Analog Comparator Input Capture by Timer/Counter 1: Off

ACSR=0x80:

// Global enable interrupts

#asm("sei")

init_HG();

while (1)

    {

    };

}

Звуковой генератор на частоту 1000 Гц

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

Микроконтроллер: AT90S2313.

Кварцевый резонатор: 4 МГц.

#include <90s2313.h>

// Процедура обработки прерывания Timer 1 по переполнению

interrupt [TIM1_0VF] void timer1_ovf_isr(void)

{

// Перезагрузить значение Timer 1

TCNT1H=0xff;

TCNT1L=0xfd;

if (PINB. 0–0) PORTB. 0=1; else P0RTB.0=0;

}

void main(void)

{

// Инициализация портов ввода/вывода

// Port В

DDRB=0xFF;

P0RTB=0x00;

// Port D

PORTD=0x00:

DDRD=0x00;

// Инициализация Timer 1

// Clock source: System Clock

// Clock value: 3906 kHz

// Mode: Output Compare

// OC1 output: Discon.

// Noise Canceler: Off

// Input Capture on Falling Edge

TCCR1A=0x00;

TCCR1B=0x05;

TCNT1H=0xff;

TCNT1L=0xfd;

0CR1H=0x00;

0CR1L=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization

TIMSK=0x80;

P0RTB=0x00;

while (1);

}

Модель светофора

К линиям 0, 1 и 2 порта В подсоединены соответственно красный, желтый и зеленый светодиоды.

Микроконтроллер: AT90S2313.

Кварцевый резонатор: 4 МГц.

Текст программы:

#include <90s2313.h>

// Timer 1 overflow interrupt service routine

interrupt [TIM1_0VF] void timer1_ovf_isr(void)

{

// Reinitialize Timer's 1 value

TCNT1H=0xb3;

TCNT1L=0xb5;

// Place your code here

P0RTB=P0RTB<<1;

if (PINB,2==1) P0RTB=0x01;

}

// Declare your global variables here

void main(void)

{

// Declare your local variables here

// Input/Output Ports initialization

// Port В

DDRB=0xFF;

P0RTB=0x00;

// Port D

P0RTD=0x00;

DDRD=0x00;

// Timer/Counter 1 initialization

// Clock source: System Clock

// Clock value: 3906 kHz

// Mode: Output Compare

// OC1 output: Discon.

// Noise Canceler: Off

// Input Capture on Falling Edge

TCCR1A=0x00;

TCCR1B=0x05;

TCNT1H=0xb3;

TCNT1L=0xb5;

0CR1H=0x00;

OCR1L=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization

TIMSK=0xB0;

P0RTB=0x01;

while (1);

}