Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лабораторні 1.doc
Скачиваний:
1
Добавлен:
09.12.2018
Размер:
1.08 Mб
Скачать

2. Ход роботи

/* Використовування LCD-функцій для дисплеїв до 2x40 символів */ /* Використовується LCD 2x16, мікроконтролер AT90S2 313. Схема підключення див. рис. 2.2. */

/* Демонструється використовування функцій запису в DDRAM LCD */ /* Демонструється вивід тексту, що містить російські букви */

#include <90s2313.h> // підключаємо заголовний файл використовуваного

// мікроконтролера AVR

/* Перед підключенням файлу lcd.h оголосимо порт, використовуваний для підключення модуля LCD */

/* Використовуємо Порт В мікроконтролера AT90S2313

Адресу порту знаходимо у файлі 90s2313.h в рядку: sfrb PORTB=0xl8; */

#asm

.equ __Icd_port=0xl8

#endasm

/* Тепер перед використовуванням LCD-функцій для дисплеїв до 2x40 символів підключимо заголовний файл lcd.h */

#include <lcd.h>

/* Визначимо тип даних byte byte==unsigned char */

typedef unsigned char byte;

/* Основна функція програми */

void main(void)

{

byte command_addr; // визначимо змінну coiranand_addr,

// для зберігання коду команди установки

// адреси осередку відеопам'яті DDRAM

/* ініціалізуємо LCD 2x16 */

lcd_init(16);

/* очистимо LCD */

lcd_clear();

/* Обчислимо значення коду команди установки адреси осередку відеопам'яті DDRAM

Адреси осередків DDRAM першого рядка LCD починаються з 0x00 Адреси осередків DDRAM другого рядка LCD починаються з 0x40 (64). Щоб одержати код команди установки адреси в DDRAM, необхідно встановити біт 7 в 1 (див. Табл. 5.35). Наступні 7 бітів (0...6) відводяться для адреси осередку відеопам'яті DDRAM */

/* Виведемо фразу "Hello!" у середину першого рядка, тобто перша буква повинна бути виведена в 5-й осередок (5-е знакомісце) першого рядка LCD

рахунок осередків починається з 0 */

command_addr=0bl0000101; // нагадаємо, що 5=0Ь00000101

/* Вивід "Hello'" */

lcd_write_byte(command_addr,'Н');

lcd_write_byte(command_addr+l,'e');

lcd_write_byte(command_addr+2,'1');

lcd_write_byte(command_addr+3,'1');

lcd_write_byte(command_addr+4,'о');

lcd_write_byte(command_addr+5,'!');

/* Виведемо фразу "Привет" в середину другого рядка, тобто перша буква повинна бути виведена в 5-й осередок (5-е знакомісце) другого рядка LCD. Відлік осередків починається з 0. Адреса необхідного осередку відеопам'яті DDRAM: 64+5=69 */

command_addr=0bll000101; // нагадаємо, що 69=0b01000101

/* Вивід "Привет" */

lcd_write_byte(command_addr,0xA8);

lcd_write_byte(command_addr+l,0x70);

lcd_write_byte(command_addr+2,0xB8);

lcd_write_byte(command_addr+3,0хВЗ);

lcd_write_byte(command_addr+4,0x65);

lcd_write_byte(command_addr+5,0xBF);

/* Завершимо програму нескінченним циклом */

while (1);

} // закриваюча дужка функції main

Результат виконання цієї програми представлений на рис.2.3.

Рисунок 2.3. - Вивід тексту, що містить російські букви.

Лабораторна робота № 3

Тема: Робота мікроконтролера з матричною клавіатурою.

Мета: вивчити основні методи роботи з матричною клавіатурою.

Розглянемо приклад, що демонструє роботу мікроконтролера з матричною клавіатурою. Мікроконтролер визначає натиснуту кнопку клавіатури і виводить її код на алфавітно-цифровий LCD-модуль.

У цьому проекті використовується матрична клавіатура, схема якої приведена на рис.3.1.

Рисунок 3.1. - Матрична клавіатура — схема і призначення виводів.

При натисненні певної кнопки клавіатури відповідний горизонтальний ряд (А, В, С або D) замикається з відповідним вертикальним стовпцем (1, 2, 3 або 4). Наприклад, при натисненні кнопки «6» між собою замкнуться ряд В і стовпець 3.

У цьому проекті міститься один початковий файл — keypad.с. Текст цього файлу з коментарями:

1: /*

2 : Демонструється клавіатура 4x4

3:

4: CodeVisionAVR З Compiler

5: (С) 2000-2002 HP InfoTech S.R.L.

6: www.hpinfotech.ro

7:

8: Чип: AT90S8515

9: Під'єднайте матричну клавіатуру таким чином:

10:

11:

12: 1 PD0-----0----1----2----3------------о+5В

13: | | | | R2

14: 2 PD1-----4----5----6----7----------

15: | | | | R3

16: 3 PD2-----8----9----10---11---------

17: | | | | R4

18: 4 PD3-----12---13---14---15---------

19: D1 | | | |

20: 5 PD4– |<| – | | |

21: D2 | | |

22: 6 PD5– |<|– –––– | |

23: D3 | |

24: 7 PD6–|<|––––––––– | Rl...R4 = 10k...47k

25: D4 | I

26: 8 PD7–|<|–––––––––––––| D1...D4 = 1N4148

27:

28: Використовуйте цифро літерний LCD 2x16, підключений

29: до роз'єму PORTC STK500 таким чином:

30:

31: [LCD] [Роз'їм PORTC STK500]

32: 1 GND - 9 GND

33: 2 +5V - 10 VCC

34: 3 VLC - управління контрастністю LCD напруга 0...1В

35: 4 RS - 1 PCO

36: 5 RD - 2 PCI

37: 6 EN - 3 PC2

38: 11 D4 - 5 PC4

39: 12 D5 -6 РС5

40: 13 D6 - 7 PC6

41: 14 D7 - 8 PC7

42: */

43: #asm

44: .equ __Icd_port=0xl5

45: #endasm

46:

47: #include <lcd.h>

48: #include <stdio.h>

49: #include <delay.h>

50: #include <90s8515.h>

51:

52: // частота кварцу [Гц]

53: #define F_XTAL 3686400L

54: // PIND0...3 будуть входами рядів

55: #define KEYIN PIND

56: // PORTD4...7 будуть виходами стовпців

57: #define KEYOUT PORTD

58: // використовуємо для ініціалізації рахунку таймера/лічильника 0

59: #define INIT_TIMER0 TCNT0=0xl00L-F_XTAL/64L/500L

60: #define FIRST_COLUMN 0x80

61: #define LAST_COLUMN 0x10

62:

63: typedef unsigned char byte;

64:

65: // збережемо тут стан кожної кнопки як біт,

66: // битий 0 буде KEY0, битий 1 KEY1,...

67: unsigned keys;

68: // буфер LCD-дисплея

69: char buf[33];

70:

71: // переривання по переповнюванню таймера/лічильника 0 кожні 2 мс

