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

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

- задача 03 -

Цель задачи 03:  

1) Создать программу для МК AT90s2313 измеряющую 50 раз в секунду частоту сигнала подаваемого на "ножку" МК и отсылающую полученные данные по rs232 (например на COM порт ПК)  

2) проверить работу программы на эмуляторе Visual Micro Lab

3) научиться генерировать Си код инициализации периферии МК с помощью программы-мастера  "Application Builder" входящей в состав компилятора ImageCraft   

 
Для выполнения задачи необходимо:

- Установленный компилятор ImageCraft 

- Установленный программный эмулятор Visual Micro Lab

- Data Sheet на МК AVR AT90s2313 

- свободное время и желание.

 

Давайте зададим диапазон частот входного сигнала от 500 до 2000 Гц (в дальнейшем он может быть изменен вами по желанию).

Напрямую МК может измерять временные интервалы - т.е. мерить мы будем период сигнала - у нас он лежит в  пределах от 500 мкС до 2000 мкС

Будем использовать для хранения результата каждого измерения два байта - т.е. диапазон чисел от 0 до 65535.

Результаты будут выводится в окно "терминал" контрольной панели эмулятора - старший байт (HB), затем младший (LB). 

Окно "терминал" эмулирует работу COM порта ПК.

Результат каждого измерения будет выводиться в новой строке.

 

- сохраните файлы задачи 01 из папки work - затем очистите ее.

- Запускаем компилятор ICC

- нажмите предпоследнюю иконку "Application Builder" - этот удобный инструмент позволяет создать Си код для конфигурирования МК под нашу задачу.

Прочитайте раздел Хелп ICC 
по "Application Builder"


- в секции CPU установите 2313, а в комментариях: "Измерение частоты сигнала с выводом на rs232"

- перейдем в секцию Timer0 

поставьте галочку использовать Timer0

частоту поставьте 50 Гц  (50 раз в секунду)

выберем коэфицент пред-делителя 1024 - во столько раз реже чем тикает МК будет отсчитывать Таймер_0.

Получи сообщение что реальная частота составит 50,08 Гц а ошибка будет 0,2


Что с этим делать?
 

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

Можно наконец учесть это в ПО обработки результатов на ПК.

Способов много - выбирай любой...

Мы изменим в разделе CPU частоту кварца на 3.6864 МГц - это позволит нам поддерживать и безошибочно точную скорость на rs232 (см. ДатаШит стр.49) из списка стандартных.

вернемся в раздел Timer0 - видим частота точная, ошибка ноль. 


переходим на ярлык UART (универсальный асинхронный приемник передатчик - это аппаратный rs232). 


Давайте оценим нужную нам скорость передачи информации. 

За  1 с нам нужно передать 50 раз по 2 байта информации, причем не стоит сильно тормозить работу МК

50 х 2 х 8 = 800 бит в сек. + служебные биты  да помножить на хороший запас по скорости...  

выберем 9600 не ошибемся. 

выбираем.

ставим две галочки - использовать UART0 и разрешить передачу. 



Нажимаем "ОК" и получаем код программы любезно сгенерированный по нашему желанию. 

Посмотрим на него повнимательней.

Ага... а после "#include" прототипов функций нет! значит компилятор их не требует - учтем на будущее.


Хотя лучше перечислять прототипы - как это было в исходном коде задачи_01. Программа становится более читаемой - т.к. функцию main можно разместить выше текста самих функций, прототипы которых уже перечислены. 

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




Вот это интересно: 

PORTD = 0x7F;


7F это 0111 1111 - но бит_7 PORTD (не существует как-бы! (стр. 3 Дата Шит и подробней 56-

TCCR0 = 0x00; //stop timer
TCNT0 = 0xB8; //
считать от184 до 255
TCCR0 = 0x05; //
start timer

о! теперь знаем на будущее как остановить и как запустить таймер_0, как установить с какого числа начинать ему счет...

подробней по регистру TCNT0 см. ДШ стр. 30


Прерывания...

#pragma interrupt_handler timer0_ovf_isr:7

эта строка просто указывает компилятору название функции timer0_ovf_isr которая будет вызываться при возникновении прерывания № 7.  

Мы могли бы назвать ее и по своему усмотрению - главное сохранить формат объявления!)

Это прерывание по переполнению TIMER0  

при этом будет вызываться вот эта функция - обработчик прерывания:

void timer0_ovf_isr(void)

                 
//TIMER0 has overflowed
TCNT0 = 0xB8;
//обновить число начал счета
}

т.е. каждые 20 мс мы будем попадать в тело этой функции, измерять частоту сигнала и отправлять результат на rs232.  

Таймер0 мы запустили при инициализации периферии - теперь он считает постоянно от 0 до 255 снова 0 и так далее. 

При переходе от 255 в 0 возникает прерывание по переполнению таймера - т.е. выставляется флаг прерывания  - соответствующий бит становится равным "1" - говорят "устанавливается"

"сбросить" бит - значит сделать его нулем - "0"

Мы должны считать не от 0 а от числа 0xB8 = 184 до 255  т.е. каждые 72 тика таймера достигаем переполнения и возникает прерывание. 


