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

Этот компилятор принципиально отличается от описанных выше тем, что он бесплатно распространяется, но при этом не имеет вообще никаких ограничений. Дело в том, что первоначальный вариант компилятора существовал (и существует) для операционной системы Линукс, практически, это — тот же компилятор, адаптированный для работы в среде Windows. По этой причине им несколько непривычно пользоваться, но он имеет достаточно неплохие характеристики.

Нижеприведенные программы идут в комплекте с свободно распространяемым компилятором AYR GCC.

Мигание светодиодами

Автор: Volker Oth.

Мигает светодиодами на плате STK200.

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

#include <io.h>

typedef unsigned char u08;

int main(void)

{

   u08 led, i, j, k;

   outp(0xff.DDRB); /* Все выводы порта В работают на вывод

   led = 1; /* Инициализировать начальное состояние */

   for (;;) {

       outp("led, PORTB); /* Инвертировать выход. 0 — светодиод включен */

       led <<= 1; /* К следующему светодиоду */

       if (!led) /* Переполнение: снова начать с линии В0 */

          led = 1;

       for (i=0; i<255; i++) /* Цикл формирования временной задержки */

           for(j=0; j<255;j++) /* Вложенный цикл формирования временной задержки */

               k++; /* Произвольное действие чтобы чем-то "занять" микроконтроллер */

      }

}

Мигание светодиодами с использованием таймера 0

Автор: Volker Oth.

Мигает светодиодами, подключенными к порту В под управлением таймера 0.

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

#include <io.h>

#include <interrupt.h>

#include <signal.h>

unsigned char led;

SIGNAL(SIG_OVERFLOW0) /* Обработчик прерывания переполнения таймера 0 */

{

   outp("led, PORTB); /* Инвертировать выходные линии. 0 — светодиод горит */

   led <<= 1; /* К следующему светодиоду */

   if (!led) /* Переполнение; начать снова с линии В0 */

      led = 1;

   outp(0, TCNT0); /* Сбросить таймер, для возможности повторного «прерывания */

}

int main(void) {

{

   outp(0xff,DDRB); /* Все выводы порта В работают на вывод */

   outp((1<<TOIE0), TIMSK); /* Разрешить прерывание по переполнению таймера 0 */

   outp(0, TCNT0); /* Сбросить (обнулить) TCNTO */

   outp(5. TCCR0); /* Включить предварительное деление СК/1024 */

   led = 1; /* Инициализация начального состояния светодиодов» */

   sei(); /* Разрешить прерывания «/

   for (;;) {} /* Бесконечный цикл */

Иллюстрация использования внешних прерываний INT0 и INT1 и препроцессора

Автор: Volker Oth.

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

#include <io.h>

#include <signal.h>

#include <interrupt.h>

#ifdef AVR_ATmega103

   #define AVR_MEGA 1

#else

   #ifdef AVR_ATmega603

      #define AVR_MEGA 2

   #else

     #ifdef AVR_ATmega161

       #define AVRMEGA 3

     #else

       #define AVR_MEGA 0

     #endif

   #endif

#endif

typedef unsigned char u08;

SIGNAL(SIG_INTERRUPTO) /* Обработчик внешнего прерывания into */

{

    register u08 led = mp(PORTB);

      if (led & 1)

         led &=  ~0x0f; else

      led |= 0x0f;

      out(led, PORTB); /* Зажечь светодиоды */

}

SIGNAL(SIG_INTERRUPT1) /* Обработчик внешнего прерывания int1 */

{

   register u08 led = inp(PORTB);

   if (led & 0x80)

      led &= ~0xf0;

   else

      led |= 0xf0;

   outp(led, PORTB); /* Зажечь светодиоды */

}

int main(void)

{

   outp(0xff, DDRB); /* Все линии порта В на вывод (светодиоды) */

   outp(0x00, DDRD); /* Все линии порта D на ввод (кнопки) */

#if AVR_MEGA

   outp((1<<INT0)|(1<<INT1),EIMSK); /* Разрешить внешние прерывания into, inti */

#else

   outp((1<<INT0)|(1<<INT1),GIMSK); /* Разрешить внешние прерывания into, inti */

   outp((1<<ISC01)|(1<<ISC10)|(1<<ISC11),MCUCR); /* По спаду: int0, no нарастанию: int1 */

#endif

   sei(); /* Разрешить прерывания */

   for (;;) {} /* Бесконечный цикл */

}

Иллюстрация применения UART

Автор: Volker Oth.

Иллюстрация применения UART. Работает совместно с программой terminal или подобной.

Формат UART: 9600 бод, 8 битов, 1 стоп-бит, без проверки четности.

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

#include <io.h>

#include <interrupt.h>

#include <signal.h>

#define F_CPU 4000000 /* 4 МГц */

#define UART_BAUD_RATE 9600 /* 9600 бод */

#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*161)-1)

typedef unsigned char u08;

typedef char s08;

typedef unsigned short u16;

typedef short s16;

static volatile u08 *uart_data_ptr;

static volatile u08 uart_counter;

SIGNAL(SIG_UART_TRANS) /* Обработчик прерывания UART txd готов */

{

   uart_data_ptr++;

   if (--uart_counter)

       outp(*uart_data_ptr, UDR); /* Записать байт в буфер данных */

}

SIGNAL(SIG_UART_RECV) /* Обработчик прерывания "прием завершен" */

{

    register char led;

   led = inp(UDR); /* Прочитать байт из буфера данных UART */

   outp(~led, PORTB); /* Отобразить полученный байт на светодиодах, подключенных к порту В */

}

void uart_send(u08 *buf, u08

{

   if (!uart_counter) { «Записать первый байт в буфер данных */

      uart_data_ptr = buf;

      uart_counter = size;

      outp(*buf, UDR);

   }

}

void uart_init(void) /* Инициализировать UART */

{ /* разрешить прерывания RxD/TxD */

    outp((1<<RXCIE)|(1<<TXCIE)I(1<<RXEN)|(1<<TXEN),UCR);

    /* установить скорость */

    outp((uD8)UART_BAUD_SELECT, UBRR);

}

int main(void)

}

   outp(0xff,DDRB); /* Все линии порта В на вывод */

   outp(0x00, PORTB); /* Зажечь светодиоды */

   uart_init();

   sei(); /* Разрешить прерывания */

   for (;;) { /* Бесконечный цикл */

       uart_send("Serlal Data from AVR received###", 32);

   }

}

Работа с EEPROM и UART

Автор: Volker Oth.

Читает и записывает EEPROM. При возникновении прерывания UART «передача завершена», содержимое EEPROM пересылается на компьютер. После получения байта от компьютера прерывание «прием завершен» отображает полученный байт на светодиодах и сохраняет его в EEPROM. Формат UART: 9600 бод, 8 битов, 1 стоп-бит, без проверки четности.

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

#include <io.h>

#include «interrupt. h>

#include «signal. h>

#include «eeprom.h>

#define F_CPU 4000000 /* 4 МГц */

#define UART_BAUD_RATE 9600 /* 9600 бод */

#define EEPR0M_SIZE (E2END+1)

#define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*161)-1)

typedef unsigned char u08;

typedef char s08;

typedef unsigned short u16;

typedef short s16:

u16 read_counter; u16

write_counter;

SIGNAl(SIG_UART_RECV) /* Обработчик прерывания “прием завершен" */

{

   register u08 ee_write;

   ee_write = inp(UDR); /* Прочитать байт из буфера данных UART */

   outp(~ee_write, PORTB); /* Отобразить байт на светодиодах */

   eeprom_wb(write_counter, ee_write); /* Записать байт в EEPROM»/

   if (++write_counter >= EEPR0M_SIZE) /* Переполнение: установить смещение 0 */

      write_counter = 0;

}

SIGNAL(SIG_UART_TRANS) /* Обработчик прерывания "передача завершена" */

{

   register u08 ee_read;

   ee_read = eeprom_rb(read_counter); /* Прочитать следующий байт из EEprom */

   outp(ee_read, UDR); /* Записать байт в буфер данных UART */

   if (++read_counter >= write_counter) /* Переполнение: начать с 1-го символа */

      read_counter = 0;

}

int main(void)

{

   outp(0xff,DDRB); /* Все линии порта В на вывод */

   outp(0x00, PORTB); /* Зажечь все светодиоды */

   /* Разрешить прерывания RxD/TxD */

   outp((1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN),UCR);

   /* Установить скорость 9600 */

   outp(UART_BAUD_SELECT, UBRR);

   sei (); /* разрешить прерывания */

   read_counter = 0; /* Начать читать с первого байта в EEPROM */

   write_counter = 0; /* Начать запись с первого байта в EEPROH */

   outp('#', UDRi); /* Записать 1-й байт в буфер данных UART */

    for (;;) {} /* Бесконечный цикл */

}

Демонстрирует использование библиотеки вычислений с плавающей запятой

Автор: Volker Oth.

Демонстрирует использование библиотеки вычислений с плавающей запятой. Выполняет 4 основных арифметических операции. Результаты преобразуются в 16-битовый формат с фиксированной точкой и передаются на настольный ПК с помощью UART. Результаты могут быть просмотрены с помощью программы terminal или подобной:

$0000 (start identifier)

$006b = 107 = 10.0*(7.5+3.2)

$002b = 43 = 10.0*(7.5–3.2)

$00f0 = 240 = 10.0*(7.5*3.2)

$0017 = 23 = 10.0*(7.5/3.2)

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

#include <io.h>

#include <interrupt.h>

#include <signal.h>

#define F_CPU 4000000

#define UART_BAUD_RATE 9600

#define UART_BAUD_SE LEOT (F_CPU/(UARr_BAUD_RATE*161)-1)

typedef unsigned char u08;

typedef char s08;

typedef unsigned short u16;

typedef short s16;

u08 uart_ready;

U08 *uart_data_ptr;

s08 uart_counter;

s16 result_buf[5]; /* Буфер результата */

float a_buf[2] = {7.};

SIGNAl(SIG_UART_TRANS) /* Обработчик прерывания uart txd готов*/

{

   uart_data_ptr++;

   uart_counter-;

   if (uart_counter>0)

      outp(*uart_data_ptr, UDR); /* Записать байт в буфер данных */

   else

       uart_ready = 1; /* Готов отсылать */

}

void uart_send(u08 *buf, u08 size) /* Послать буфер на uart */

{ /* Записать первый байт в буфер данных */

   if (!uart_ready) return;

   uart_ready = 0; /* Не готов отсылать */

   uart_data_ptr = buf;

   uart_counter = size:

   outp(*buf, UDR);

}

void calc(float a, float b)

{

   result_buf[0] = 0;

   result_buf[1] = (a+b)*10.0;

   result_buf[2] = (а-Ь)*10.0;

   result_buf[3] = (a*b)*10.0;

   result_buf[4] = (а/Ь)*10.0;

}

int main(void)

{

   / Разрешить прерывания RxD/TxD */

   outp((1<<RXCIE)|(1<<TXCIE)|(1<<TXEN),UCR);

   /«Установить скорость */

   outp((u08)UART_BAUD_SELECT, UBRR);

   uart_ready =1; /* Готов отсылать */

   sei(); /* Разрешить прерывания */

   for (;;) { /* Бесконечный цикл */

      calc(7.5, 3.2);

      uart_send((u08*)result_buf, 5*sizeof(s16));

   }

}

Простейшие приемы печати и чтения UART

Автор: Volker Oth.

Назначение: демонстрирует простейшие приемы печати и чтения UART.

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

#include "uart.h"

#include <progmem.h>

int main(void)

{

   u08 data;

   UART_Init(); /* Инициализация UART */

   PRINT(“Hello World!");

   EOL();

   for (;;) { /* Бесконечный цикл */

      PRINT("Press any key…");

      EOL();

      data = UART_ReceiveByte();

      PRINTC'You pressed "');

      UART_SendByte(data);

      PRINT("' whicn is 0x");

      UART_Printfu08(data);

      PRINT(" in hexadecimal.");

      EOL();

   }

}

Получение доступа к данным в памяти программ

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

#include <io.h>

#include <progmem.h>

typedef unsigned char u08;

u08 __attribute__ ((progmem)) leds[]={0xff, 0xe7, 0хс3, 0x81, 0x00, 0x81, 0хс3, 0xe7};

int main(void)

{

   u08 i, j, k, l

   outp(0xff.DDRB); / Все выводы порта В на вывод */

   for (;;) {

      for (1=0; l<< sizeof(leds);l++) {

         outр(PRG_RDB(&leds[1]), PORTB):

         for (i=0; i<255; i++) /* Цикл временной задержки */

            for(j=0; j<255;j++) /* Вложенный цикл временной задержки */

               k++; /* Любая операция (чтобы "занять" процессор) /

      }

   }

}