IAR Embedded Workbench

С течением времени всегда кажется, что у соседа трава зеленее. 

В смысле, компилятор круче, проще, удобней и оптимизирует лучше.

Начнём с IAR Embedded Workbench IDE for AVR - посмотрим, как хотя бы запустить в нем проект.

Будем рассматривать язык С - без плюсов - поэтому уясним, что никаких ссылок "at" и битовых переменных тут не используется.

Теперь наш удел - это выражения типа "portLight |= 1 << _Light;" и "portButton &= ˜(1 << _Button);", где выражение типа "x |= a" заменяет длинную запись "x = x | a".

Ещё тут много всяких кнопочно-галочных настроек, которые не совсем очевидны, но без них не работает >_<
Поэтому щёлкаем "Project -> Options...":

Во вкладке "General options" - "Target" определяем конфигурацию процессора - справа от текстового поля есть кнопочка  

В "General options" - "System" есть крайне важная и крайне незаметная галочка "Enable bit definitions in I/O-Include files" - поставим её, и будет нам счастье: компилятор будет понимать не только названия регистров, но и названия битов регистров. То есть можно будет писать примерно так: "GICR |= 1 << INT0; //разрешаем внешнее прерывание INT0", и имена 'GICR' и 'INT0' будут распознаны.

//В "C/C++ Compiler" - "Language 1" ставим галочку "Multi-file Compilation" - поговаривают, что так лучше О_о

Во вкладке "C/C++ Compiler" - "Optimizations" можно поставить высокий уровень оптимизации, и объем выходного файла будет уменьшаться. Теоретически, по крайней мере.

В "Linker" - "Output" ставим галочку "Override default" и в текстовом поле пишем расширение .hex; можно вообще написать "$PROJ_FNAME$.hex" - тогда автоматом будет проставляться название проекта. Ниже, в области "Format" выбираем "Other" - "intel-standard"

После этого все должно быть хорошо)

 

Едем дальше - для написания любой программы нам потребуются несколько библиотек. Чтобы их подключить, используем директиву include:

#include <имя_файла.h>
#include "имя_файла.h"

Угловые скобки указывают компилятору, что подключаемые файлы нужно сначала искать в стандартной папке "IAR\avr\inc", а кавычки - что нужно начинать поиск с директории, в которой хранится проект.

При этом для каждого типа микроконтроллера нужно подключать свой заголовочный файл (для ATmega8 - iom8.h, для ATtiny2313 - iotiny2313.h и т.д.), но в принципе, можно подключить общие заголовочные файлы ioavr.h и inavr.h, а препроцессор уже сам разберется, что к чему - в зависимости от настроек программы.

Также в этом компиляторе будет куча define-ов - чтобы переобозвать регистры управления портов (DDRx, PORTx, PINx) - пользоваться указателями на unsigned char, как в MikroC, не получится - и на самом деле непонятно, что даже лучше) Маленький экскурс: в языке Си есть такая вещь, как препроцессор. Он способен изменить код до компиляции и работает с директивами #include, #define, #if, #ifdef и так далее.

Когда мы пишем #define three 3, то дальше препроцессор перед компиляцией заменит в программе все "three" на "3"

О насущном и обычно необходимом: где-то запрятана функция __delay(value), которая работает с миллисекундами - она есть в справке, но найти библиотеку, где она лежит, я так и не смогла - зато есть функция __delay_cycles(unsigned long int), которая работает с тактами - лежит в библиотеке "intrinsics.h" - "inavr.h" тоже на неё ссылается. Чтобы получить нужное количество секунд, надо умножить это количество на частоту в герцах.

#define CPUfreq_MHz 8 
#define delayLight_mc 300

//определяем функцию задержки в мс
void delay_ms(unsigned long time)
{
  long i;
  for(i = 0; i < time; i++)
	 __delay_cycles(CPUfreq_MHz * 1000);
}

Для примера представлена программа, мигающая светодиодиком:

//программа для attiny2313; светодиод на выводе B.0 мигает (подключаем длинную ножку светодиода к микросхеме, короткую - через резистор на землю)
#include "ioavr.h"
#include "inavr.h"

//частота работы процессора в МГц (!)
#define CPUfreq_MHz 8 

//вывод для светодиода B.0
#define  ddrLight DDRB
#define portLight PORTB
unsigned char _Light = 0;
#define delayLight_mc 300

//определяем функцию задержки в мс
void delay_ms(unsigned long time)
{
  long i;
  for(i = 0; i < time; i++)
	 __delay_cycles(CPUfreq_MHz * 1000);
}

void main(void)
{
  //инициализация порта, где будет мигать лампочка
   portLight = 0;
   ddrLight = 0;
   //инициализация светодиодика - на выход и в 1
   portLight |= 1 << _Light;
   ddrLight |= 1 << _Light;
   while(1)
   {
	  delay_ms(delayLight_mc);							//задержка
	  portLight &= ˜(1 << _Light);					//ножку в ноль - светодиод не горит
	  delay_ms(delayLight_mc);							//задержка
	  portLight |= 1 << _Light;       				//ножку в единицу - светодиод горит
   }
}

Автор - Moriam

Обсуждение на форуме