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++; /* Любая операция (чтобы "занять" процессор) /
}
}
}
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОК