NFLic

STM8 с нуля.

UART

UART (Universal Asynchronous Receiver-Transmitter) - основное средство для общения с нашим загрузчиком/терминалом.

Здесь рассмотрим только настройки 9600/8N1. Сигнал передается по двум проводам, третий общий. С обоих сторон выводы TXD, RXD, GND. Формат передачи данных по обеим линиям одинаков. Сигнал распространяется последовательно от выхода TXD до входа RXD. Дежурное состояние линии "1". Все интервалы одинаковы и для нашей скорости 9600 равны 1000000/9600 = 104 мксек.

;                       Start                                                 Stop 
; TXD   "1"  ----------       ----- ----- ----- ----- ----- ----- ----- ----- ----- -------   RXD
;                      |     |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |     
; GND   "0"             ----- ----- ----- ----- ----- ----- ----- ----- -----                 GND 
;         time - >

Первым идет сигнал Start - уровень "0" длительностью интервал. От начала сигнала Start идет отсчет временных интервалов.

Далее следуют начиная с младшего все биты длительностью интервал каждый передаваемого байта.

Последним следует сигнал Stop - уровень "1" длительностью не менее интервал.

После сигнала Stop сразу может последовать сигнал Start либо неопределенное время дежурное состояние линии "1".

 

Схема подключения для STM8S103F3P6:

;                 5V        _ _ _ _ _ _ _ _ _ _ _ _  _ _ _ _ _ _ _ _ _ _ _ _
;USB-UART 5V  ->>-'      __|                       \/                       |__ 
;USB-UART VCC ->>-,     |__| PD4 (HS) TIM2_CH1            TIM2_CH2 (HS) PD3 |__|----------------,   /|
;USB-UART 3V3 ->>-'      1 |    UART1_CK  BEEP            AIN4   ADC_ETR    |20                 |  / | 
;USB-UART TXD ->>----,   __|                                                |__               ,---/  | 
;USB-UART RXD ->>----|--|__| PD5 (HS) AIN5                AIN3     (HS) PD2 |__|              |   |  | 
;USB-UART GND ->>-.  |   2 |    UART1_TX                  [TIM2_CH3]        |19               HCM1212A 
;                GND |   __|                                                |__               |   |  | 
;                    '--|__| PD6 (HS) AIN6                SWIM     (HS) PD1 |__|--- SWIM      |   |  | 
;                        3 |    UART1_RX 

Уровень сигнала с обоих сторон должен быть одинаков (в нашем случае 3,3В).

 

Рассмотрим настройку UART без использования прерываний. В STM8 несколько UART. Выбираем UART1.

Принятые настройки 8N1 (8 бит данных, нет контроля четности, 1 стоповый бит) приняты по умолчанию в STM8.