72: interrupt [TIM0_OVF] void timer0_int(void)

73: {

74: static byte key_pressed_counter=20;

75: static byte key_released_counter,column=FIRST_COLUMN;

76: static unsigned row_data,crt_key;

77:

78: // наново ініціалізуємо таймер/лічильник 0

79: INIT_TIMER0;

80: row_data<<=4;

81:

82: // одержимо групу 4 кнопок в змінній row_data

83: row_data|=~KEYIN&0xf;

84: column»=l;

85:

86: if (column==(LAST_COLUMN»l))

87: {

88: column=FIRST_COLUMN;

89: if (row_data==0) goto new_key;

90: if (key_released_counter) --key_released_counter;

91: else

92: {

93: if (--key_pressed_counter==9) crt_key=row_data;

94: else

95: {

96: if (row_data!=crt_key)

97: {

98: new_key:

99: key_pressed_counter=10;

100: key_released_counter=0;

101: goto end_.key ;

102: };

103: if (!key_pressed_counter)

104: {

105: keys=row_data;

106: key_released_counter=20;

107: };

108: };

109: };

110: end_key:;

111: row_data=0;

112: };

113: // виберемо наступний стовпець, входи будуть

114: //с підтягаючими резисторами

115: KEYOUT—column ;

116: }

117:

118: // перевіримо, чи була натиснута кнопка

119: unsigned inkey(void)

120: {

121: unsigned до;

122: if (k=keys) keys=0;

123: return до;

124: }

125:

126: void init_keypad(void)

127: {

128: DDRD=0xf0;

129: INIT_TIMER0;

130: TCCR0=3;

131: TIMSK=2;

132: #asm("sei")

133: }

134:

135: main()

136: {

137: unsigned до;

138: init_keypad();

139: lcd_init(16);

140: lcd_putsf("CVAVR Keypad");

141:

142: // прочитаємо кнопку і відобразимо її код

143: while (1)

144: {

145: lcd_gotoxy(0,1);

146: if (k=inkey())

147: {

148: sprintf(buf,"Key code=%Xh",k);

149: lcd_puts(buf);

150: }

151: else lcd_putsf("NO KEY ");

152: delay_ms(500);

153: }

154: }

У цьому файлі знаками /* (початок) і */ (кінець) виділений блок з коментарями, а знаком // — рядки з коментарями (див. Коментарі).

У блоці з коментарями (рядки 1...42) даються рекомендації по підключенню матричної клавіатури і LCD-модуля до налагоджувальної плати STK500 при апаратній реалізації даного проекту.

За відсутності налагоджувальної плати STK500 можна самостійно реалізувати цей проект по схемі, приведеній на рис.3.2. Ланцюг живлення, скидання і кварцовий резонатор мікроконтролера не показані (див. рис. 1.1).

Рисунок 3.1. - Проект «Keypad». Схема електрична принципова.

У рядках 43...45 оголошується, який порт мікроконтролера буде використаний для зв'язку з модулем LCD. Для цього в програму включений асемблерний код. Директива #asm (рядок 43) говорить компілятору про початок асемблерного коду, а директива #endasm (рядок 45) — про його завершення (див. Директиви #asm і #endasm). У рядку 44 асемблерна директива .equ привласнює ідентифікатору__lcd_port значення 0x15. Це значення, відповідне адресі регістра PORTx вибраного порту (в даному випадку вибраний Порт В), знаходимо у файлі 90s8515.h у відповідному рядку: «sfrb PORTC=0xl5;». Цей файл знаходиться в піддиректорії ..\INC.

При трансляції асемблерного коду, одержаного при компіляції даного проекту компілятором Си CodeVisionAVR, асемблер замість цього ідентифікатора підставить його значення.

У разі модифікації програми при використовуванні іншого порту для підключення LCD-модуля достатньо буде лише замінити значення у вказаній директиві .equ, не змінюючи решти тексту програми.

Докладніше про директиви асемблера див. систему допомоги безкоштовної програми AVR Studio від Atmel, яку можна викачати на сайті розробників мікроконтролерів AVR http://www.atmel.com.

Директивами #include (рядки 47...50) підключаються: LCD-функції — файл lcd.h (докладніше див. LCD-функції для дисплеїв до 2x40 символів), функції вводу/виводу — файл stdio.h (див. Стандартні функції вводу/виводу); функції затримки — файл delay.h (див. Функції затримки) і заголовний файл для використовуваного мікроконтролера AVR (AT90S8515) — файл 90s8515.h. Перед компіляцією препроцесор компілятора вставить замість цих рядків текст відповідних файлів (див. Директива #include).

Директивами #define (рядки 52...61) визначаються ідентифікатори F_XTAL, KEYIN, KEYOUT, INIT_TIMERO, FIRST_COLUMN і LAST_COLUMN. Після цих рядків перед компіляцією препроцесору компілятора замінить в тексті програми ці ідентифікатори на їх значення: F_XTAL на 3686400L, KEYIN на PIND і т.д. У разі модифікації програми для іншої частоти кварцу, для іншого порту підключення клавіатури і т.д. достатньо буде лише замінити значення у вказаних директивах #define, не змінюючи решти тексту програми (див. Директива #define, #undef).

Директива #define дуже зручна, але зовсім не обов'язкова.

У рядку 63 оголошується тип даних byte, який відповідає типу даних unsigned char (беззнаковий символьний). Як і директива #define, оператор typedef зручний, але зовсім не обов'язковий.

У рядку 67 оголошується глобальна змінна keys типу unsigned int (беззнакове ціле). Ключове слово unsigned означає unsigned int. Глобальні змінні автоматично ініціалізуються із значенням 0. У кожному біті цієї змінної зберігатиметься стан відповідної кнопки клавіатури. У біті 0 зберігатиметься стан кнопки KEY0, в біті 1 KEY1, ..., в біті 15 KEY15. Значення 1 у відповідному біті відповідає натиснутій кнопці, значення 0 — віджатої. Тобто якщо натиснута кнопка KEY6, то значення змінної keys повинне бути: 0b 0000 0000 0100 0000 = 0x0040.

У рядку 69 оголошується глобальний символьний масив (рядкова змінна) buf, що складається з 33 членів. При цьому всі елементи цього масиву автоматично ініціалізуються із значенням 0 (див. Масиви). У цьому масиві зберігатиметься інформація, призначена для виводу на LCD.

Оскільки в настройках проекту на закладці С Compiler (Компілятор Си) вибрана опція char is unsigned (байт є беззнаковим) (рис. 3.2), то всі дані типу char (байт) компілятор оброблятиме як дані типу unsigned char (беззнаковий байт), тобто масив buf складатиметься з даних типу unsigned char (беззнаковий байт).

Рядки 72... 116 — це визначення програми (функції) обслуговування переривання по переповнюванню таймера/лічильника 0 timer0_int.

У рядку 72 здійснюється доступ до системи переривань мікроконтролера AVR, на що указує ключове слово interrupt. Далі за цим ключовим словом в квадратних дужках повинен йти номер вектора переривання. Але тут замість номера стоїть ідентифікатор TIM0_OVF. Річ у тому, що цей ідентифікатор визначений директивою #define в заголовному файлі 90s8515.h.

Рисунок 3.2. - Опція char is unsigned (байт є беззнаковим) вибрана.

Перед компіляцією препроцесор компілятора замінить TIM0_OVF на цифру 8 (номер вектора переривання), як визначено у файлі 90s8515.h. Замість TIM0_OVF в квадратних дужках можна було написати 8, але TIM0_OVF більш наглядно. Далі йде ключове слово void, вказуює на те, що функція не повертає ніяких значень. Потім ім'я функції timer0_int (може бути довільним, але краще із смисловим навантаженням). За цим іменем далі у програмі здійснюється виклик даної функції. Ключове слово void в дужках указує на те, що в цю функцію не передаються ніякі параметри.

У рядку 73 відкриваюча фігурна дужка указує початок тіла програми обслуговування переривання.

У рядках 74...76 оголошуються локальні змінні різних типів із специфікатором класу пам'яті static (статичні). Такі змінні мають глобальний час життя і область видимості усередині функції, в якій вони оголошені. При виконанні програми статичні змінні ініціалізуються тільки один раз, навіть якщо функція, де вони ініціалізуються, викликається багато разів. Тип byte був визначений раніше, в рядку 63. Визначення unsigned має на увазі тип unsigned int (беззнакове ціле).

Деякі змінні відразу ініціалізуються, тобто їм привласнюються певні початкові значення. Якщо статичні змінні спеціально не ініціалізують, то при запуску програми вони автоматично встановлюються в 0.

У рядку 79 перед компіляцією препроцесор компілятора замість ідентифікатора INIT__TIMER0 підставить вираз, визначений директивою #define в рядку 59. Таким чином, у цьому рядку відбувається ініціалізація таймера/лічильника 0, тобто в його регістр TCNT0 записується початкове значення, яке обчислюється за формулою TCNT0 = 0xl00L - F_XTAL/64L/500L. У цій формулі перед компіляцією препроцесор замінить ідентифікатор F__XTAL на 3686400L (див. рядок 53). Буква L в кінці чисел означає, що ці константи мають тип long integer (довге ціле).

Спочатку, згідно пріоритетам операцій, зліва направо виконуються операції розподілу (знак операції /, пріоритет 3). Після цього виконується операція віднімання (знак операції —, пріоритет 4). Всі обчислення ведуться з довгими цілими, щоб не втратити значущі цифри. На закінчення значення результату всіх операцій записується (привласнюється) в регістр TCNT0 (знак операції /, пріоритет 14).

У рядку 80 здійснюється операція здвигу вліво з привласненням (знак операції — <<=) поточного значення змінної row_data. Значення здвигається вліво на 4 біти, тобто значення 0-го біта перейде в 4-й біт, 1-го — в 5-й, ..., 11-го — в 15-й. Молодші 4 біти (з 0-го по 3-й) заповнюються нулями. Таким чином, значення змінної row_data здвигається на один нібл (півбайт, або 4 біти) вліво. Молодший нібл заповнюється нулями. Набуте значення привласнюється змінній row_data. Її значення стане рівним 0b ХХХХ ХХХХ ХХХХ 0000, де ХХХХХХХХХХХХ — значення трьох молодших ніблів змінною row_data до операції. Значення найстаршого ніблу змінній row_data після цієї операції пропадає.

Вираз в рядку 83 розглянемо докладніше.

Перед компіляцією препроцесор замінить ідентифікатор KEYIN на PIND (див. рядок 55). PIND — це значення, отримане з регістра PINx Порту D, тобто значення логічних рівнів, які до теперішнього часу присутні на фізичних (тобто реальних) виводах Порту D.

Відповідно до пріоритетів операцій порядок обчислення виразу наступний. Спочатку прочитується поточне значення PIND. Після цього з цим значенням виконується операція побітового логічного заперечення (знак операції ~, пріоритет 2). Після її виконання все 1 в значенні PIND замінюються на 0, а 0 — на 1. Потім виконується операція побітного І (знак операції &, пріоритет 8), набутого значення з числом 0xf = 0b 0000 1111. При цьому кожен біт першого операнда порівнюється з відповідним бітом другого операнда. Якщо обидва порівнювані біти 1, то відповідний біт результату встановлюється в 1, інакше — в 0. У результаті виходить значення 0b 0000 YYYY, де YYYY — значення молодшого ніблу, тобто бітів 0...3, регістра PIND, в якому 0 замінений на 1, а 1 — на 0.

Останній здійснюється операція побітного АБО з привласненням (знак операції — |=, пріоритет 14) поточного значення змінної row_data (0b XXXX ХХХХ ХХХХ 0000) і результату попередніх операцій (0Ь 0000 YYYY). При цьому кожен біт першого операнда порівнюється з відповідним бітом другого. Якщо будь-який (або обидва) з порівнюваних бітів рівний 1, то відповідний біт результату встановлюється в 1, інакше — в 0 (див. Бінарні операції). Набуте значення (0Ь ХХХХ ХХХХ ХХХХ YYYY) привласнюється змінній row__data.

У рядку 84 здійснюється операція здвигу вправо з привласненням (знак операції »=) поточного значення змінної column. Значення здвигається вправо на 1 біт, тобто значення 7-го біта переходить ву6-й біт, 6-го — в 5-й, ..., 1-го — в 0-й. Значення 0-го біта пропаде, а в 7-й біт записується 0. Набуте значення привласнюється змінній column.

У рядках 86... 112 знаходиться укорочений оператор if-else (без else).

У рядку 86 — початок цього оператора, на що указує ключове слово if. Вираз в дужках (умова оператора if-else) обчислюється в наступному порядку. Спочатку значення LAST__COLUMN (препроцесор підставить замість нього число 0x10 = 0Ь 0001 0000, див. рядок 61) зсовується управо на 1 біт (знак операції »). Потім набуте значення (0x08 = 0Ь 0000 1000) порівнюється із значенням змінної column, одержаним в попередньому рядку програми. Якщо вони рівні — вираз істинний, якщо ні — хибний.

Якщо вираз в дужках істинний (тобто значення виразу відмінне від нуля), то виконуватиметься група операторів (складовий оператор), зазначена у фігурних дужках, що знаходяться в рядках 87 (відкриваюча дужка) і 112 (закриваюча дужка). Тобто виконуватиметься тіло оператора if-else. Після цього виконання програми продовжується з рядка 115. Якщо вираз у дужках хибний (значення виразу рівне нулю), то виконання програми відразу переходить на рядок 115, тобто тіло оператора if-else виконуватися не буде.

У складовому операторі в рядку 88 змінної column привласнюється значення FIRST__COLUMN (препроцесор підставить замість нього число 0x80 = 0Ь 1000 0000, див. рядок 60).

У рядку 89 знаходиться укорочений оператор if-else (без else). Оскільки в його тілі всього один оператор, вся конструкція записана в один рядок, без фігурних дужок. У умові оператора if-else (у дужках) перевіряється поточне значення змінної row__data, і якщо воно рівне 0 (рівність істинна), то виконується oпeратор goto, який здійснює перехід виконання програми на мітку new_key (на рядок 98). Якщо значення змінної row__data не дорівнює 0 (рівність помилкова), виконується наступний оператор (рядок 90).

У рядку 90 також знаходиться оператор if-else. У умові цього оператора if-else (у дужках) перевіряється поточне значення змінної key__released__counter, і якщо воно не рівне 0 (істина), то виконується операція дикремента (знак операції —), тобто значення змінної key__released__counter зменшується на 1 (див. Унарні операції), і виконання програми переходить на рядок 91. Якщо значення змінної key__released__counter рівно 0 (брехня), те виконання програми відразу переходить на рядок 91.

У рядку 91 знаходиться ключове слово else оператора if-else, що означає початок групи операторів (складовий оператор), які виконуватимуться, якщо умова оператора if-else (рядок 90) помилкова. Складовий оператор наведений у фігурних дужках, що знаходяться в рядках 92 (відкриваюча дужка) і 109 (закриваюча дужка).

У рядку 93 в умові чергового оператора if-else перевіряється вираз, що стоїть в дужках. Цей вираз обчислюється в наступному порядку. Спочатку значення змінної key_pressed__counter дикрементується (знак операції —), тобто зменшується на 1. Потім набуте значення порівнюється з числом 9. Якщо вони рівні, вираз істинний, якщо ні — хибний. Якщо вираз істинний, то змінною crt__key привласнюється поточне значення змінної row_data, і виконання програми переходить на рядок 109 (точніше, 111, оскільки в рядках 109, 110 немає виконуваних операторів). Якщо вираз, що стоїть в дужках, хибний, то виконання програми переходить на рядок 94.

У рядку 94 знаходиться ключове слово else оператора if-else, що означає початок групи операторів (складовий оператор), які виконуватимуться, якщо умова оператора if-else (рядок 93) помилкова. Складовий оператор укладений у фігурні дужки, що знаходяться в рядках 95 (відкриваюча дужка) і 108 (закриваюча дужка).

У рядку 96 в умові оператора if-else перевіряється вираз, що стоїть в дужках. Цей вираз буде істинний, якщо значення змінної row__data не дорівнює значенню змінної crt__key (знак операції !=), інакше вираз хибний. Якщо вираз істинний, то виконується група операторів (складовий оператор), наведена у фігурних дужках, що знаходяться в рядках 97 (відкриваюча дужка) і 102 (закриваюча дужка). Якщо вираз, що стоїть в дужках, хибний, то виконання програми переходить на рядок 103.

У рядку 98 знаходиться мітка new__key. Вона використовуються тільки для вказівки місця, куди передається управління оператором goto, що знаходиться в рядку 89.

У рядку 99 змінної key_pressed_counter привласнюється значення 10.

У рядку 100 змінної key_released__counter привласнюється значення 0.

У рядку 101 оператор goto (див. Оператор goto) здійснює перехід виконання програми на мітку end__key (на рядок 110).

У рядку 103 в умові оператора if-else перевіряється вираз, що стоїть в дужках. Цей вираз буде істинний (не нуль), якщо значення змінної key__pressed__counter рівно 0, оскільки операція логічного заперечення (знак операції !) не надає значення 0, якщо операнд є істина, і значення 1, якщо

операнд є хибне (нуль). Інакше вираз хибний. Вираз в дужках (!key__pressed__counter) в даному випадку можна замінити іншим: (key_pressed_counter == 0).

Якщо вираз в дужках істинний, то виконується група операторів (складовий оператор), наведена у фігурних дужках, що знаходяться в рядках 104 (відкриваюча дужка) і 107 (закриваюча дужка). Якщо вираз, що стоїть в дужках, помилково, то виконання програми переходить на рядок 108 (точніше, 111, оскільки в рядках 108... 110 немає виконуваних операторів).

У рядку 105 глобальної змінної keys привласнюється поточне значення локальної змінної row_data.

У рядку 106 змінної keyjreleased__counter привласнюється значення 20.

У рядку 110 знаходиться мітка end__key. Вона використовуються тільки для вказівки місця, куди передається управління оператором goto, що знаходиться в рядку 101.

У рядку 111 змінної row__data привласнюється значення 0.

У рядку 115 перед компіляцією препроцесор замінить ідентифікатор KEYOUT на PORTD (див. рядок 57). Таким чином, в цьому виразі спочатку береться значення змінної column, в якому все 0 замінюються на 1, а 1 — на 0 (операція побітового логічного заперечення, знак операції ~), а потім одержаний результат записується в регістр PORTx Порту D. При цьому значенні змінної column не змінюються.

На цьому виконання програми (функції) обслуговування переривання по переповнюванню таймера/лічильника 0 закінчується.

Функція timer0_int здійснює опитування клавіатури. Кожен вивід молодшого ніблу Порту D (PD0...PD3) конфігурований як вхід (див. нижче функцію init__keypad, рядок 128) і підключений до відповідного ряду клавіатури (див. рис. 3.1). Кожен вивід старшого ніблу Порту D (PD4...PD7) конфігурований як вихід і через діод (VD1...VD4) підключений до відповідного стовпця клавіатури. Спочатку на всіх чотирьох виводах молодшого ніблу Порту D (PD0...PD3) присутній рівень логічної 1 завдяки підтягаючим резисторам R1...R4.

Алгоритм опитування наступний. На кожен вивід старшого ніблу Порту D (PD4...PD7) послідовно подається рівень логічного 0, прочитується значення молодшого ніблу Порту D і записується в молодший нібл змінною row__data, причому попереднє значення змінної row__data заздалегідь здвигається на один нібл вліво. Якщо в поточному стовпці (на який поданий 0) є натиснута кнопка, то на входах в біті, який відповідає ряду з натиснутою кнопкою, також з'явиться 0. Таким чином, у змінній row__data міститься код натиснутої кнопки.

Алгоритм роботи функції timer0__int представлений блок-схемою на рис.3.3.

Блок 1 виконується тільки один раз при найпершому виклику функції timer0_int, оскільки всі локальні змінні цієї функції оголошені з класом пам'яті static. При подальших викликах функції timer0_int блок 1 ігнорується.

Вся решта блоків функції timer0_int виконується (відповідно до алгоритму) при кожному виклику цієї функції.

У блоці 2 відбувається нова ініціалізація таймера/лічильника 0, тобто починається новий відлік таймера/лічильника 0 для ініціації наступного переривання (див. рядок 79 програми) по його переповнюванню.

У блоці 3 відбувається здвиг з привласненням значення змінної row_data на 1 нібл (4 біти) вліво (див. рядок 80 програми).

