Вопрос возник в ходе первого знакомства с USART. Была написана тестовая прога. Первая её версия гасит светодиод по приходу нуля и зажигает по приходу любого другого символа - работало. Потом решил добавить передачу: по нажатию кнопки контроллер простейшим образом, без буфера, 1 старт и стоп бит, отсылает компьютеру вот такое выражение: "23C ".
Передача заработала, но потери данных меня смущают (так и должно быть?)
Спойлер

Проверил, не уходит ли в ребут или в обработчике косяк - вроде всё в норме.
Прошу помощи по данному вопросу.
Мейн код:
Спойлер
Код: Выделить всё
.include "m88PAdef.inc" ; Используем ATmega88PA
.include "macrobaselib.inc" ; Макроопределения
;======== RAM ============
.DSEG ; Сегмент ОЗУ
StrPtr: .byte 2
;======= FLASH ===========
.CSEG ; Кодовый сегмент
.ORG 0x0000 ; (RESET)
RJMP Reset
.include "ivectors.inc" // Подключим файл с таблицой прерываний
;----------------------------------------------------------------------
; Это обработчик прерывания. Тут, на просторе, можно наворотить сколько
; угодно кода.
RX_OK:
PUSHF ; Сохраняем в стек SREG и R16
LDS R22,UDR0 ; Тут главное забрать байт из UDR иначе
; флаг прерывания не снимется
; Дальше, если время позволяет, можно и обработать
subi R22, 0b00110000 //Вычитаем из R22 ASCII-код нуля
breq I1 //Если пришел нуль, то гасим светодиод
rjmp I2 //Если любое другое - зажигаем
I1:
OUTI PORTB, 0b00000010 ; Гасим светодиод
rjmp Rx_Exit
I2:
OUTI PORTB, 0b00000011 ; Зажигаем светодиод
OUTI PORTD, 0b10000000
Rx_Exit:
POPF ; Достаем SREG и R16
RETI
TX_OK:
reti
UD_OK:
PUSHF ; Макрос, сохраняющий SREG и R16
PUSH ZL ; Сохраняем в стеке Z
PUSH ZH
LDS ZL,StrPtr ; Грузим указатели в индексные регистры
LDS ZH,StrPtr+1
LPM R16,Z+ ; Хватаем байт из флеша. Из нашей строки
CPI R16,0 ; Если он не ноль, значит читаем дальше
BREQ STOP_RX ; Иначе останавливаем передачу
STS UDR0,R16 ; Выдача данных в USART.
STS StrPtr,ZL ; Сохраняем указатель
STS StrPtr+1,ZH ; обратно, в память
OUTI PORTD, 0b10000000
Exit_RX:
POP ZH ; Все достаем из стека, выходим.
POP ZL
POPF
RETI
; глушим прерывание по опустошению, выходим из обработчика
STOP_RX:
LDI R16, (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0)|(0<<UDRIE0)
STS UCSR0B, R16
RJMP Exit_RX
;----------------------------------------------------------------------
// Теперь инициализируем всё, что нам нужно, а особенно стек.
Reset:
STACKINIT // Инициализация стека
RAMFLUSH // Очистка ОЗУ
GPRFLUSH // Очистка РОН (Регистров Общего Назначения)
.equ XTAL = 16000000
.equ baudrate = 9600
.equ bauddivider = XTAL/(16*baudrate)-1
uart_init: //Инициализация USART
; -------------------------------------------------------------------
;|Записываем в UBRR0H:UBRR0L делитель для настройки скорости передачи|
; -------------------------------------------------------------------
LDI R16, low(bauddivider)
STS UBRR0L,R16
LDI R16, high(bauddivider)
STS UBRR0H,R16
LDI R16, 0
STS UCSR0A, R16
; Прерывания прием-передачи разрешены, прием-передача разрешена
LDI R16, (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0)|(0<<UDRIE0)
STS UCSR0B, R16
; Формат кадра - 8 бит
LDI R16, (1<<UCSZ00)|(1<<UCSZ01)
STS UCSR0C, R16
OUTI DDRB, 0b11111101 //Инициализация порта B, PB0 - на выход
OUTI PORTB, 0b00000010 //Подтяжка на PB0 и PB1
OUTI DDRD, 0b11111111
OUTI PORTD, 0b00000000
sei // Глобально разрешаем прерывания
Main:
INR R16, PINB //Загружаем значение всего порта B в temp
subi R16, 0b00000010
brpl M1 //Если кнопка не нажата, то крутимся дальше
LDI R17,low(2*String) ; Берем младший байт
LDI R18,High(2*String) ; Берем старший байт
STS StrPtr,R17 ; Сохраняем Младший байт
STS StrPtr+1,R18 ; Сохраняем Сташрий байт
//Разрешаем прерывание по опустошению UDRIE
LDI R16, (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0)|(1<<UDRIE0)
STS UCSR0B, R16
M1:
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rcall Delay
rjmp Main
Delay:
ldi R20,0 ;начало подпрограммы
Loop:
dec R20
brne Loop
dec R21
brne Loop
ret
String: .db "23C ",0
;===== EEPROM ============
.ESEG ; Сегмент EEPROM (ППЗУ)
Спойлер
Код: Выделить всё
; ***** INTERRUPT VECTORS ************************************************
; Используем HAL Микроконтроллера "ATmega88PA"
.org INT0addr ; External Interrupt Request 0
reti
.org INT1addr ; External Interrupt Request 1
reti
.org PCI0addr ; Pin Change Interrupt Request 0
reti
.org PCI1addr ; Pin Change Interrupt Request 0
reti
.org PCI2addr ; Pin Change Interrupt Request 1
reti
.org WDTaddr ; Watchdog Time-out Interrupt (Не стоило злить собаку...)
reti
.org OC2Aaddr ; Timer/Counter2 Compare Match A
reti
.org OC2Baddr ; Timer/Counter2 Compare Match A
reti
.org OVF2addr ; Timer/Counter2 Overflow
reti
.org ICP1addr ; Timer/Counter1 Capture Event
reti
.org OC1Aaddr ; Timer/Counter1 Compare Match A
reti
.org OC1Baddr ; Timer/Counter1 Compare Match B
reti
.org OVF1addr ; Timer/Counter1 Overflow
reti
.org OC0Aaddr ; TimerCounter0 Compare Match A
reti
.org OC0Baddr ; TimerCounter0 Compare Match B
reti
.org OVF0addr ; Timer/Couner0 Overflow
reti
.org SPIaddr ; SPI Serial Transfer Complete
reti
.org URXCaddr ; USART Rx Complete
RJMP RX_OK
.org UDREaddr ; USART, Data Register Empty
RJMP UD_OK
.org UTXCaddr ; USART Tx Complete
RJMP TX_OK
.org ADCCaddr ; ADC Conversion Complete
reti
.org ERDYaddr ; EEPROM Ready
reti
.org ACIaddr ; Analog Comparator
reti
.org TWIaddr ; Two-wire Serial Interface
reti
.org SPMRaddr ; Store Program Memory Read
reti
.org INT_VECTORS_SIZE ; size in words <<Конец таблицы прерываний>>
;=== END "ivectors.inc" ================
Если нужна еще информация - пишите, выложу.




