1   2   3   4
Ім'я файлу: РобототехникаЛабораторныеБаза_4_5_6.pdf
Розширення: pdf
Розмір: 3063кб.
Дата: 21.10.2022
скачати

UBRRn.
Цей регістр визначає швидкість роботи за протоколом UART. У технічній документації наводяться такі формули у разі асинхронної роботи інтерфейсу:
1 16



BAUD
f
UBRRn
OSC
, (L6_1)
1 8



BAUD
f
UBRRn
OSC
, (L6_2) де
UBRRn
– значення однойменного регістру,
OSC
f
– робоча частота мікроконтролера,
BAUD
– швидкість роботи UART.
Формула (L6_1) справедлива, якщо біт U2Xn = 0, а формула (L6_2) - якщо біт
U2Xn = 1. Біт U2Xn це перший біт регістру UCSRnA (див. рис.L6_3).
Однак найпростіше скористатися таблицею, яка також наведена у технічній документації.
Таблица L6_5. Зв'язок між значенням регістру UBRRn та швидкістю роботи.
З цієї таблиці видно, що при частоті мікроконтролера 16 МГц і бажаної швидкості роботи 9600 бод значення регістра UBRRn дорівнює 103 в стандартному режимі, та 207 – при подвоєному.


41
Зазначимо ще один важливий момент. Структуру регістру UBRRn наведено рисунку L6_6. З якого видно, що він складається з двох восьми-бітових регістрів
UBRRnH та UBRRnL. Причому використовуються лише молодші чотири біти старшого регістру UBRRnH. Таким чином, при записі значення UBRRn ми повинні записати спочатку старші біти в регістр UBRRnH, а потім молодші в
UBRRnL.
UART протокол.
Потік даних які передаються протоколом UART є набір кадрів. Кожен кадр містить:
- стартовий біт;
- від п'яти до дев'яти біт даних;
- стоповий біт.
Перед стоповим бітом може бути біт парності: парний або непарний.
Розглянемо структуру кадру (див. рис.
L6_
6) із офіційної документації на мікроконтролер.
Рис.
L6_
6. Структура кадру UART.
Поки немає передачі (IDLE – холостий хід) лінія перебуває у високому стані тобто. на лінії є логічна одиниця. Як тільки передавальний пристрій збирається надсилати інформацію, він притягує лінію до землі (логічного нуля). Це називається передача старт-біта (St). Потім іде передача інформаційних біт.
Якщо передаємо одиницю, то лінію притягуємо до + живлення, якщо нуль, то - землі. Інформаційних біт може бути від 5 до 9. Після передачі інформаційних біт може йти біт парності. Завершує передачу стоп-біт, який завжди має високий рівень, а його тривалість може дорівнювати 1, 1,5 або 2 тривалостей передачі одного біта.
Тривалість передачі біта пов'язана зі швидкістю UART протоколу. Зазвичай це
9600 бод, яка означає, що час передачі біта буде дорівнювати
мкс
сек 104 10 04
,
1 9600 1
4




При описі протоколу UART зазвичай використовують короткий запис
ЦИФРА-БУКВА-ЦИФРА.
Де ЦИФРА означає кількість інформаційних бітів (від 5 до 9) які передаються у кадрі.
Буква - біт парності, його наявність та тип:
- N - None (відсутній) без біта парності.

42
- E - Even (парний). Перевірка даних на парність. Перед стоп-бітом до кадру додається біт: 0 якщо у кадрі була непарна кількість одиниць, 1 — якщо парна.
- O - Odd (непарний). Перевірка даних на непарність. Перед стоп-бітом до кадру додається біт: 1 якщо у кадрі була непарна кількість одиниць, 0 — якщо парна.
ЦИФРА - тривалість стоп-біту 1, 1.5, 2.
Serial Monitor у Arduino IDE працює з наступними стандартними налаштуваннями: 8-N-1. Що означає: вісім інформаційних бітів, відсутній біт парності та один стоп-біт.
Для вивчення інтерфейсу UART за допомогою Proteus необхідно зібрати схему, зображену на рис.
L6_
7 якщо ми працюємо з
ATmega328.
Рис.
L6_
7 ATmega328 або схему (рис. L6_8), якщо використовується ATmega2560.
Рис.
L6_
8 ATmega2560
Зверніть увагу, що підключення пристрою з UART перехресне, тобто пін RX з'єднується з TX, а TX з RX. Оскільки ми хочемо, щоб лабораторні роботи можна було виконувати або в симуляторі, або на реальному устаткуванні, то для