У блоці 4 визначається поточне значення регістру PIND; у цьому значенні все 1 замінюються на 0, а 0 — на 1, і набуте значення заноситься в молодший нібл змінною row_data (див. рядок 83 програми).

У блоці 5 відбувається здвиг з привласненням значення змінної column на 1 біт управо (див. рядок 84 програми). Якщо набуте значення не дорівнює виразу LAST__COLUMN >>1 (блок 6), то все 1 в значенні змінної column замінюються на 0, а 0 — на 1, і набуте значення записується в регістр PORTD (блок 18), і виконання функції timer0__int закінчується.

Рисунок 3.3. - Блок-схема функції timer0_int.

Після чотирьох викликів функції timer0_int клавіатура буде повністю опитана, а в змінній row_data знаходитиметься код натиснутої кнопки клавіатури. Якщо жодна кнопка не натиснута, то в змінній row_data буде значення 0b 0000 0000 0000 0000. Поточне значення змінної row_data привласнюється змінній crt__key.

Потім повний цикл опиту клавіатури для визначення натиснутої кнопки (чотирикратне повторення ланцюжка 2→3→4→5→6→18) повторюється 10 разів (10 - значення змінної key__pressed__counter у блоці 14). Після кожного разу порівнюються значення змінних row__data і crt__key (блок 13) і, якщо всі 10 разів вони були рівними, то значення змінної row_data привласнюється змінній keys (блок 16). Якщо значення змінних row__data і crt__key хоч раз виявилися не рівні, то повний цикл опиту клавіатури для визначення натиснутої кнопки знову повторюється 10 разів (змінною key_pressed_counter у блоці 14 знову привласнюється значення 10). Таким чином, зменшуються помилки, пов'язані з брязкотом контактів, нечітким натисненням кнопки клавіатури і т.д.

Після того, як значення змінної row__data привласнено змінній keys, тобто визначена натиснута кнопка клавіатури, починається опит клавіатури для визначення моменту відпуску кнопки. Знову здійснюється повний цикл опиту клавіатури (чотирикратне повторення ланцюжка 2→3→4→5→6→18). Кількість повних циклів задається значенням змінної key_released__counter у блоці 16. Після кожного циклу опиту перевіряється умова рівності значення змінної row__data нулю (блок 16), що є критерієм того, що всі кнопки віджаті (немає натиснутих кнопок). Якщо умова виконується, то починається новий цикл опиту клавіатури для визначення натиснутої кнопки. Якщо ні, то опит клавіатури для визначення моменту відпуску кнопки повторюється.

На цьому закінчимо опис функції timer0_int і повернемося до опису решти частини програми.

Рядки 119... 124 — це визначення функції inkey.

