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