AVR раз, два, три... бай-ру   это просто!

Курс  Начинающим:   МикроКонтроллеры 
AVR "с нуля" на языке Си

- задача 01 -

Цель задачи:  

1) получить основные навыки работы с компилятором Си для МК AVR от компании ImageCraft.

2) получить файл work.hex - это "прошивка" готовая для загрузки в МК или для проверки работы на эмуляторе.   

Задание составлено на основе Application Note AVR031 "Getting Started with ImageCraft C for AVR"  компании Atmel - в котором рассказывается как начать работать с этим компилятором (этот документ находится и в папке где установлен компилятор).



Для работы над задачей необходимы:

- Установленый в директорию по умолчанию (C:\ICC) компилятор ImageCraft 

- Data Sheet на МК AVR AT90s2313

- Скачаные
AVR 8-Bit RISC - Application Notes


Открываем указанный выше .pdf 

Features

• How to Open a New Project
• Description of Option Settings
• Writing and Compiling the C Code
• How to Load the Executable File into the
STK200 Starter Kit

Мы выполним 3 первых пункта, 4 пункт - прошивка МК установленого в плату разработчика, вы почитайте но делать его пока не будем. 

1) Как создать новый проект в компиляторе:

проделайте путь описанный в документе по созданию проекта  - при этом выберите папку для проекта "c:\icc\work", тогда:  

- файл исходного текста Си будет называться work.с (создается в п. 3)

- файл поекта  - work.prj

- файл результат компиляции - work.hex 


2) Описание установок компилятора

Прочитайте и сделайте (не нужно менять "Paths" в разделе "Settings in Project>Options")

3) Написание и компиляция кода программы на Си

После создания проекта WORK и и установки опций компилятора можно приступить к написанию текста программы.

Предлагается простая программка инкрементирующая (значит - увеличивающая на единицу) значение в порте B (PORTB) МК, к выводам которого подключены 8 светодиодов (eight LEDs).

Компилятор использует названия "Железа" (переферии, хадвэа и т.п.) МК в точном соответствии с Data Sheet!



Мы проверим работу откомпилированной программы в эмуляторе (в задаче 02), но только с 5-ю светодиодами - столько есть в эмуляторе 

Вместо трех других светодиодов используем виртуальный осциллограф эмулятора - посмотрим сигналы на соответствующих ножках МК!



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

 

Создадим файл исходного текста программы work.c

- выбирете  “File>New” или click по иконке “New”.

- в появившемся окне введите название файла "work.c" и сохраните “File>SaveAs”. 


Мы условились сохранять проект в папке
c:\icc\work”.. 
Так нам проще будет общаться - 
и решать проблемы.




Листинг программы на языке Си для МК  AT90S2313 (набран черным цветом)


#include <io2313.h>
  // Включить вместо этой 
   
// строки текстовый файл - io2313.h   

препроцессор компилятора, перед компиляцией в место этой строчки просто вставит  текст всего файла -
io2313.h 
- он содержит описание "железа" МК на синтаксисе языка Си, чтобы компилятор знал, что по какому адресу находится и как называется в конкретном МК. 


Найдите в папках где установлен компилятор и просмотрите этот файл - интересно!
  


void initialization(void);
void delay(void);


Прототипы функций которые мы будем использовать (простой список-перечисление на память!). 

В Си рекомендуется перечислить все функции которые мы напишем и будем использовать в нашей программе. После каждой функции можно написать комментарий - что она делает и т.д.


Ниже идут тексты кода этих функций:



1. функция "инициализации железа" МК - она конфигурирует аппаратные средства МК в соответствии с решаемой нами задачей:

void initialization(void)
< здесь точку с запятой НЕ СТАВИТЬ!
{

DDRB = 0xff;     // set PORTB as output


Записать число -1111 1111-  в регистр МК  DDRB (этот регистр управляет направлением работы выводов МК: "вход - выход").  

Мы установили этой строчкой направление работы порта B на "выход" т.е. все биты DDRB "1" и соответсвующие выводы МК стали выходами. 

Запись "0" в какой либо бит DDRx означает что соответствующая ножка МК будет входом. 


Например "1100 0001" в  DDRB - значит что 0, 6 и 7-й "биты - ножки" порта B являются выходами а биты 1-5 входами.

Десятичное число 255 можно записать как:

0xFF
в шестнадцатеричном виде  или FFh

1111 1111
в двоичном виде.    

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

Для перевода чисел из одного представления в другое начинающему можно посоветовать калькулятор WINDOWS в инженерном режиме.

Биты в байте считаются с права на лево начиная с "0"  

в других МК может быть по другому!



Каждому порту в МК AVR соответствуют минимум три регистра:

DDRx - регистр направления работы

PINх - регистр содержит значения физических (т.е. реальных) уровней сигнала на соотв. ножках МК.

PORTх - регистр в который МЫ записываем значения "1" или "0" -  которые хотим получить на соотв. ножках МК при назначении их выходом.   т.е. если соответствующий бит=1 в регистре DDRx. 


ВАЖНО! - если бит в регистре DDRx равен "0", а в такой же бит PORTх записана "1" то "ножка" МК будет "входом с подтяжкой" т.е. к ней как бы подключен резистор примерно 100-150 кОм от питания МК.

PORTB - подробно смотрим стр. 52 ДатаШит



ДатаШит вам в руки
! Особенно если выводы МК несут дополнительные функции! 

 
TCCR0 = 0x05;  // Count clock/1024

Выбрали частоту "тиканья" таймера в одну 1024 от частоты работы МК. 

см. описание таймера в ДатаШит ! Таймер тикает постоянно.


} // закрывающие скобочки не забывайте!