У рядку 119 здійснюється оголошення функції inkey. Визначник unsigned (мається на увазі unsigned int (беззнакове ціле) задає тип значення, яке повертає функція. Далі слідує ім'я функції inkey (може бути довільним). За цим іменем далі у програмі здійснюється виклик даної функції. Ключове слово void у дужках указує на те, що в цю функцію не передаються ніякі параметри.

У рядку 120 відкриваюча фігурна дужка вказує на початок тіла функції inkey.

У рядку 121 оголошується локальна змінна k типу unsigned int (беззнакове ціле). Ключове слово unsigned у дужках означає unsigned int.

У рядку 122 знаходиться укорочений оператор if-else (без else). Оскільки в його тілі всього один оператор, вся конструкція записана в один рядок, без фігурних дужок. У умові оператора if-else (у дужках) локальній змінній k привласнюється значення глобальної змінної keys, і якщо воно не рівне 0 (істинно), то глобальній змінній keys привласнюється значення 0 і виконується наступний оператор (рядок 123). Якщо значення змінної k після привласнення рівно 0 (помилково), то відразу виконується наступний оператор (рядок 123).

У рядку 123 знаходиться оператор return, який завершує виконання функції, в якій він заданий, і повертає управління в зухвалу функцію. Значення виразу, що стоїть за оператором return, повертається в зухвалу функцію як значення функції, що викликається (див. Оператор return).

У рядку 124 закриваюча фігурна дужка указує кінець тіла функції inkey.

Таким чином, функція inkey повертає значення локальної змінної до, якій привласнене значення глобальної змінної keys. Значення глобальної змінної keys після виконання функції inkey у будь-якому випадку рівне 0.

Рядки 126... 133 — це визначення функції init_keypad. Ця функція проводить ініціалізацію периферійних пристроїв мікроконтролера.

У рядку 126 здійснюється оголошення функції init_keypad. На початку стоїть ключове слово void, яке вказує на те, що ця функція не повертає ніяких значень. Далі слідує ім'я функції init_keypad (може бути довільним). За цим іменем далі у програмі здійснюється виклик даної функції. Ключове слово void в дужках указує на те, що в цю функцію не передаються ніякі параметри.

У рядку 127 відкриваюча фігурна дужка указує початок тіла функції init_keypad.

У рядку 128 у регістр DDRx Порту D записується число 0хf0 (0xf0=0b 1111 0000), тим самим всі виводи старшого ніблу цього порту (биті PD4...PD7) стають виходами, а всі виводи молодшого ніблу (биті PD0...PD3) — входами.

У рядку 129 замість, ідентифікатора INIT_TIMER0 препроцесор компілятору підставить вираз, який визначений у рядку 59. Таким чином, в регістр TCNT0 таймера/лічильника 0 буде записане початкове значення, розраховане по відповідній формулі (див. опис рядка 79). Саме з цього значення починатиметься рахунок таймера/лічильника 0.

У рядку 130 в регістр управління таймером/лічильником 0 TCCR0 записується число 3, тим самим коефіцієнт розподілу попереднього дільника частоти таймера/лічильника 0 встановлюється рівним 64, тобто таймер/лічильник 0 працює з тактовою частотою в 64 рази менше за системну (частоти кварцу).

При таких параметрах, переривання по переповнюванню таймера/лічильника 0 відбуватимуться приблизно кожні 2 мс.

У рядку 131 в регістр маски переривання від таймерів/лічильників TIMSK записується число 2, тим самим дозволяється переривання по переповнюванню таймера/лічильника 0 (якщо встановлений глобальний дозвіл переривань).

У рядку 132 здійснюється глобальний дозвіл переривань. Для цього в програму включений асемблерний код (див. Директиви #asm і #endasm). Інструкція асемблера sei встановлює прапор глобального переривання 1 в регістрі статусу SREG мікроконтролера, тим самим дозволяючи глобальні переривання.

У рядку 133 закриваюча фігурна дужка указує на кінець тіла функції init_keypad.

Рядки 135... 154 — це визначення основної функції програми (main). Ця функція обов'язково повинна бути присутнім у всіх програмах (але тільки ОДНА!). Саме з цієї функції, в якому б місці програми вона ні знаходилася, починається виконання програми.

У рядку 135 здійснюється оголошення функції main. На початку опущене (але мається на увазі) ключове слово void, яке вказує на те, що ця функція не повертає ніяких значень; потім слідує ім'я функції main (ЙОГО ЗМІНЮВАТИ НЕ МОЖНА!). У дужках опущене (але мається на увазі) ключове слово void, яке указує на те, що в цю функцію не передаються ніякі параметри.

У рядку 136 відкриваюча фігурна дужка указує на початок тіла функції main.

У рядку 137 оголошується локальна змінна k типу unsigned int (беззнакове ціле). Ключове слово unsigned в дужках означає unsigned int. Не слід плутати її з локальною змінною k, оголошеної у функції inkey. Не дивлячись на одне ім'я, ці змінні РІЗНІ . Їх видно тільки в тих функціях, де вони оголошені (див. Змінні).

У рядку 138 здійснюється виклик функції init_keypad, яка визначена в рядках 126... 133. Ця функція ініціалізує периферійні пристрої мікроконтролера.

У рядку 139 здійснюється виклик функції lcd_init з фактичним параметром 16 (кількість стовпців у використовуваному модулі LCD). Ця функція ініціалізує модуль LCD, очищає дисплей і встановлює позицію для виводу символу в ряд 0 стовпця 0. Курсор не відображається.

У рядку 140 здійснюється виклик функції lcd_putsf, яка відображає в поточній дисплейній позиції рядок «CVAVR Keypad».

Обидві ці функції визначені в підключеному файлі lcd.h (рядок 47).

У рядках 143...153 реалізований нескінченний цикл за допомогою оператора while.

У рядку 143 — початок цього оператора, на що указує ключове слово while. Поки умова цього оператора (у дужках) істинна, тобто значення виразу відмінне від нуля, виконуватиметься група операторів (складовий оператор, тіло оператора while), наведена у фігурних дужках, що знаходяться в рядках 144 (відкриваюча дужка) і 153 (закриваюча дужка). Вираз в дужках — 1 (можна також написати 55 або 16), а не 0, тобто завжди істинно. Отже, ця група операторів виконуватиметься нескінченно, поки не відбудеться переривання програми.

У рядку 145 здійснюється виклик функції lcd_gotoxy з фактичними параметрами (0, 1). Ця функція встановлює поточну позицію дисплея відповідно в стовпець 0 і ряд 1. Нумерація рядів і стовпців починається з 0. Ця функція визначена в підключеному файлі lcd.h (рядок 47).

У рядках 146...152 знаходиться оператор if-else.

У рядку 146 - початок цього оператора, на що указує ключове слово if. Порядок обчислення виразу в дужках (умова оператора if-else) наступний. Спочатку викликається функція inkey, яка визначена в рядках 119...124. Значення, яке повертає функція inkey, привласнюється локальній змінній до. Якщо це значення рівно 0, то вираз в дужках буде хибний. У всій решті випадків вираз буде істинний.

Якщо вираз в дужках істинний, то виконуватиметься група операторів (складовий оператор), укладена у фігурні дужки, що знаходяться в рядках 147 (відкриваюча дужка) і 150 (закриваюча дужка). Після цього виконання програми буде продовжене з рядка 152. Якщо вираз в дужках хибний, то виконуватиметься оператор, що знаходиться в рядку 151.

У рядку 148 функція sprintf здійснює перетворення форматів і поміщає результати в рядок buf. Специфікація перетворення «Key code = %Xh» означає, що спочатку буде виведена послідовність «Key code =», потім значення локальної змінної k в шістнадцятерічному вигляді символами верхнього регістра (символ перетворення 'X'). Потім буде виведений символ «h». Ця функція визначена в підключеному файлі stdio.h (рядок 48).

У рядку 149 функція lcd_puts відображає в поточній дисплейній позиції вміст рядка buf, який був сформований у попередньому рядку програми.

У рядку 151 знаходиться ключове слово else оператора if-else, що означає, що цей рядок виконуватиметься, якщо умова оператора if-else (рядок 146) хибна. У цьому рядку здійснюється виклик функції lcd_putsf, яка відображає в поточній дисплейній позиції послідовність «NO KEY».

Функції lcd_puts і lcd_putsf визначені в підключеному файлі lcd.h (рядок 47).

У рядку 152 функція delay_ms генерує затримку 500 мс. Ця функція визначена в підключеному файлі delay.h (рядок 49).

У рядку 154 закриваюча фігурна дужка указує на кінець тіла функції main.

Програма працює таким чином. Після подачі живлення (або апаратного скидання на вивіду RESET мікроконтролеру) починає виконуватися функція main. Послідовно викликаються функція init_keypad, яка ініціалізує Порт D, таймер/лічильник 0 і настроює систему переривань, функція lcd_init, яка ініціалізує LCD-модуль, і функція led_putsf, яка у верхній рядок LCD-модуля виводить послідовність «CVAVR Keypad».

Після цього програма переходить у нескінченний цикл, в якому спочатку курсор LCD встановлюється в початкову позицію нижнього рядка, потім викликається функція inkey, яка повертає код натиснутих кнопок клавіатури, і цей код відображається на LCD після напису «Key code=». В кінці виводиться символ «h», що показує, що код виводиться в шістнадцятерічному вигляді. Якщо жодна кнопка не натиснута, то виводиться послідовність «NO KEY». Після цього генерується тимчасова пауза в 500 мс, і після неї нескінченний цикл повторюється знову. Під час виконання функції main (у тому числі і під час паузи в 500 мс) постійне, через кожні 2 мс, відбувається переривання по переповнюванню таймера/лічильника 0 і викликається функція timer0_int, яка здійснює опит клавіатури і залежно від натиснутих кнопок клавіатури формує відповідний код.

Код натиснутих кнопок слід інтерпретувати таким чином. Молодший (перший) біт коду відповідає стовпцю 1, старший (четвертий) — стовпцю 4. Якщо в стовпці натиснута кнопка в ряду А, то в цьому біті буде число 1, якщо в ряду В — число 2, С — 4, D — 8.

При натисненні в одному стовпці двох і більш кнопок буде виведена сума їх кодів.

Лабораторна робота № 4

Тема: Робота з аналого-цифровим перетворювачем мікроконтролеру Atmel АТ90S8535

Мета: вивчити основні методи роботи аналого-цифровим перетворювачем однокристальних мікроЕОМ

Данна робота демонструє використання внутрішнього аналого-цифрового перетворювача (АЦП) мікроконтролера AT90S8535.

Розглянемо приклад файлу, що реалізує аналого-цифрове перетворення на чипі типу AT90S8535:

1: /*

2: Приклад АЦП для AT90S8535 на

3: платні Atmel STK500

4:

5: CodeVisionAVR З Compiler

6: © Copyright 2001-2002 HP InfoTech S.R.L.

7: www.hpinfotech.ro

8:

9: Встановіть наступні перемички на платні STK500:

10: VTARGET, AREF, RESET, XTAL1, OSCSEL: 1-2

11:

12: З'єднайте роз'єми P0RTB і LEDS з допомогою

13: 10-жильного плоского кабелю

14:

15: З'єднайте роз'єми ISP6PIN і SPROG3 з допомогою

16: 6-жильного плоского кабелю

17:

18: AT90S8535 повинен бути розташований в панельке SCKT3100A3

19:

20: У AVR Studio у вікні Tools ISTK500I Board встановити:

21: - VTarget=5V

22: - ARef=5V

23: - 0scillator=3.69МГц

24:

25: Подайте позитивну DC напругу в діпазоне 0...5V

26: між висновками РАО і GND роз'єму PORTA

27: */

28:

29: // визначення регістрів вводу/виводу для AT90S8535

30: #іnclude <90s8535.h>

31: // функції затримки

32: #include <delay.h>

33:

34: // #define ADC_VREF_TYPE 0x00

35:

36: // Програма обслуговування переривання АЦП

37: interrupt [ADC_INT] void adc_isr(void)

38: {

39: // Світлодіоди відображають 8 найбільш

40: // значущих бітів АЦП

41: PORTB=(unsigned char) ~(ADCW>>2);

42: // затримка 20 мс

43: delay_ms(20);

44: // Початок нового АЦ перетворення

45: ADCSR1=0x40;

46: }

47:

48: void main(void)

49: {

50: // Ініціалізація Порту В

51: PORTB=0xFF; // всі виходи

52: DDRB=0xFF; // всі світлодіоди спочатку вимкнені

53:

54: // Ініціалізація АЦП

55: // Тактова частота АЦП: 57.656 кГц

56: // Переривання АЦП: Вкл

57: ADCSR=0x8E;

58:

59: // Глобальний дозвіл переривань

60: #asm("sei")

61:

62: // Виберемо вхід 0 АЦП

63: ADMUX=0;

64:

65: // Запустимо перше АЦ перетворення

66: ADCSR1=0x40;

67:

68: // Вся робота робиться за допомогою АЦП переривань

69: while (1);

70: }

У цьому файлі знаками /* (початок) і */ (кінець) виділений блок з коментарями, а знаком // — рядки з коментарями.

У блоці з коментарями (рядки 1...27) даються рекомендації з настройки плати STK500 при апаратній реалізації даного проекту.

Директивами #include (рядки 30 і 32) підключаються: заголовний файл для використовуваного мікроконтролеру AVR (AT90S8535) — файл 90s8535.h, і функції затримки — файл delay.h. Перед компіляцією препроцесор компілятора вставить замість цих рядків текст відповідних файлів.

Директивою #define (рядок 34) визначається ідентифікатор ADC_VREF_TYPE. Перед компіляцією препроцесор замінить в тексті програми цей ідентифікатор на його значення — 0x00.

Рядки 37...46 — це визначення програми (функції) обслуговування переривання від АЦП (ADC). Це переривання відбувається при закінченні кожного аналого-цифрового перетворення.

У рядку 37 здійснюється доступ до системи переривань мікроконтролера AVR, на що указує ключове слово interrupt. Далі за цим ключовим словом в квадратних дужках повинен йти номер вектора переривання. Але тут замість номера стоїть ідентифікатор ADC_INT. Річ у тому, що цей ідентифікатор визначений директивою #define в заголовному файлі 90s8535.h. Перед компіляцією препроцесор компілятора замінить ADC_INT на цифру 15 (номер вектора переривання), як визначено у файлі 90s8535.h. Замість ADC_INT в квадратних дужках можна було написати 15, але ADC_INT більш наглядно. Далі йде ключове слово void, яке вказує на те, що функція не повертає ніяких значень, потім ім'я функції adc_jsr (може бути довільним, але краще із смисловим навантаженням). По цьому імені далі в програмі здійснюється виклик даної функції. Ключове слово void в дужках указує на те, що в цю функцію не передаються ніякі параметри.

У рядку 38 відкриваюча фігурна дужка вказує на початок тіла програми обслуговування переривання.

У тілі програми обслуговування переривання від АЦП в рядку 41 в регістр PORTx Порту В записується значення виразу, що стоїть праворуч від знаку «=». Розглянемо цей вираз докладніше. ADCW — це змінна, яка визначена у файлі 90s8535.h. Вона має розмір 16 біт (2 байти), і для доступу до неї у файлі 90s8535.h використовується ключове слово sfrw. У змінній ADCW CodeVisionAVR зберігає 10-бітовий результат аналого-цифрового перетворення АЦП (у бітах 0...9). У 0-у біті зберігається наймолодший біт результату перетворення, а в 9-у — найстарший.

Оскільки Порт В, до якого підключені світлодіоди, має всього 8 бітів, то в даному проекті світлодіодами відображатимуться тільки 8 найзначущіших (найстарших) бітів результату аналого-цифрового перетворення АЦП. Для цього значення змінної ADCW зсовується на два біти управо (знак операції — >>2. При цьому значення 1-го і 0-го бітів пропадають. Тепер 8 найзначущіших бітів результату аналого-цифрового перетворення знаходяться в молодшому байті (биті 0...7) змінної ADCW.

Оскільки світлодіоди, підключені до вивідів Порту В, засвітяться тільки тоді, коли на відповідному виводу буде логічний «0», то необхідно замінити в змінній ADCW все 1 на 0, а 0 — на 1. Це здійснюється за допомогою операції побітного інвертування (знак операції — ~).

Оскільки PORTB — це байт (8 біт), а ADCW — це слово (2 байти = 16 біт), то, перш ніж виконати операцію привласнення (знак операції — =), потрібно перетворити тип ADCW в беззнаковий байт (unsigned char). При такому перетворенні типів даних у змінної ADCW залишиться тільки молодший байт (старший буде відкинутий).

Одержаний результат поміщається (привласнюється операцією «=») в регістр PORTx Порту В. Еслі при цьому в регістрі DDRx Порту В всі біти встановлені в 1, тобто всі виводи Порту В є виходами, то світлодіоди, підключені до виводів Порту В, відобразять старші 8 бітів результату перетворення АЦП, причому включений світлодіод позначатиме 1 у відповідному біті, а вимкнений — 0.

Далі, в рядку 43, за допомогою функції delay_ms здійснюється затримка в 20 мс, щоб в реальному пристрої можна було побачити перемикання світлодіодів.

У рядку 45 здійснюється запуск нового аналого-цифрового перетворення АЦП. Для цього в регістрі ADCSR (ADC Control and Status Register — Регістр управління і стану АЦП) мікроконтролеру необхідно встановити в одиницю біт 6 — ADSC (ADC Start Conversion — Старт перетворення АЦП). Цей біт має значення 1 під час всього циклу перетворення і скидається в 0 після його закінчення. Докладніше дивитеся опис (datasheet) від Atmel на мікроконтролер AT90S8535. Для установки біта ADSC в 1 використовується операція побітового АБО з привласненням (знак операції — |=) з числом 0x40 = 0b 0100 0000. В результаті цієї операції в 6-й біт в регістрі ADCSR (битий ADSC) буде записана 1, незалежно від того, яке значення там було до цього. Значення решти бітів регістра ADCSR не зміняться.

У рядку 46 закриваюча фігурна дужка указує кінець тіла програми обслуговування переривання.

Рядки 48...70 — це визначення основної функції програми (main). Ця функція обов'язково повинна бути присутнім у всіх програмах (але тільки ОДНА!). Саме з цієї функції, в якому б місці програми вона ні знаходилася, починається виконання програми.

У рядку 48 здійснюється оголошення функції main. На початку рядка стоїть ключове слово void, яке вказує на те, що ця функція не повертає ніяких значень, потім слідує ім'я функції main (ЙОГО ЗМІНЮВАТИ НЕ МОЖНА!) і ключове слово void в дужках, яке указує на те, що в цю функцію не передаються ніякі параметри.

У рядку 49 відкриваюча фігурна дужка указує на початок тіла функції main.

У рядках 51 і 52 в регістри DDRx і PORTx Порту В у всі біти записується 1 (0xff = 0b 1111 1111), тим самим всі виводи цього порту робляться виходами, і на всіх виводах встановлюється значення логічної 1. Таким чином, всі світлодіоди, підключені до виводів Порту В, вимикаються.

У рядку 57 здійснюється ініціалізація АЦП. При цьому в регістр ADCSR (ADC Control and Status Register — Регістр управління і стану АЦП) записується значення 0х8Е = 0b 1000 1110. Значення 1 в 7-у біті дозволяє АЦП; 0 в 6-у біті забороняє аналого-цифрове перетворення; 0 в 5-у біті забороняє режим безперервного перетворення; 0 в 4-у біті — прапор переривання від АЦП скинутий; 1 в 3-у біті дозволяє переривання від АЦП (якщо встановлений глобальний дозвіл переривань). Код 110 в трьох молодших бітах (0...2) задає коефіцієнт поділу тактової частоти АЦП, рівний 64, тобто АЦП тактуватиметься частотою:

3690 / 64 = 57.65625 кГц → 57.656 кГц.

Докладніше див. опис (datasheet) від Atmel на мікроконтролер AT90S8535.

У рядку 60 здійснюється глобальний дозвіл переривань. Для цього в програму включений асемблерний код. Інструкція асемблера sei встановлює прапор глобального переривання 1 в регістрі статусу SREG мікроконтролеру, тим самим дозволяються глобальні переривання.

У рядку 63 вибирається один з 8 каналів АЦП. Для цього в регістр ADMUX (ADC Multiplexer Select Register — регістр вибору мультиплексору АЦП) записується відповідний двійковий код номера каналу: для 7-го — 111, для 6-го — 110,..., для 0-го — 000. У даному проекті вибраний 0-й канал (у регістр ADMUX записується код 000).

У рядку 66 здійснюється запуск першого перетворення АЦП, як було розглянуто при описі рядки 45 програми, тобто біт 6 (ADSC) регістру ADCSR мікроконтролера встановлюється в 1.

У рядку 69 реалізований нескінченний цикл за допомогою оператора while. Цей оператор виконуватиметься до тих пір, поки вираз в дужках істинний, тобто не 0. Вираз в дужках — 1 (можна також написати 5 або 89), а не 0, тобто завжди істинно. Отже, цей оператор виконуватиметься нескінченно, поки не відбудеться переривання програми.

У рядку 70 закриваюча фігурна дужка указує кінець тіла функції main.

Програма працює таким чином. Після подачі живлення (або апаратного скидання на вивіду RESET мікроконтролера) починає виконуватися функція main. При цьому відбувається конфігурація периферійних пристроїв (Порту В і АЦП) і настройка системи переривань мікроконтролера. Запускається перше перетворення АЦП. Після цього програма переходить до виконання нескінченного циклу while і виконує його, поки не відбудеться переривання після закінчення перетворення АЦП.

Після цього програма переходить до виконання функції обробки переривання adc_isr. На висновках Порту В встановлюються інвертовані значення старших 8 бітів результату перетворення АЦП. При цьому спалахують відповідні світлодіоди. Робиться пауза в 20 мс, і знову запускається перетворення АЦП. Після цього програма повертається в нескінченний цикл while і виконує його, поки знову не відбудеться переривання після закінчення перетворення АЦП, і т.д.

Результати виконання цієї програми представлені на рис. 4.1, рис. 4.2. Ланцюг скидання, живлення і кварцовий резонатор мікроконтролера не показані (див. рис. 1.1).

При вхідній напрузі АЦП 5 В результат перетворення буде Ob 1111 111111, оскільки опорна напруга також рівно 5 В. Один молодший біт результату перетворення відповідає напрузі:

5 В / 1024 = 0.0048828125 В → 0.00488 В.

Таким чином, при вхідній напрузі 3.5 В результат перетворення буде:

3.5 В / 0.00488 В ≈ 717 = 0b 0010 1100 1101,

тобто 8 старших бітів — 0b 1011 0011, і горітимуть світлодіоди VD8 (найстарший біт), VD6, VD5, VD2 і VD1 (рис.4.1).

Рисунок 4.1. - Результат роботи програми при вхідній напрузі 3.5 В.

При вхідній напрузі 1.5 В результат перетворення буде: 1.5 В/0,00488 В≈307 = 0b 0001 0011 1100, тобто 8 старших бітів — 0b 0100 1100, і горітимуть світлодіоди VD7, VD4 і VD3 (Рис. 4.2).

За відсутності налагоджувальної платі STK500 можна самостійно реалізувати цей проект по приведеній схемі.

Рисунок 4.2. - Результат роботи програми при вхідній напрузі 1.5 В.

Література

  1. Фрунзе А.В. Микроконтроллеры? Это же просто! Т.1.- Москва.: ООО «ИД СКИМЕН», 2002.- 336 с., ил.

  2. Файнштейн В.Г., Файнштейн Е.Г. Микропроцессорные системы управления электроприводами.-М.: Энергоатомиздат, 1986

  3. Микропроцессоры Т.2 - Средства сопряжения. Контролирующие и информационно - управляющие системы. Под ред. Преснухина Л. Н. - М.: Высшая школа, 1986 - 384с.

  4. Микро-ЭВМ (Учебные стенды). Под ред. Преснухина Л.Н. - М.: Высшая школа, 1988 - 224с.

  5. Балашов Е. П., Пузанков Д.В. Микропроцессоры и микропроцессорные системы. - М.: Радио и связь, 1981 - 328с.

Методичні вказівки до виконання лабораторних робіт з дисципліни «Мікропроцесорні пристрої», 6.092200 “Електротехнічні системи та комплекси транспортних засобів”, 6.092200 “Електромеханічні системи автоматизації та електропривод”

Укладач: доц., канд. техн. наук Алексеєв І.А.

асист., магістр, Крупнік О.О.

Відповідальний за випуск: зав. кафедрою ЕМ, докт. техн. наук,

професор Садовой О. В.

Рецензент: канд. техн. наук, доцент Количев С.В.

Підписано до друку ____________2010 р.

Формат Обсяг др. аркуш.

Тираж екз. Замовлення

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]