43 сумісності будемо використовувати лише UART0 на ATmega2560, так само як і платформа Arduino MEGA яка з'єднана з Serial Monitor за допомогою UART0.
Також необхідно переконатися, що Virtual Monitor налаштований аналогічно
Serial Monitor в Arduino IDE, тобто. 8-N-1. Для цього двічі клацаємо лівою кнопкою миші по Virtual Monitor і налаштовуємо обладнання, як зазначено на рис.
L6_
9
Рис.
L6_
9. Налаштування Virtual Monitor у Proteus.
Наведемо програму prog1_6_1, яка виведе в монітор порту фразу HELLO
WORLD.
prog1_6_1
1 2
3 4
5 6
7 8
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
#define
F_CPU 16000000UL
//16MHz
#include
<
avr
/
io h
>
#include
<
util
/
delay h
>
//функция инициализации UART
void
UART_init(){
//настройка скорости передачи
UBRR0H
=
0;
UBRR0L
=
103;
// (16000000/(9600*16))–1=103 Table L6_5
//Настройка
//UCSR0A U2Xn=0 одинарная скорость передачи
//UCSR0B
//RXCIE0=TXCIE0=UDRIE0=0 не используем прерывания
//RXEN0=0 не используем прием данных
UCSR0B
|=
(1
<<
TXEN0);
//разрешить передачу
//UCSZ02=0 задает количество передаваемых бит
//UCSR0C
//UMSEL01=UMSEL00=0 асинхронный режим
//UPM01=UPM00=0 контроль четности отсутствует
//USBS0=0 стоповый бит один
//UCSZ01=UCSZ00=1 с учетом UCSZ02 передаем 8 бит
}
//Функция для передачи одного символа void
UART_transmit_char( uint8_t c ){
//ждем пока буфер передачи не освободится while
(
!
(UCSR0A
&
(1
<<
UDRE0)) );
UDR0
=
c;
}
//Функция для передачи строки void
UART_transmit_str(
char
*
str){ uint8_t c;

44 37 38 39 40 41 42 43 44 45 46 47
while
((c
=*
str
++
)
!=
0){
//передаем символы последовательно
UART_transmit_char(c);
}
} int main(){
UART_init();
//инициализируем UART while
(1){
UART_transmit_str(
"Hello World\r\n"
);
_delay_ms(300);
}
}
Завантаживши програму і ввімкнувши Serial Monitor (не забудьте налаштувати швидкість його роботи 9600 бод), після цього побачимо фразу
Hello World
Програма для виведення числа за інтерфейсом UART
prog1_6_2
1 2
3 4
5 6
7 8
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#define
F_CPU 16000000UL
//16MHz
#include
<
avr
/
io h
>
//функция инициализации UART
void
UART_init(){
//настройка скорости передачи
UBRR0H
=
0;
UBRR0L
=
103;
// (16000000/(9600*16))–1=103 Table L6_5
//Настройка
//UCSR0A U2Xn=0 одинарная скорость передачи
//UCSR0B
//RXCIE0=TXCIE0=UDRIE0=0 не используем прерывания
//RXEN0=0 не используем прием данных
UCSR0B
|=
(1
<<
TXEN0);
//разрешить передачу
//UCSZ02=0 задает количество передаваемых бит
//UCSR0C
//UMSEL01=UMSEL00=0 асинхронный режим
//UPM01=UPM00=0 контроль четности отсутствует
//USBS0=0 стоповый бит один
//UCSZ01=UCSZ00=1 с учетом UCSZ02 передаем 8 бит
}
//Функция для передачи одной цифры d void
UART_transmit_digit( uint8_t d ){
//ждем пока буфер передачи не освободится while
(
!
(UCSR0A
&
(1
<<
UDRE0)) );
UDR0
=
d
+
0x30;
//формируем код ASCII заданной цифры
}
//Функция для передачи целого беззнакового числа D
void
UART_transmit_uint( uint32_t
D ){ uint8_t
M[9]
,
i
=
0;
//Массив будет хранить число-в каждой ячейке цифра do
{
M[i]
=
D
%
10;
//записываем самую младшую цифру
D
/=
10;
//отбрасываем от числа млашую цифру i
++
;
//увеличиваем счетчик цифр в числе на 1
} while
(D
>
0);
//если D=0 все цифры числа перебрали for
(;i
>
0;i
--
){
//начинаем цикл с i равному количеству цифр
UART_transmit_digit(M[i
-
1]);
//передаем цифры со старшей
}

45 43 44 45 46 47 48
} int main(){
UART_init();
//инициализируем UART
UART_transmit_uint(12345);
//передаем целое положительное число while
(1){}
}
Напишемо тепер програму, яка керуватиме світлодіодом на піні D13
(ATmega328) за допомогою UART. Коли посилаємо 1, стан світлодіода буде змінюватися на протилежний.
prog1_6_3
1 2
3 4
5 6
7 8
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
#define
F_CPU 16000000UL
//16MHz
#include
<
avr
/
io h
>
//функция инициализации UART
void
UART_init(){
//настройка скорости передачи
UBRR0H
=
0;
UBRR0L
=
103;
//(16000000/(9600*16))–1=103 для 16 МГц и скорости 9600
//Настройка
//UCSR0A U2Xn=0 одинарная скорость передачи
//UCSR0B
//RXCIE0=TXCIE0=UDRIE0=0 не используем прерывания
//TXEN0=0 не используем передачу данных
UCSR0B
|=
(1
<<
RXEN0);
//разрешить прием
//UCSZ02=0 задает количество передаваемых бит
//UCSR0C
//UMSEL01=UMSEL00=0 асинхронный режим
//UPM01=UPM00=0 контроль четности отсутствует
//USBS0=0 стоповый бит один
//UCSZ01=UCSZ00=1 с учетом UCSZ02 передаем 8 бит
}
//Функция для приема символа uint8_t
UART_receive(){
//ждем прием байта while
((UCSR0A
&
(1
<<
RXC0))
==
0);
//считываем принятый байт return
UDR0;
} uint8_t
ControlByte;
//переменная для управления светодиодом int main(){
DDRB
|=
(1
<<
DDB5);
PORTB
&=
(1
<<
PORTB5);
UART_init();
//инициализируем UART
while
(1){
ControlByte
=
UART_receive(); if
(ControlByte
==
'1'
){
PORTB
^=
(1
<<
PORTB5);
//инверсия состояния светодиода
}
} return
0;
}