2. эта функция выполняет задержку в 65 мС при частоте кварца 4 мГц:

void delay(void)   // Produce a delay of  
      {                 //  65 ms  at 4 MHz

while (!(TIFR&0x02)); 
// Wait for timer0 overflow 
// flag to be set


наша программа будет сидеть в цикле while() пока условие в скобках истино - т.е. "не ноль" - на языке Си:  !(0)       "!" - означает "не"  


Так как после  while() нет скобок {...} и в строке ниже нет выполняемого кода - то после while() нужно поставить точку с запятой!

В противном случае ; не нужно!


Комбинация в скобках
while() - станет "0" то есть "ложно" когда бит1 регитстра TIFR станет равным "1" 

Это  произойдет когда значение в регистре таймера станет 255 (значит насчитано 256 тиков - от 0 до 255) - соответственно будет установлен
бит1 регистра TIFR - это "флаг переполнения таймера".

TIFR = 0x02;     // Clear overflow flag

Подготовимся засечь окончание следующей паузы. 

Для этого сделаем бит1 опять "0", записав в него лог "1" - да именно так...  Да вот так забавно решили сделать инженеры компании ATMEL. 


Почитайте описание регистра TIFR в ДатаШит МК стр. 24-25 и посмотрите, что делает запись в остальные биты регистра нулей?


"Bit 1 – TOV0

Timer/Counter0 Overflow Flag

The bit TOV0 is set (one) when an overflow occurs in Timer/Counter0. 

TOV0 is cleared by hardware when executing the corresponding interrupt handling vector.

т.е. МК и сам бы очистил флаг если бы мы использовли в программе соответствующее прерывание! но мы его не используем... так что пришлось "ручками"... 

Alternatively,
TOV0 is cleared by writing a logical “1” to the flag! 

When the SREG I-bit and TOIE0
(Timer/Counter0 Overflow Interrupt Enable) and TOV0 are set (one), the Timer/Counter0 Overflow Interrupt is executed."


}

Код любой функции должен заканчиваться фигурной скобкой! 



в программе на Си должна обязательно быть Главная функция - main()   

Ее можно считать скелетом программы:
 

void main (void)
{

initialization(); //Initialize Peripherals

Инициализировали (запустили) периферию процессора в нужном режиме вызвав соответствующую функцию.

while (1) //Forever   
{  


while(1) - очень частое применение этого цикла  - означает "Делать пока есть питание и нет прерывания" - так как в скобках "не ноль" постоянно. 


ВАЖНО: можно было написать любое число 5, 25, или 3...

Запомните в Си: "не ноль" это "истина"  а  "ложно" только "ноль" !!!


PORTB++;    // Increment PORTB  

Увеличить на 1 предыдущее значение в PORTB 

Но каково было начальное значение? при запуске МК?  

смотрим ДатаШит  стр. 52 "Initial value" под схемой регистра "PORTB" видим "Нули" - значит при запуске МК  PORTB=0 (или 0x00 или "00000000") 

Значит все светодиоды загорятся после выполнения строки
"DDRB = 0xff;"  



Типовая схема включения светодиодов - между выводом МК и "+" питания последовательно с резисторои 390-1200 Ом (на светодиоде падение напряжения примерно 2 вольта, а остальное напряжение гасится на резисторе).

Эмулятор который мы будем использовать позволяет использовать ТОЛЬКО такую схему подключения!

Но светодиод подключенный к выводу бит_0 PORTB почти мгновенно погаснет из-за выполнения строки "PORTB++;" до вызова функции задержки: 

Проверим при эмуляции в задаче 02...


delay();    // Short delay  


Задержались на 65 мС - вызвав соответствующую функцию.


}
// скобка закрывающая для While(1);

} // скобка закрывающая для main-функции.

Все - текст программы закончен.


Не все комментарии что я использовал выше допустимы в программе !!! 

Комментарии могут быть двух типов: 

// комментарии одной строкой

/* комментарии любой длины и на любое количество строк */  

в любом случае, старайтесь делать комментарии как можно подробней - ведь программу пишете для себя.

 

Идем дальше - "Including the Source File in the Project" стр. 5 AVR031 

Включаем наш файл исходного текста work.c в состав проекта и запускаем компиляцию.

 
Если текст набран без ошибок, то компиляция проходит успешно и мы получаем сообщение что использовано 6% ресурсов МК - это условная ориентировочная цифра. 

НО! когда она близка к 50% стоит задуматься о применении более мощного МК! 


Я не рассматриваю вариант когда в тексте программы есть ошибки - это был бы перевод ХЕЛПА компилятора! 

Скажу только что компилятор указывает строку в которой ошибка и коротко сообщает о ее характере.

Теперь у нас есть навыки работы с компилятором и есть файл "прошивки" для МК:

 c:\icc\work\work.hex 


Работу нашей прошивки мы будем проверять в Задаче 02


Поставленные цели достигнуты 

Задача 01 завершена.