посчитаем:
3.6864 МГц делим на 1024 и на 72 получим... да 50 Гц

 


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




Продолжим...


сохраните файл как work.c в папке work

создайте новый проект work.prj (см. задачу 01) в папке work.

добавьте в проект файл исходного кода work.c 


"Application Builder" - парень хороший, полезный 
но туповатый!

так что откройте меню:

проект - опции - цель

и укажите компилятору МК
AT90s2313

сам он это не делает почему-то 

 

Запустим компиляцию проекта кнопкой "билд ..." 

Ага... получили сообщение об ошибке: отсутствует главная функция main

Нужно было в Аппилдере нужный флажок отметить...

Напишем ее ручками... 

void main (void)
{

}

и вставим в самый низ исходника программы.

Ок! Теперь компиляция проходит успешно - все формальности Си соблюдены, ходя МК ничего не делает по этой программе.

Теперь нужно чтобы программа что ни будь делала.

Добавим:


void main (void)
{

init_devices();

while(1);

}

Теперь после запуска МК произойдет инициализация переферии и мы засядем в бесконечном цикле while(1) 

но 50 раз в секунду мы будем попадать в функцию обработчик прерывания - timer0_ovf_isr(void)


Давайте в эмуляторе измерим период возникновения прерываний! 

Для этого в "тело" функции  timer0_ovf_isr(void) впишем код который заставит МК сделать импульс - переход "1" - "0" - "1" - на выводе PB5  например.

для этого нужно сделать выходом PB5 


DDRB = 0x20;
// 0010 0000



...а затем сделать импульс

PORTB = 0x20; // 0010 0000     бит5=1

на PB5 появился высокий уровень "1"


сделаем паузу, чтоб импульс был заметен:

ctr=0; // обнулим переменную счетчик

while(ctr<200) // пока ctr<200 делаем {...} 
{
  ctr++;
// увеличть счетчик на 1
}

паузу сделали "в лоб" - просто посчитали до 200

обратите внимание: 
после while(ctr<200) - нет точки с запятой!

 

PORTB = 0; // 0000 0000     бит5=0

на PB5 появился низкий уровень "0"

 

ctr=0; // обнулили счетчик


о! пусть МК, что ни будь выводит в окно терминала по rs232, например:

putchar('R');
putchar('x');


в окне терминала будет последовательность печататься: 
RxRxRx...


добавьте объявление переменной для счетчика вверху текста программы, после #include 

unsigned char ctr;

окончательно функция - обработчик прерывания 
будет таким:


void timer0_ovf_isr(void)
{

TCNT0 = 0xB8;

DDRB = 0x20; // 0010 0000

PORTB = 0x20; // 0010 0000 


while(ctr<200)
{
   ctr++; 
}

PORTB = 0; 

ctr=0;

putchar('R');
putchar('x');

}


Компилируем программу.




Поработаем с эмулятором   
Visual Micro Lab
 

сохраните файлы задачи 02 и скопируйте только что полученный файл work.hex в папку work эмулятора. 

отредактируем файл проекта эмулятора work.prj - нам нужно подключить терминал для контроля посылаемой по rs232 информации.
 

; Файл-проект Эмуляции программы 
; частота -> rs232
;
; После запуска программы в порт_B 
; бит5, выводятся импульсы с периодом 
; 20 мс а на терминал символы 

; RxRxRxRx.......... 



.MICRO "AT90S2313" ; Указали МК

.POWER VDD=5 VSS=0 ; Питание 5 вольт

.CLOCK 3.6864 meg  
;частота кварца 3.6864 Mhz

.PROGRAM "work.hex"  ; что "прошито" в МК

.TRACE

.STORE 1000m

; ////////////////////////
;
; N E W ! ! !
;
; ////////////////////////

; Virtual TTY terminal. Must cross connect

X_MyRS232 TTY(9600 8) PD0 PD1

;
PD0   от RS232 в МК - окно Rx
;
;
PD1   от МК в RS232 - окно Tx
;
;
в контрольной панели эмулятора
;

; Импульс на бит_5 порта_B и сигнал  
; передачи последовательной 
; информации с ножки PD1
; будем наблюдать 
; в окне виртуального осцилографа 
; эмулятора - "Scope"

.PLOT V(PB5) V(PD1)

 

сохраните изменения файла проекта.

- запустите эмулятор
- откройте проект
- билданите проект
- откройте контрольную панель 
- откройте осциллограф
- стартуйте светофором
- спасибо за совет
- стартуйте еще раз... по-е-е-e-хали...

В терминале идут буковки, а в "скопе" вибрируют сигналы - красота...  

- остановите "красным стопом"
- разверните "скоп" на весь экран

попробуйте определить по осциллограмме передачи символов их двоичные коды.

дальше...

- "прокрутите" экран на середину эмуляции
- подгоните развертку чтоб видеть два импульса полностью


Замерьте расстояние между фронтами или спадами импульсов.

скока? 

У меня ровно 20 мС получилось.

 


Все работает 
по программе!

 

Продолжение следует... будем учиться частоту измерять в задаче 04.

можете скачать все рабочие файлы 
в архиве zad_3_1.zip