Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Помогите с инициализацией UART
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
TwisteR
У меня возник вопрос по инициализации UART в AT90S8535.

Компилируется нормально, прошивается тоже. При включении мигает синий светодиод (т.е. нормально функционирует основной цикл программы - LOOP1). Но стоит только послать что то по юарту - МК "виснет" (т.е. вместо загорания зелёного светодиода мигающий синий останавливается в том состоянии, на которое пришллось прерывание).

Помогите, пожалуйста, определить, в чём проблема. Подозреваю, что намудрил с инициализацией UART'а...

Пишу на ассемблере. Вот текст программы (для компиляции использую AVR GCC, частота кварца 8 МГц).

Код
.nolist
#define __SFR_OFFSET    0
#include <avr/io.h>
#include <avr/interrupt.h>
.list

#define    RED    0b11111011
#define    BLUE    0b11110111
#define    GREEN    0b11101111
#define    OFF    0b11111111

tmp1        = 16
tmp2        = 17
led_color    = 18

.global        main

main:

.org 0
rjmp RESET    ; Reset Handler
reti; EXT_INT0    ; IRQ0 Handler
reti; EXT_INT1    ; IRQ1 Handler
reti; TIM2_COMP    ; Timer2 Compare Handler
reti; TIM2_OVF    ; Timer2 Overflow Handler
reti; TIM1_CAPT    ; Timer1 Capture Handler
reti; TIM1_COMPA    ; Timer1 CompareA Handler
reti; TIM1_COMPB    ; Timer1 CompareB Handler
reti; TIM1_OVF    ; Timer1 Overflow Handler
reti; TIM0_OVF    ; Timer0 Overflow Handler
reti; SPI_STC    ; SPI Transfer Complete Handler
rjmp UART_RXC    ; UART RX Complete Handler
reti; UART_DRE    ; UDR Empty Handler
reti; UART_TXC    ; UART TX Complete Handler
reti; ADC    ; ADC Conversion Complete Interrupt
reti; EE_RDY    ; EEPROM Ready Handler
reti; ANA_COMP    ; Analog Comparator Handler

RESET:
    ldi    tmp1, lo8(RAMEND); Stack setup
    out    SPL, tmp1
    ldi    tmp1, hi8(RAMEND)
    out    SPH, tmp1

    ldi    tmp1, 51; set uart baudrate to 9600 baud
    out    UBRR, tmp1

    ldi    tmp1, (1<<TXEN)|(1<<RXEN)|(1<<RXCIE); enable RXint and enable tx/rx
    out    UCR, tmp1

    ser    tmp1
    out    DDRC, tmp1; set all PORTC bits as output

    ldi    led_color, BLUE; turn on blue led by default
    ldi    tmp2, OFF

    sei        ; global enable interrupts

LOOP1:
    out    PORTC, led_color; LED on
    rcall    wait_some_time
    out    PORTC, tmp2    ; LED off
    rcall    wait_some_time
    rjmp    LOOP1        ; repeat

wait_some_time:
    push    r24
    push    r25
    ldi    r24, 0xFF
    ldi    r25, 0xFF

wait_some_time_loop:
    sbiw    r24, 1
    brne    wait_some_time_loop
    pop    r25
    pop    r24
    ret

UART_RXC:
    ldi    led_color, GREEN
    reti
VladimirB
Цитата(TwisteR @ Jul 29 2009, 00:12) *
У меня возник вопрос по инициализации UART в AT90S8535.

Компилируется нормально, прошивается тоже. При включении мигает синий светодиод (т.е. нормально функционирует основной цикл программы - LOOP1). Но стоит только послать что то по юарту - МК "виснет" (т.е. вместо загорания зелёного светодиода мигающий синий останавливается в том состоянии, на которое пришллось прерывание).

Помогите, пожалуйста, определить, в чём проблема. Подозреваю, что намудрил с инициализацией UART'а...

Пишу на ассемблере. Вот текст программы (для компиляции использую AVR GCC, частота кварца 8 МГц).


По приходу данных флаг RXC устанавливается в 1, что вызывает прерывание. Но этот флаг сбрасывается только при чтении регистра UDR, а у вас оно отсутствует - поэтому прерывание начинает генерироваться снова и снова - что приводит к зависанию.
Вставьте в обработчик прерывания команду
Код
in R7, UDR;

и всё случится smile.gif
TwisteR
Цитата(VladimirB @ Jul 28 2009, 23:17) *
Вставьте в обработчик прерывания команду
Код
in R7, UDR;

и всё случится smile.gif

"Это слишком хорошо, чтобы быть правдой" =)
Код
UART_RXC:
    in    r19, UDR;
    reti