46
Якщо ми працюємо з Virtual Monitor, то для того щоб можна було бачити символи, що посилаються через UART потрібно включити Echo Typed Characters
(див. рис.
L6_
10) для цього потрібно правою кнопкою миші клацнути в робочому полі Virtual Monitor і вибрати відповідний пункт. Після цього символи будуть відображатися у вікні.
Рис.
L6_
10. Налаштування Virtual Monitor для передачі даних UART.
Зауважимо, що на відміну від Serial Monitor (Arduino IDE) символи, що відображаються, в Virtual Monitor відразу посилаються по UART інтерфейсу, в
Serial Monitor потрібно натиснути ENTER.
Найбільший недолік програми prog1_6_3 полягає в тому, що в головному нескінченному циклі (рядки 39-43) мікроконтролер змушений чекати на прихід байта по UART і при цьому нічим іншим він займатися не може. Щоб уникнути цього, потрібно використовувати переривання.
Таблиця L6_6 – USART вектори прериваннь для ATmega328
Номер вектора
Адреса
Джерело
Опис переривання
19 0x0024
USART, RX
USART прием закінчений
20 0x0026
USART, UDRE
Регістр даних USART порожній
21 0x0028
USART, TX
USART передача закінчена
Таблица L6_7 – USART вектори переривань для ATmega2560
Vector
No.
Program
Address
Source
Interrupt Definition
26
$0032
USART0 RX
USART0 Rx Complete
27
$0034
USART0 UDRE
USART0 Data Register Empty
28
$0036
USART0 TX
USART0 Tx Complete
52
$0066
USART2 RX
USART2 Rx Complete
53
$0068
USART2 UDRE
USART2 Data Register Empty

