Тема: Робота із UART мікроконтролера 8051
Привіт, форумчани!
В своєму ВНЗ ми проходили UART. Тому я хотів би поділитись кодом, в якому наведений приклад роботи із ним.
Про UART можна прочитати в Вікіпедії.
Як із ним працювати прекрасно розписано в статті 8051 Tutorial: Serial Communication на сайті www.8052.com.
Для того, щоб працювати із UART, його треба налаштувати. За роботу цього пристрою відповідає регістр спеціального призначення (SFR) SCON. В цьому коді UART налаштований в 8-бітовий режим із прийманням вводу. Частота розраховується по формулі, наведеній в статті.
ADI - Apps написали функції, що спрощують роботу із UART. Ця програма представляє приклад застосування функцій ADI - Apps
;********************************************************************
;
; Автори : ADI - Apps www.analog.com/MicroConverter
; Дата : 12 Жовтня 1999
;
; Файл : UARTIO.hex
; Вимоги до апаратури : будь який мікроконтролер чи мікроконвертор сумісний з 8051
;
;Стандартна UART I/O підпрограма. Загальний розмір
; цього коду після трансляції 155 байт
;Включає такі процедури
; SENDSTRING – передача рядка символів
; SENDCHAR - передача одиночного символу
; SENDVAL - передача байту як 2 ASCII символи
; HEX2ASCII - перетворення з HEX у ASCII
; ASCII2HEX - перетворення з ASCII у HEX
; GETCHAR - прийом одиночного символу
; GETVAL - прийом байту як 2 ASCII символи
;
;********************************************************************
NL EQU 10
CR EQU 13
ENDL EQU 00
CSEG AT 0C000h
ORG 0C000h
JMP MAIN
STRING: DB 'This string is in CODE memory', NL, CR, ENDL
MAIN: MOV SCON, #50h ;8-bit UART, accept recieve
ORL TMOD, #20h ;8-bit TIMER with reloading
ORL PCON, #80h ;setting up SMOD bit to double baud rate
MOV TH1, #0F4h ;setting up TIMER frequency to 4800 bode
SETB TR1
MOV A, #'H'
CALL SENDCHAR
MOV A, #'e'
CALL SENDCHAR
MOV A, #'l'
CALL SENDCHAR
MOV A, #'l'
CALL SENDCHAR
MOV A, #'o'
CALL SENDCHAR
MOV A, #'!'
CALL SENDCHAR
MOV A, #NL
CALL SENDCHAR
MOV A, #CR
CALL SENDCHAR
MOV DPTR, #STRING
CALL SENDSTRING
MOV A, #'A'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
MOV A, #'-'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
MOV A, #'A'
CALL SENDVAL
MOV A, #NL
CALL SENDCHAR
MOV A, #CR
CALL SENDCHAR
MOV A, #'A'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
MOV A, #'-'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
MOV A, #'A'
CALL HEX2ASCII
CALL SENDVAL
MOV A, #NL
CALL SENDCHAR
MOV A, #CR
CALL SENDCHAR
MOV A, #'C'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
MOV A, #'X'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
MOV A, #'-'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
MOV A, #'C'
CALL ASCII2HEX
CALL SENDVAL
MOV A, #' '
CALL SENDCHAR
MOV A, #'X'
CALL ASCII2HEX
CALL SENDVAL
MOV A, #NL
CALL SENDCHAR
MOV A, #CR
CALL SENDCHAR
CALL GETCHAR
CALL SENDCHAR
PUSH ACC
MOV A, #' '
CALL SENDCHAR
MOV A, #'-'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
POP ACC
CALL SENDVAL
MOV A, #NL
CALL SENDCHAR
MOV A, #CR
CALL SENDCHAR
CALL GETVAL
PUSH ACC
MOV A, #' '
CALL SENDCHAR
MOV A, #'-'
CALL SENDCHAR
MOV A, #' '
CALL SENDCHAR
POP ACC
CALL SENDCHAR
MOV A, #NL
CALL SENDCHAR
MOV A, #CR
CALL SENDCHAR
JMP $
;____________________________________________________________________
; SENDSTRING
SENDSTRING: ; пересилання ASCII рядка до UART починаючи з значення
; DPTR та закінчуючи нульовим (0) значенням
PUSH ACC
PUSH B
CLR A
MOV B,A
IO0010: MOV A,B
INC B
MOVC A,@A+DPTR
JZ IO0020
CALL SENDCHAR
JMP IO0010
IO0020: POP B
POP ACC
RET
; SENDCHAR
SENDCHAR: ; пересилка ASCII значення з A до UART
JNB TI,$ ; чекати поки символ надійде
CLR TI ; обнулити ТI
MOV SBUF,A
RET
;____________________________________________________________________
; SENDVAL
SENDVAL: ; переводить шістнадцяткове значення в A у два ASCII символи,
; і надсилає їх до UART.
; не змінює значення A.
PUSH ACC
SWAP A
CALL HEX2ASCII
CALL SENDCHAR ; передача старшого півбайта
POP ACC
PUSH ACC
CALL HEX2ASCII
CALL SENDCHAR ; передача молодшого півбайта
POP ACC
RET
;____________________________________________________________________
; HEX2ASCII
HEX2ASCII: ; перетворює А в ASCII код
ANL A,#00Fh
CJNE A,#00Ah,$+3
JC IO0030
ADD A,#007h
IO0030: ADD A,#'0'
RET
;____________________________________________________________________
; ASCII2HEX
ASCII2HEX: ; перетворює вміст A із ASCII цифри ('0'-'9' чи 'A'-'F')
; у відповідне число (0-15). Повертає C=1
; коли введено відмінне від цифри ASCII ,
; при невірному вводі приймає значення 255.
CLR C
SUBB A,#'0'
CJNE A,#10,$+3
JC IO0050 ; якщо '0'<=char<='9', повертає OK
CJNE A,#17,$+3
JC IO0040 ; якщо '9'<char<'A', повертає FAIL
SUBB A,#7
CJNE A,#10h,$+3
JC IO0050 ; iякщо'A'<=char<='F', повертає OK
CJNE A,#42,$+3
JC IO0040 ; якщо 'F'<char<'a', повертає FAIL
SUBB A,#20h
CJNE A,#10h,$+3
JC IO0050 ; якщо 'a'<=char<='f', повертає OK..
IO0040: CLR C ; інакше повертає FAIL
MOV A,#0FFh
IO0050: CPL C
RET
;____________________________________________________________________
; GETCHAR
GETCHAR: ; чекає поки одиночний ASCII символ буде надіслано
; за допомогою UART. Записує цей символ до регістру A.
JNB RI,$
MOV A,SBUF
CLR RI
RET
;____________________________________________________________________
; GETVAL
GETVAL: ; чекає поки дві ASCII цифри буде прийнято за допомогою
; UART. повертає шістнадцяткове значення до A.
PUSH B
PUSH 0
IO0060: CLR RI
CALL GETCHAR ; перший півбайт
MOV 0,A ; запам’ятовуємо символ що надійшов
CALL ASCII2HEX
JC IO0060 ; якщо не від '0' до 'F', не приймається
SWAP A ; переставляє півбайти
MOV B,A ; запам’ятовує пів байт у регістрі В
MOV A,0 ;
CALL SENDCHAR
IO0070: CLR RI
CALL GETCHAR ; другий півбайт
MOV 0,A ; запам’ятовуємо символ що надійшов
CALL ASCII2HEX
JC IO0070 ; якщо не від '0' до 'F', не приймається
ORL A,B ; об’єднуємо півбайти
MOV B,A ; запам’ятовує результат у регістрі В
MOV A,0
CALL SENDCHAR
MOV A,B ; кінцевий результат
POP 0
POP B
RET
END
Вивід програми:
Пояснення:
Для того, щоб вивести який-небудь текст на UART, необхідно застосовувати таблицю символів ASCII.
Наприклад, щоб вивести рядок "Hello!", необхідно в буфер UART послідовно надсилати ASCII код кожного символу:
72 - 'H'
101 - 'e'
108 - 'l'
108 - 'l'
111 - 'o'
33 - '!'
Це робиться із допомогою цього шматку коду:
MOV A, #'H'
CALL SENDCHAR
MOV A, #'e'
CALL SENDCHAR
MOV A, #'l'
CALL SENDCHAR
MOV A, #'l'
CALL SENDCHAR
MOV A, #'o'
CALL SENDCHAR
MOV A, #'!'
CALL SENDCHAR
MOV A, #NL
CALL SENDCHAR
MOV A, #CR
CALL SENDCHAR
Та функції SENDCHAR:
SENDCHAR: ; пересилка ASCII значення з A до UART
JNB TI,$ ; чекати поки символ надійде
CLR TI ; обнулити ТI
MOV SBUF,A
RET
Також ми надіслали на вивід символи 10 та 13, що відповідають символу нового рядку та переведення каретки. Для зручності вони зазначені у вигляді констант на початку файлу:
NL EQU 10
CR EQU 13
ENDL EQU 00
Простіше заздалегідь записати рядок в пам’ять кодів, а потім скористатись функцією SENDSTRING:
STRING: DB 'This string is in CODE memory', NL, CR, ENDL
...
MOV DPTR, #STRING
CALL SENDSTRING
...
;____________________________________________________________________
; SENDSTRING
SENDSTRING: ; пересилання ASCII рядка до UART починаючи з значення
; DPTR та закінчуючи нульовим (0) значенням
PUSH ACC
PUSH B
CLR A
MOV B,A
IO0010: MOV A,B
INC B
MOVC A,@A+DPTR
JZ IO0020
CALL SENDCHAR
JMP IO0010
IO0020: POP B
POP ACC
RET
В коді також наведені приклади використання корисних функцій, які можуть знадобитись при роботі з UART.
На скріншоті рядок A - 41 виведений за допомогою функцій SENDCHAR та SENDVAL. За допомогою функції SENDVAL можна вивести реальне шістнадцяткове число без його перетворення на символ. Ця функція розбиває байт на два числа і надсилає на вивід ASCII-код символу, що відповідає кожному із цих чисел.
В наступному рядку A - 31, показаний приклад роботи функції HEX2ASCII. Функція аналізує другу цифру ASCII-коду символу та повертає ASCII-код для цієї цифри. ASCII-код літери A - це 41h, HEX2ASCII візьме 01h та поверне код 31h, що відповідає символу '1'.
В рядку C X - 0C FF показаний приклад роботи функції ASCII2HEX. Функція ASCII2HEX проаналізувала ASCII-код символу C (43h) і повернула відповідну шістнадцяткову цифру 0Ch. Оскільки символу X немає в шістнадцятковій системі, функція повернула FF, що свідчить про помилку.
Наступний рядок 4 - 34 показує роботу GETCHAR. Ця функція повертає 1 символ із вводу. В цьому випадку ми ввели 4. Спочатку ми вивели просто символ '4', а потім іще вивели ASCII-код цього символу.
Останній рядок 34 - 4 демонструє роботу функції GETVAL. Яка має зворотню дію. Ми вводимо ASCII-код символу, а вона повертає цей символ.
Дякую Вам за увагу!