К сожалению, не помогло sad.gif МК по прежнему виснет при посылке байта на PD0 (RXD). Какие ещё могут быть варианты?
singlskv
Цитата(TwisteR @ Jul 29 2009, 00:12) *
ldi led_color, GREEN
Обясните пожалуйста что Вы делаете таким оператором ?
TwisteR
Цитата(singlskv @ Jul 29 2009, 00:26) *
Обясните пожалуйста что Вы делаете таким оператором ?

В начале файла обьявлено:
Код
#define    GREEN    0b11101111

Следовательно, эта инструкция загружает значение 0b11101111 в регистр led_color (r18), откуда я в основном цикле вывожу его на порт, к которому подпаян трёхцветный светодиод с общим анодом.
ReAl
Линкуете "вручную" или вызывая avr-gcc "и пусть он заботится"?
Дизассемблировать avr-objdump -ом уже собранную программу целиком пробовали?

Дело в том, что если идёт стандартная линковка, то обычный "сишный" startup-код подлинковывается и таблица прерываний в нём, Ваша ничего не делает и её можно убрать. А метку обработчика прерываний объявить так, как этого ждёт стартап-код. Ну и UDR вынимать нужно

Код
    .global main
main:
  ; .org 0 и таблицу векторов выбросить
  ; тут то, что у Вас идёт после метки RESET
    ...
    ...

  ; имя обработчика прерываний - как и в C-программах,
  ; брать из io*.h для нужного контроллера
    .global UART_RX_vect
UART_RX_vect:
    ...
    reti
TwisteR
Цитата(ReAl @ Jul 29 2009, 07:06) *
Дизассемблировать avr-objdump -ом уже собранную программу целиком пробовали?

Пробовал конечно, но всегда настораживало вот это (вижу, что таблица прерываний, но не понимаю, почему она вся однородная, ведь я использовал одно из них):
Код
Disassembly of section .text:

00000000 <__vectors>:
   0:    10 c0           rjmp    .+32     ; 0x22 <__ctors_end>
   2:    17 c0           rjmp    .+46     ; 0x32 <__bad_interrupt>
   4:    16 c0           rjmp    .+44     ; 0x32 <__bad_interrupt>
   6:    15 c0           rjmp    .+42     ; 0x32 <__bad_interrupt>
   8:    14 c0           rjmp    .+40     ; 0x32 <__bad_interrupt>
   a:    13 c0           rjmp    .+38     ; 0x32 <__bad_interrupt>
   c:    12 c0           rjmp    .+36     ; 0x32 <__bad_interrupt>
   e:    11 c0           rjmp    .+34     ; 0x32 <__bad_interrupt>
  10:    10 c0           rjmp    .+32     ; 0x32 <__bad_interrupt>
  12:    0f c0           rjmp    .+30     ; 0x32 <__bad_interrupt>
  14:    0e c0           rjmp    .+28     ; 0x32 <__bad_interrupt>
  16:    0d c0           rjmp    .+26     ; 0x32 <__bad_interrupt>
  18:    0c c0           rjmp    .+24     ; 0x32 <__bad_interrupt>
  1a:    0b c0           rjmp    .+22     ; 0x32 <__bad_interrupt>
  1c:    0a c0           rjmp    .+20     ; 0x32 <__bad_interrupt>
  1e:    09 c0           rjmp    .+18     ; 0x32 <__bad_interrupt>
  20:    08 c0           rjmp    .+16     ; 0x32 <__bad_interrupt>


Ну, думаю, пускай так и будет (не знал ведь, как оно должно быть на самом деле cranky.gif )
Последовал вашему совету (про _vect не знал sad.gif ) и с удивлением обнаружил вот что biggrin.gif :
Код
  14:    0e c0           rjmp    .+28     ; 0x32 <__bad_interrupt>
  16:    32 c0           rjmp    .+100    ; 0x7c <__vector_11>
  18:    0c c0           rjmp    .+24     ; 0x32 <__bad_interrupt>


Прошил МК и всё заработало 8) Век живи, век учись...

Цитата(ReAl @ Jul 29 2009, 07:06) *
Дело в том, что если идёт стандартная линковка, то обычный "сишный" startup-код подлинковывается и таблица прерываний в нём, Ваша ничего не делает и её можно убрать. А метку обработчика прерываний объявить так, как этого ждёт стартап-код. Ну и UDR вынимать нужно

Спасибо большое за обьяснение, так и знал, что не до конца разобрался с синтаксисом. В Сети море примеров, но очень мало именно на ассемблере (для GCC). Руководствовался тем, что удалось найти, в частности этой программой генератора простейших сигналов. Как я понял, её автор линкует вручную?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.