47 54
$006A
USART2 TX
USART2 Tx Complete
55
$006C
USART3 RX
USART3 Rx Complete
56
$006E
USART3 UDRE
USART3 Data Register Empty
57
$0070
USART3 TX
USART3 Tx Complete
Напишемо наступну програму
prog1_6_4
1 2
3 4
5 6
7 8
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
#define
F_CPU 16000000UL
//16MHz
#include
<
avr
/
io h
>
#include
<
avr
/
interrupt h
>
// Бібліотека імен переривань
//функция инициализации UART
void
UART_init(){
//настройка скорости передачи
UBRR0H
=
0;
UBRR0L
=
103;
//(16000000/(9600*16))–1=103 для 16 МГц и скорости 9600
//Настройка
//UCSR0A U2X0=0 одинарная скорость передачи
//UCSR0B
//TXCIE0=UDRIE0=0 не используем прерывания
UCSR0B
|=
(1
<<
RXCIE0);
//разрешаем прерывания по завершению приема
//TXEN0=0 не используем передачу данных
UCSR0B
|=
(1
<<
RXEN0);
//разрешить прием
//UCSZ02=0 задает количество передаваемых бит
//UCSR0C
//UMSEL01=UMSEL00=0 асинхронный режим
//UPM01=UPM00=0 контроль четности отсутствует
//USBS0=0 стоповый бит один
//UCSZ01=UCSZ00=1 с учетом UCSZ02 передаем 8 бит стр 191
} int main(){
DDRB
|=
(1
<<
DDB5);
PORTB
&=
(1
<<
PORTB5);
UART_init();
//инициализируем UART
sei(); while
(1){} return
0;
}
ISR(USART_RX_vect){ uint8_t cb
=
UDR0;
//cb=control byte if
(cb
==
'1'
){
PORTB
^=
(1
<<
PORTB5);
} if
(cb
==
'H'
){
PORTB
|=
(1
<<
PORTB5);
} if
(cb
==
'L'
){
PORTB
&=
(1
<<
PORTB5);
}
}
У програмі prog1_6_4 основна частина (рядок 33) порожня, всі дії відбуваються у перериваннях. Коли вводиться 1, стан світлодіода на D13 інвертується, якщо вводимо H, то вмикаємо світлодіод, якщо L – вимикаємо.

48
Зазначимо, якщо цю програму треба переписати під ATmega2560, то потрібно пін PB5 замінити на PB7, а також вектор USART_RX_vect замінити на
USART0_RX_vect.
Зараз розробимо програму яка буде отримувати по інтерфейсу UART число типу
uint8_t
та передавати це число в порівняльний регістр каналу А таймер-лічильника №0, який налаштовано на генерацію ШІМ сигналу. Таким чином ми зможемо з клавіатури встановлювати потрібну яскравість світлодіоду, якщо він буде підключено до відповідного піну.
Проект розробимо на ATmega2560, тому ШІМ сигнал будемо генерувати на піні
PB7=OC0A=D13
. Після того, як усі цифри потрібного числа будуть введені, необхідно ввести q
– це вкаже програмі, що число введено і можна записувати
ШІМ параметр. На жаль, Proteus не може змінювати яскравість світлодіода при симуляції роботи програми, тому разом зі світлодіодом до вказаного піна ми підключимо осцилограф, який в реальному часі буде демонструвати згенерований ШИМ сигнал (див. рис.
L6_
11).
Рис.
L6_
11. Керування ШІМ сигналом за допомогою UART
prog1_6_5
1 2
3
#define
F_CPU 16000000UL
//16MHz
#include
<
avr
/
io h
>
#include
<
avr
/
interrupt h
>
// Бібліотека імен переривань

49 4
5 6
7 8
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
uint8_t bufRX[5]; volatile uint8_t count
=
0;
//функция инициализации UART
void
UART_init(){
//настройка скорости передачи
UBRR0H
=
0;
UBRR0L
=
103;
//(16000000/(9600*16))–1=103 для 16 МГц и скорости 9600
//Настройка
//UCSR0A U2X0=0 одинарная скорость передачи
//UCSR0B
//TXCIE0=UDRIE0=0 не используем прерывания
UCSR0B
|=
(1
<<
RXCIE0);
//разрешаем прерывания по завершению приема
//TXEN0=0 не используем передачу данных
UCSR0B
|=
(1
<<
RXEN0);
//разрешить прием
//UCSZ02=0 задает количество передаваемых бит
//UCSR0C
//UMSEL01=UMSEL00=0 асинхронный режим
//UPM01=UPM00=0 контроль четности отсутствует
//USBS0=0 стоповый бит один
//UCSZ01=UCSZ00=1 с учетом UCSZ02 передаем 8 бит стр 191
} int main(){
//налаштовуємо ШІМ on ATmega2560
DDRB
|=
(1
<<
DDB7);
//PB7=OC0A=D13 як ВИХІД
TCCR0A
|=
(1
<<
WGM00);
//режим PWM Phase Correct №1
TCCR0B
|=
(1
<<
CS02)
|
(1
<<
CS00);
//дільник 1024
TCCR0A
|=
(1
<<
COM0A1);
//неінвертований ШІМ
UART_init();
//инициализируем UART
sei(); while
(1){}
}
ISR(USART0_RX_vect){ uint8_t udr
=
UDR0; if
(udr != 'q'){
//в конце числа посылаем 'q'=0x71
bufRX [count++] = udr-0x30;
//переводим код ASCII в цифру
} else
{ switch
(count){ case
3
:
OCR0A
=
bufRX[0]
*
100
+
bufRX[1]
*
10
+
bufRX[2]; break
; case
2
:
OCR0A
=
bufRX[0]
*
10
+
bufRX[1]; break
; case
1
:
OCR0A
=
bufRX[0]; break
;
} count
=
0;
}
}
Після завантаження програми пишемо в Virtual Terminal 10q (Enter не натискаємо) і бачимо на осцилографі відповідний ШІМ сигнал (див. рис.
L6_
12).

