1 Востаннє редагувалося Ярослав (25.12.2014 09:12:45)

Тема: Робота із 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

Вивід програми:
http://i.imgur.com/zUz6VQ8.png

Пояснення:
Для того, щоб вивести який-небудь текст на 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-код символу, а вона повертає цей символ.

Дякую Вам за увагу!

Подякували: Chemist-i, 0xDADA11C7, leofun013