Первым делом необходимо включить тактирование UART1 (для STM8L) установкой в "1" бита PCKEN13(#3) в регистре CLK_PCKENR1. В STM8S103F3 при сбросе периферия уже тактируется.

    bset   CLK_PCKENR1, #3   ; для STM8L

 

Следом надо настроить скорость UART. При сбросе STM8 стартует от внутреннего генератора частотой 16 МГц с подключенным делителем 1/8. Итого на вход UART1 приходит частота 2 МГц. Необходимо посчитать величину UART_DIV и загрузить ее в регистры UART1_BRR1 и UART1_BRR2. В документации дается формула:

    Tx/Rx baud rate = Fmaster / UART_DIV

По которой UART_DIV = 2000000 / 9600 = 208 = $D0. Вот это число и надо загрузить сначало в регистр UART2_BRR2 потом в регистр UART1_BRR1 и не наоборот. Разряды значения UART_DIV по регистрам UART2_BRR2 и UART2_BRR1 распределяются следующим образом:

;       7     6     5     4     3     2     1     0
;     ----- ----- ----- ----- ----- ----- ----- -----
;    |  15 |  14 |  13 |  12 |  3  |  2  |  1  |  0  |  UART2_BRR2
;     ----- ----- ----- ----- ----- ----- ----- -----
;    |  11 |  10 |  9  |  8  |  7  |  6  |  5  |  4  |  UART2_BRR1
;     ----- ----- ----- ----- ----- ----- ----- -----

Получается $0 надо записать в регистр UART2_BRR2, а $D надо записать в регистр UART2_BRR1:

    mov    UART1_BRR2, #$0           ; [35 00 52 33]  для Fmaster=16/8=2МГц и 96000
    mov    UART1_BRR1, #$D           ; [35 0D 52 32]  для Fmaster=16/8=2МГц и 96000

Ввиду того, что регистры UART2_BRR2 и UART2_BRR1 при сбросе инициализируются величиной $00, первую команду можно было бы опустить.

 

Теперь необходимо разрешить прием и передачу установкой в "1" соответственно битов REN (#2) и TEN (#3) в регистре UART1_CR2:

   mov    UART1_CR2, #%00001100     ; [35 0C 52 35]    UART1_CR2.TEN <- 1  UART1_CR2.REN <- 1  разрешаем передачу/прием

 

Для того, чтобы отправить байт по UART необходимо поместить требуемый байт в регистр UART1_DR и опрашивая бит TXE (#7) регистра UART1_SR убедиться, что освободился регистр с данными для передачи:

    mov    UART1_DR, #$FA
wait_tx_byte:
	btjf   UART1_SR, #7, wait_tx_byte  ; skip if UART1_SR.TXE = 0 Transmit data register empty

 

Для того, чтобы принять байт по UART необходимо опрашивая бит RXNE (#5) регистра UART1_SR убедиться, что регистр с данными для приема не пустой и прочитать содержимое регистра UART1_DR:

wait_rx_byte:
    btjf   UART1_SR, #5, wait_rx_byte	; skip if UART1_SR.RXNE = 0 Read data register not empty
	ld     A, UART1_DR

 

Набросаем программу которая будет принимать байт по UART, инвертировать и отправлять по UART:

 

stm8/ TITLE “mainRAM_echo.asm”

    #include "STM8S103F3P.inc"
    MOTOROLA
    WORDS           ; define following addresses as long
	
    segment byte at 0100 'some_RAM_segment'
start:
; настраиваем UART 9600/8N1
    mov    UART1_BRR2, #$0           ; [35 00 52 33]  для Fmaster=16/8=2МГц и 96000
    mov    UART1_BRR1, #$D           ; [35 0D 52 32]  для Fmaster=16/8=2МГц и 96000
; разрешаем передачу/прием
    mov    UART1_CR2, #%00001100     ; [35 0C 52 35]    UART1_CR2.TEN <- 1  UART1_CR2.REN <- 1
	
cycle:

; ожидаем получения байта из UART
wait_rx_byte:
    btjf   UART1_SR, #5, wait_rx_byte	; [72 0B 52 30 FB]
; включаем светодиод
    bset    PB_DDR,#5   ; [72 1A 50 07]
    bset    PB_CR1,#5   ; [72 1A 50 08]
	
; принимаем, инвертируем и отправляем байт по UART
    cpl    UART1_DR                    ; [72 53 52 31]
; ожидаем передачи байта по UART
wait_tx_byte:
    btjf   UART1_SR, #7, wait_tx_byte  ; [72 0F 52 30 FB]
; выключаем светодиод
    bres   PB_DDR,#5   ; [72 1B 50 07]
    bres   PB_CR1,#5   ; [72 1B 50 08]
	
    jra    cycle       ; [20 E0] 

    end
; mainRAM_echo.asm

 

Команда "mov longmem, #byte" помещает byte в ячейку памяти с адресом longmem.

Команда "btjf longmem, #bit, ssoff" проверяет разряд с номером #bit в ячейке памяти с адресом longmem и если разряд равен "0"(false) осуществляет переход со смещением ssoff (-128...+127).

Команда "cpl longmem" инвертирует содержимое ячейки памяти с адресом longmem.

Команда "bset longmem, #bit" устанавливает в "1" разряд с номером #bit содержимого ячейки памяти с адресом longmem.

Команда "bres longmem, #bit" сбрасывает в "0" разряд с номером #bit содержимого ячейки памяти с адресом longmem.

 

Выгружаем файл [mainRAM_echo] запускаем файл [run_STM8uLoader.bat], нажимаем кнопку сброса на плате STM8, нажимая последовательно две клавиши из набора 0..9, A..F отправляем байт прикладной программе, на что программа отвечает инверсным значение байта:

 

 

Следующая программа будет принимать старший байт начального адреса, отправлять этот байт обратно, потом принимать младший байт начального адреса и отправлять содержимое блока памяти (64 байт) начиная с адреса принятого двумя предыдущмим байтами.

 

stm8/ TITLE “mainRAM_ReadBlock.asm”
	.NOLIST
    #include "STM8S103F3P.inc"
	.LIST
	
    MOTOROLA
    WORDS            ; define following addresses as long
    segment byte at 0100 'some_RAM_segment'
start:
; настраиваем UART 9600/8N1
    mov    UART1_BRR2, #$0           ; [35 00 52 33]  для Fmaster=16/8=2МГц и 96000
    mov    UART1_BRR1, #$D           ; [35 0D 52 32]  для Fmaster=16/8=2МГц и 96000
; разрешаем передачу/прием
    mov    UART1_CR2, #%00001100     ; [35 0C 52 35]    UART1_CR2.TEN <- 1  UART1_CR2.REN <- 1
	
cycle:

; ожидаем получения старшего байта начального адреса блока
wait_rx_byte_XH:
    btjf   UART1_SR, #5, wait_rx_byte_XH	; [72 0B 52 30 FB]
	ld     A, UART1_DR  ; [C6 52 31]
	ld     XH, A        ; [95]
; отправляем эхо старшего байта начального адреса блока
	ld     UART1_DR, A  ; [C7 52 31]
wait_tx_byte_XH:
	btjf   UART1_SR, #7, wait_tx_byte_XH  ; [72 0F 52 30 FB]
; ожидаем получения младшего байта начального адреса блока
wait_rx_byte_XL:
    btjf   UART1_SR, #5, wait_rx_byte_XL	; [72 0B 52 30 FB]
	ld     A, UART1_DR  ; [C6 52 31]
	ld     XL, A        ; [97]
; в индексный регистр Y количество байт в блоке
    ldw    Y, #64       ; [90 AE 00 40]
; включаем светодиод
    bset    PB_DDR,#5   ; [72 1A 50 07]
    bset    PB_CR1,#5   ; [72 1A 50 08]
read_block;
	ld    A, (X)
	ld    UART1_DR, A
wait_tx_block:
	btjf   UART1_SR, #7, wait_tx_block  ; [72 0F 52 30 FB]
	incw   X            ; [5C]
	decw   Y            ; [90 5A]
	jrne   read_block   ; [26 F2]
; выключаем светодиод
    bres    PB_DDR,#5   ; [72 1B 50 07]
    bres    PB_CR1,#5   ; [72 1B 50 08]
	
    jra     cycle       ; [20 E0] 

    end
; mainRAM_ReadBlock.asm

 

Выгружаем файл [mainRAM_ReadBlock] запускаем файл [run_STM8uLoader.bat], нажимаем кнопку сброса на плате STM8, нажимая последовательно четыре клавиши из набора 0..9, A..F отправляем начальный адрес требуемого блока (64 байт) памяти, на что прикладная программа читает содержимое блока с начальным адресом и отправляет в UART:

 

 

Машинные коды STM8 и команды ассемблера здесь. Адресное пространство STM8S103F3 тут.

 

[Адресное простанство и регистры STM8 (Статья 2)][Оглавление.] [Принятые сокращения (Статья 4)]