50
Рис.
L6_
12. Задаємо ШИМ параметр 10 за допомогою UART.
Не зупиняючи симуляцію, вводимо 50q і бачимо відповідні зміни ШІМ сигналу
(див. рис.
L6_
13).
Рис.
L6_
13. Задаємо ШИМ параметр 50 за допомогою UART.
Аналогічно задавши ШІМ параметр 150 і 250 можна бачити зміни сигналу, які формуються на піні OC0A (див. рис.
L6_
14 і рис.
L6_
15).

51
Рис.
L6_
14. Задаємо ШИМ параметр 150 за допомогою UART.
Рис.
L6_
15. Задаємо ШИМ параметр 250 за допомогою UART.

52
Хід роботи
Завдання 6.1.
Написати програму ЛУНА не використовуя переривання. Тобто посилаємо один символ по UART та отримуємо у відповідь той самий символ. Згідно таблиці виберіть швидкість роботи UART інтерфейсу.
Таблиця L6_8.
Варіант BAUD
U2X0 1
2400 1
2 4800 1
3 19200 1
4 38400 1
5 57600 1
6 1000000 1
7 115200 1
8 250000 1
9 2400 0
10 4800 0
11 19200 0
12 38400 0
13 57600 0
14 1000000 0
15 2400 1
16 250000 0
17 500000 0
18 9600 1
19 115200 1
20 500000 1
Примітка: у вікні властивостей Virtual Terminal в полі Baud Rate можливо просто ввести необхідне значення швидкості.

53
Завдання 6.2.
Написати програму ЛУНА використовуя переривання. Тобто посилаємо один символ по UART та отримуємо у відповідь той самий символ. Згідно таблиці виберіть швидкість роботи UART інтерфейсу.
Таблиця L6_9.
Варіант BAUD
U2X0 1
4800 1
2 19200 1
3 38400 1
4 57600 1
5 1000000 1
6 115200 1
7 250000 1
8 2400 0
9 4800 0
10 19200 0
11 38400 0
12 57600 0
13 1000000 0
14 2400 1
15 250000 0
16 500000 0
17 9600 1
18 115200 1
19 500000 1
20 2400 1
Примітка: у вікні властивостей Virtual Terminal в полі Baud Rate можливо просто ввести необхідне значення швидкості.

54
Завдання 6.3.
Написати програму яка буде отримувати по UART ціле число x типу int16_t, тобто число зі знаком, та повертати у термінал результат розрахунку відповідной функції f(x) типу int32_t. Надати відповідни скріншоти в яких є вивід у терміналі позитивних і негативних чисел.
Таблиця L6_10.
Варіант
f(x)
BAUD
U2X0 1
x
2
-10x+5 4800 1
2 2x
2
-5x-3 19200 1
3 3x
2
-8x-23 38400 1
4 4x
2
-80x+3 57600 1
5 5x
2
-20x-70 1000000 1
6
-x
2
+2x+44 115200 1
7
-2x
2
+x+30 250000 1
8
-3x
2
+5x+25 2400 0
9
-4x
2
+3x+57 4800 0
10
-5x
2
+2x+28 19200 0
11
x
2
-10x+5 38400 0
12 2x
2
-5x-3 57600 0
13 3x
2
-8x-23 1000000 0
14 4x
2
-80x+3 2400 1
15 5x
2
-20x-70 250000 0
16
-x
2
+2x+44 500000 0
17
-2x
2
+x+30 9600 1
18
-3x
2
+5x+25 115200 1
19
-4x
2
+3x+57 500000 1
20
-5x
2
+2x+28 2400 1

1   2   3   4

скачати

© Усі права захищені
написати до нас