PORTx сбрасываются в 0 (ATmega88PA)

Обсуждаем контроллеры компании Atmel.
Ответить
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

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

Код: Выделить всё

.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" ================
Светодиод сидит на PB0, кнопка на PB1. Еще один светодиод посадил на PD7. Среда разработки: AVR Studio 4. Связь с компьютером через FT232RL, терминальная программа - Terminal v1.91b.
Если нужна еще информация - пишите, выложу.
Последний раз редактировалось НАПАЛМ Вс июн 29, 2014 11:45:55, всего редактировалось 1 раз.
Реклама
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

Сообщение Pink-Pank »

Передача заработала, но потери данных меня смущают (так и должно быть?)
Такое может быть, если Вы не очень точно настроили скорость UART и не делаете задержек между отправками байтов, а посылаете их друг за дружкой по факту опустошения буфера. Ошибка частоты UART накапливается и в один прекрасный момент Вы видете такой результат.

P.S. Код не смотрел пока.
Fucking static initialization order fiasco
Контактная информация:
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

поддерживаю мнение Pink-Pank. код посмотрел.
Советую слать новые данные не по прерыванию опустошения буфера, а по прерыванию окончания отправки, в нем все равно у вас только reti. Попробуйте, о результатах отпишитесь.
По поводу логики работы и сбросах светодиода, не могу сказать точно, но мне кажется идея с вычитанием не лучшая идея для проверки кнопки. sbrc, sbrs - как альтернатива. попробуйте.
Ставим плюсы: )
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Да, похоже ошибка в передаче из-за отсутствия буферизации - с ней пока решил не заморачиваться (больше кода, менее читабельно). А как можно неточно настроить частоту USART, там же формула одна всего?
По UD_OK я передавал, т.к. в обучалке DI Halt'а это аргументировалось:
А зачем нужно прерывание TX_OK? Ну мало ли зачем. Еще какое-нибудь событие повесить. Оно сработает когда произойдет две вещи — UDR кончится и в сдвиговом регистре USART все биты улетят в провод. В принципе, многие юзают его вместо UDRE, но тогда между двумя уходящими байтами будет промежуток периодом в 1 байт. Что не очень кошерно.
Буферизацию запилю чуть позже и отпушусь о результатах.
Но все-таки главный затык со светодиодами - что же порты обнуляет? Причём два светодиода на разных портах.
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

при работе с UART, ножка RX автоматом сконфигурирована как вход, ножка TX - выход
RXD, Receive Data (Data input pin for the USART). When the USART Receiver is enabled this pin is configured as an input regardless of the value of DDD0. When the USART forces this pin to be an input, the pull-up can still be controlled by the PORTD0 bit.
я полагаю, что ваш команда: OUTI PORTD, 0b10000000 могла сформировать стартовый бит на входе приемника, который в этот момент принимает неизвестно что. При работе с битами портов используйте sbi, cbi (атомарно), или конструкцию вида in-or/and-out (не атомарно).
Еще, ошибки UART (Frame Error (FEn), Data OverRun (DORn) and Parity Error (UPEn)) вы не анализируете, а следовало бы.
Ставим плюсы: )
Реклама
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Второй светодиод, а соответственно и (пере)инициализацию PORTD, я ввел уже после появления бага - значит отпадает.
ibiza11 писал(а):При работе с битами портов используйте sbi, cbi (атомарно), или конструкцию вида in-or/and-out (не атомарно)
Буду повышать свой скил владения ассемблером, спасибо. Изображение
А то в голову все сразу не впихнуть.
ibiza11 писал(а): Еще, ошибки UART (Frame Error (FEn), Data OverRun (DORn) and Parity Error (UPEn)) вы не анализируете, а следовало бы.
Что конкретно предлагаете? Повесить светодиод на ошибку и смотреть, что будет по приёму байта?
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

вот так попробуйте залить и проверьте:
Спойлер

Код: Выделить всё

.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:
    cbi  portb,0;OUTI PORTB, 0b00000010 ; Гасим светодиод
    rjmp Rx_Exit   
I2:
    sbi  portb,0;OUTI PORTB, 0b00000011 ; Зажигаем светодиод        
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   ; обратно, в память
    sbi   portd,7 ;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, 0b11100000
   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,  0b11111110
   OUTI    PORTD, 0b00000001
   sei // Глобально разрешаем прерывания

Main:
   IN R16, PINB //Загружаем значение всего порта B в temp
   sbrc R16,1
   rjmp 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 (ППЗУ)
Ставим плюсы: )
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Залил, ничего не изменилось. Диод на PB0 по приходу символа загорается и вскоре гаснет. При передаче строки компьютеру светодиод на PD7 загорается, но гаснет вместе с PB0 после прихода символа.

И такой вопрос, зачем вот эта строчка?

Код: Выделить всё

  LDI    R16, 0b11100000
   STS    UCSR0A, R16
Зачем имитировать прием-передачу вначале?
Спойлер

Код: Выделить всё

; UCSR0A - USART Control and Status Register A
.equ	MPCM0	= 0	; Multi-processor Communication Mode
.equ	U2X0	= 1	; Double the USART transmission speed
.equ	UPE0	= 2	; Parity Error
.equ	DOR0	= 3	; Data overRun
.equ	FE0	= 4	; Framing Error
.equ	UDRE0	= 5	; USART Data Register Empty
.equ	TXC0	= 6	; USART Transmitt Complete
.equ	RXC0	= 7	; USART Receive Complete
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

может у вас контроллер сбрасывается? попробуйте в начале программы после Reset пару-тройку раз моргнуть светодиодом (типо такого в цикле: sbi portb,7 rcall delay, cbi portb,7 rcall delay)
будете знать, по морганию, что он сбросился.
НАПАЛМ писал(а):И такой вопрос, зачем вот эта строчка?
Эта строчка сбрасывает биты UDRE0, TXC0, RXC0. Они сбрасываются записью в них лог. 1.
Ставим плюсы: )
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

ibiza11 писал(а):Эта строчка сбрасывает биты UDRE0, TXC0, RXC0. Они сбрасываются записью в них лог. 1.
Но если эту строчку ввести, то при стартовой инизицализации происходит одиночная передача "23C  "
ibiza11 писал(а):может у вас контроллер сбрасывается? попробуйте в начале программы после Reset пару-тройку раз моргнуть светодиодом (типо такого в цикле: sbi portb,7 rcall delay, cbi portb,7 rcall delay)
будете знать, по морганию, что он сбросился.
Тоже была такая мысль, сделаю.
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Здравствуйте.
Долго не отвечал - закрывал сессию.
Вернулся к проекту, что сделал: убрал код светодиода на порте PD7 для ясности, оставил только на PB0. Внес в стартовую инициализацию код мигания светодиода, чтобы было наглядно видно - сбрасывается МК или нет. Прошил МК, посылаю с терминалки единичку - светодиод горит некоторое время (рандомно, 0-3 секунды), мигает и гаснет - значит сбрасывается МК.
Где затык, не пойму.

Новый код:
Спойлер

Код: Выделить всё

.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   R16,UDR0   ; Тут главное забрать байт из UDR иначе 
                    ; флаг прерывания не снимется
               ; Дальше, если время позволяет, можно и обработать
 
    subi R16, 0b00110000 //Вычитаем из R16 ASCII-код нуля
    breq I1  //Если пришел нуль, то гасим светодиод
    rjmp I2  //Если любое другое - зажигаем
I1:
    cbi  portb,0;OUTI PORTB, 0b00000010 ; Гасим светодиод
    rjmp Rx_Exit   
I2:
    sbi  portb,0;OUTI PORTB, 0b00000011 ; Зажигаем светодиод        
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   ; обратно, в память
;    sbi   portd,7 ;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
    ;----------- Конец инициализации USART -------------------------------

   OUTI    DDRB,  0b11111101 //Инициализация порта B, PB0 - на выход
   OUTI    PORTB, 0b00000011 //Подтяжка на PB0 и PB1
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000011 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
    OUTI    PORTB, 0b00000011 //Подтяжка на PB0 и PB1
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000011 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
    OUTI    PORTB, 0b00000011 //Подтяжка на PB0 и PB1
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000011 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   sei // Глобально разрешаем прерывания

Main:
   IN R16, PINB //Загружаем значение всего порта B в temp
   sbrc R16,1
   rjmp 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 (ППЗУ)


UPD 18:53
Магическим образом баг ушел. МК просто перестал сбрасываться, всё заработало как надо. Заметил такую вещь, при подключении USB кабеля к платке с FT232RL, если земли платы и кабеля соприкоснутся, то иногда МК сбрасывается. А если с терминалки слать слишком быстро байты, то МК может сбросится и/или послать какой-нибудь мусор обратно компьютеру. Сейчас запилю буфер, посмотрим на результат.

UPD 19:11
Но через продолжительное время МК всё равно сбрасывается...
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Сообщение ibiza11 »

а питаете вы тоже от USB? на RESET что-нибудь висит?
Ставим плюсы: )
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Питание - БП - лмка на 5В - мк. Ресет через 10К на плюсе питания, и подсоединен к ресету разъема для программатора без резистора.
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Так, я с вестями с поля боя.
Реализовал буферизацию на прием и на передачу. Не уверен, что работает правильно, потому что потери при передаче всё-таки остались, причем даже если кнопку нажимать раз в секунду. Может быть, это не програмная проблема...
Скрин терминалки:
СпойлерИзображение
Код:
Спойлер

Код: Выделить всё

.include "m88PAdef.inc" ; Используем ATmega88PA
.include "macrobaselib.inc" ; Макроопределения

 
;======== RAM ============
      .DSEG         ; Сегмент ОЗУ
      
StrPtr:      .byte   2
UCSR0B_temp: .byte   1
        .equ MAXBUFF_IN 	=	10	; Размер в байтах
		.equ MAXBUFF_OUT 	= 	10
 
IN_buff:	.byte	MAXBUFF_IN	; Буфер приема
IN_PTR_S:	.byte	1		; Указатель начала
IN_PTR_E:	.byte	1		; Указатель конца
IN_FULL:	.byte	1		; Флаг переполнения
 
OUT_buff:	.byte	MAXBUFF_OUT	; Буфер передачи
OUT_PTR_S:	.byte	1		; Указатель начала
OUT_PTR_E:	.byte	1		; Указатель конца
OUT_FULL:	.byte	1		; Флаг переполнения. 
 
;======= FLASH ===========
      .CSEG         ; Кодовый сегмент 

.ORG 0x0000        ; (RESET) 
         RJMP   Reset
.include "ivectors.inc" // Подключим файл с таблицой прерываний
;----------------------------------------------------------------------
; Это обработчик прерывания. Тут, на просторе, можно наворотить сколько
; угодно кода. 

RX_OK:		
        PUSHF				; Макрос, пихающий в стек SREG и R16
		PUSH	R17
		PUSH	R18
		PUSH	XL
		PUSH	XH
 
		LDI	XL,low(IN_buff)		; Берем адрес начала буффера
		LDI	XH,high(IN_buff)
		LDS	R16,IN_PTR_E		; Берем смещение точки записи
		LDS	R18,IN_PTR_S		; Берем смещение точки чтения
 
		ADD	XL,R16			; Сложением адреса со смещением
		CLR	R17		    	; получаем адрес точки записи
		ADC	XH,R17
 
		LDS	R17,UDR0		; Забираем данные
		ST	X,R17			; сохраняем их в кольцо
 
		INC	R16			; Увеличиваем смещение
 
		CPI	R16,MAXBUFF_IN		; Если достигли конца 
		BRNE	NoEnd
		CLR	R16			; переставляем на начало
 
NoEnd:	
     	CP	R16,R18			; Дошли до непрочитанных данных?
		BRNE	RX_OUT		; Если нет, то просто выходим
 
 
RX_FULL:
    	LDI	R18,1			; Если да, то буффер переполнен.
		STS	IN_FULL,R18		; Записываем флаг наполненности
 
RX_OUT:		
        STS	IN_PTR_E,R16	; Сохраняем смещение. Выходим

		POP	XH
		POP	XL
		POP	R18
		POP	R17
		POPF				; Достаем SREG и R16

		RETI


TX_OK:
        RETI


UD_OK:		
        PUSHF		   ; Пихаем в стек SPEG, R16, R17, R18, R19 
		PUSH	R17    ; и пару XL:XH	
		PUSH	R18
		PUSH	R19
		PUSH	XL
		PUSH	XH
 
 
		LDI	XL,low(OUT_buff)	; Берем адрес начала буффера
		LDI	XH,high(OUT_buff)
		LDS	R16,OUT_PTR_E		; Берем смещение точки записи
		LDS	R18,OUT_PTR_S		; Берем смещение точки чтения			
		LDS	R19,OUT_FULL		; Берем флаг переполнения
 
		CPI	R19,1			; Если буффер переполнен, то указатель начала
		BREQ	NeedSend	; Равен указателю конца. Это надо учесть.
 
		CP	R18,R16			; Указатель чтения достиг указателя записи?
		BRNE	NeedSend	; Нет! Буффер не пуст. Надо слать дальше
 
		LDI 	R16,(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0)|(0<<UDRIE0) 
		STS 	UCSR0B, R16		; Запрет прерывания По пустому UDR
		RJMP	TX_OUT			; Выходим
 
NeedSend:	
        CLR	R17			    ; Получаем ноль
		STS	OUT_FULL,R17	; Сбрасываем флаг переполнения
 
		ADD	XL,R18			; Сложением адреса со смещением
		ADC	XH,R17			; получаем адрес точки чтения
 
		LD	R17,X			; Берем байт из буффера
		STS	UDR0,R17		; Отправляем его в USART
 
		INC	R18			; Увеличиваем смещение указателя чтения
 
		CPI	R18,MAXBUFF_OUT		; Достигли конца кольца?
		BRNE	TX_OUT			; Нет? 
 
		CLR	R18			; Да? Сбрасываем, переставляя на 0
 
TX_OUT:		
        STS	OUT_PTR_S,R18		; Сохраняем указатель
 
		POP	XH
		POP	XL
		POP	R19
		POP	R18
		POP	R17
		POPF				; Выходим, достав все из стека

		RETI
;----------------------------------------------------------------------
 // Теперь инициализируем всё, что нам нужно, а особенно стек.
 
Reset: 
 STACKINIT // Инициализация стека
 RAMFLUSH  // Очистка ОЗУ
 GPRFLUSH  // Очистка РОН (Регистров Общего Назначения)


.equ    XTAL = 16000000    
.equ    baudrate = 19200  
.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
    ;----------- Конец инициализации USART -------------------------------

   OUTI    DDRB,  0b11111101 //Инициализация порта B, PB0 - на выход
   OUTI    PORTB, 0b00000011 //Подтяжка на PB0 и PB1
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000011 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
    OUTI    PORTB, 0b00000011 //Подтяжка на PB0 и PB1
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000011 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
    OUTI    PORTB, 0b00000011 //Подтяжка на PB0 и PB1
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000011 
   rcall Delay
   rcall Delay
   OUTI    PORTB, 0b00000010 
   rcall Delay
   rcall Delay
   SEI // Глобально разрешаем прерывания

Main:
   RCALL Buff_Pop ; Вызываем подпрограмму чтения из буфера приема USART
                  ; В R19 - код ошибки (1 - пустой буфер), R17 - данные.
   CPI R19, 1     ; Проверяем, пустой ли буфер.
   BREQ M1        ; Если буфер пуст, то идем на М1.

   SUBI R17, 0b00110000 //Вычитаем из R17 ASCII-код нуля
   BREQ I1  //Если пришел нуль, то гасим светодиод
   rjmp I2  //Если любое другое - зажигаем
I1:
   cbi  portb,0  ;Гасим светодиод
   rjmp M1   
I2:
   sbi  portb,0  ;Зажигаем светодиод        


M1:
   IN R16, PINB   ; Загружаем значение всего порта B в temp
   sbrc R16,1
   rjmp M2        ; Если кнопка не нажата, то крутимся дальше


   LDI   R17,low(2*String)   ; Берем младший байт
   LDI   R18,High(2*String)  ; Берем старший байт
 
   STS   StrPtr,R17        ; Сохраняем Младший байт
   STS   StrPtr+1,R18      ; Сохраняем Сташрий байт

   LDS   ZL,StrPtr   ; Грузим указатели в индексные регистры
   LDS   ZH,StrPtr+1
New_symbol:
   LPM   R19,Z+    ; Хватаем байт из флеша из нашей строки.
   CPI   R19,0     ; Достигли конца строки?  
   BREQ RUN        ; Если да, то запускаем передачу.
  
   RCALL Buff_Push ;Вызываем подпрограмму записи в буфер USART
                   ;Перед вызовом в R19 мы должны иметь данные для передачи
				   ;А на выходе мы получим код ошибки (R19=1 - буфер переполнен)
   
   CPI	R19,1	   ; Буфер переполнился?
   BRNE	New_symbol ; Если не переполнился, то грузим в буфер следующий символ.
                   ; А если переполнился, то запускаем передачу,
				   ; но юзаем делей, чтобы данные успели отправится.
   LDI    R16, (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0)|(1<<UDRIE0)
   STS    UCSR0B, R16 //Разрешаем прерывание по опустошению UDRIE
   	
   RCALL Delay		; Ждем или передаем управление другой задаче
   rjmp	 New_symbol		; А потом снова пробуем положить в буфер.

    
RUN:      
   LDI    R16, (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0)|(1<<UDRIE0)
   STS    UCSR0B, R16 //Разрешаем прерывание по опустошению UDRIE
  

M2:   
   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]---------------------------*
Delay:
   LDI R20,0    

Loop:
   dec R20
   BRNE Loop

   dec R21
   BRNE Loop
     
   ret
;-----------------Конец подпрограммы-----------------------------------


;--------Подпрограмма чтения из буфера USART---------------------------*
; OUT: 	R17 - Data,
;		R19 - ERROR CODE
Buff_Pop:
        LDS R16, UCSR0B      ; Берем в R16 значение UCSR0B
		STS UCSR0B_temp, R16 ; Сажаем предыдущее значение UCSR0B в ОЗУ  
        LDI R16, (0<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)
        STS UCSR0B, R16      ; Запрещаем прерывания от UART
                             ; для соблюдения атомарности.

		LDI	XL,low(IN_buff)	 ; Берем адрес начала буффера
		LDI	XH,high(IN_buff)
		LDS	R16,IN_PTR_E	 ; Берем смещение точки записи
		LDS	R18,IN_PTR_S	 ; Берем смещение точки чтения			
		LDS	R19,IN_FULL		 ; Берм флаг переполнения
 
		CPI	R19,1			 ; Если буффер переполнен, то указатель начала
		BREQ	NeedPop		 ; Равен указателю конца. Это надо учесть.
 
		CP	R18,R16			 ; Указатель чтения достиг указателя записи?
		BRNE	NeedPop		 ; Нет! Буффер не пуст. Работаем дальше
 
		LDI	R19,1			 ; Код ошибки - пустой буффер!
 
		RJMP	_TX_OUT		 ; Выходим
 
NeedPop:
    	CLR	R17			    ; Получаем ноль
		STS	IN_FULL,R17		; Сбрасываем флаг переполнения
 
		ADD	XL,R18			; Сложением адреса со смещением
		ADC	XH,R17			; получаем адрес точки чтения
 
		LD	R17,X		; Берем байт из буффера
		CLR	R19			; Сброс кода ошибки
 
		INC	R18			; Увеличиваем смещение указателя чтения
 
		CPI	R18,MAXBUFF_OUT		; Достигли конца кольца?
		BRNE	_TX_OUT			; Нет? 
 
		CLR	R18			; Да? Сбрасываем, переставляя на 0
 
_TX_OUT:	
        STS	IN_PTR_S,R18		; Сохраняем указатель

		LDS R16, UCSR0B_temp	;Загружаем в R16 предыдущее состояние UCSR0B
        STS UCSR0B, R16         ;Возвращаем обратно прерывания по USART

		RET
;-----------Конец подпрограммы-----------------------------------------


;--------Подпрограмма записи в буфер USART-----------------------------*
; IN R19 	- DATA
; OUT R19 	- ERROR CODE
Buff_Push:
        PUSH ZL
		PUSH ZH
        LDS R16, UCSR0B      ; Берем в R16 значение UCSR0B
		STS UCSR0B_temp, R16 ; Сажаем предыдущее значение UCSR0B в ОЗУ  
        LDI R16, (0<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)
        STS UCSR0B, R16      ; Запрещаем прерывания от UART
                             ; для соблюдения атомарности.
							  
		LDI	XL,low(OUT_buff)	; Берем адрес начала буффера
		LDI	XH,high(OUT_buff)
		LDS	R16,OUT_PTR_E		; Берем смещение точки записи
		LDS	R18,OUT_PTR_S		; Берем смещение точки чтения
 
		ADD	XL,R16		; Сложением адреса со смещением
		CLR	R17			; получаем адрес точки записи
		ADC	XH,R17
 
 
		ST	X,R19		; сохраняем их в кольцо
		CLR	R19			; Очищаем R19, теперь там код ошибки
						; Который вернет подпрограмма
 
		INC	R16			; Увеличиваем смещение
 
		CPI	R16,MAXBUFF_OUT		; Если достигли конца 
		BRNE	_NoEnd
		CLR	R16			; переставляем на начало
 
_NoEnd:	
    	CP	R16,R18			; Дошли до непрочитанных данных?
		BRNE	_RX_OUT		; Если нет, то просто выходим
 
 
_RX_FULL:
    	LDI	R19,1			; Если да, то буффер переполнен.
		STS	OUT_FULL,R19	; Записываем флаг наполненности
						    ; В R19 остается 1 - код ошибки переполнения
 
_RX_OUT:
    	STS	OUT_PTR_E,R16		; Сохраняем смещение. Выходим

		LDS R16, UCSR0B_temp	;Загружаем в R16 предыдущее состояние UCSR0B
        STS UCSR0B, R16         ;Возвращаем обратно прерывания по USART

		POP ZH
		POP ZL

        RET
;-----------Конец подпрограммы-----------------------------------------

String:      .db   "23C  ",0 
;===== EEPROM ============
      .ESEG         ; Сегмент EEPROM (ППЗУ)
После запайки тантала на 22 мкФ на вход лмки сбросы прекратились, аптайм был около 6ти часов (потом я его сам сбросил).

UPD 19:49
Отключил программатор (AVR ISP mkII клон) от схемы, количество ошибок при передаче ЗНАЧИТЕЛЬНО уменьшилось: заполнил весь экран терминалки, 3 ошибки. Питание от программатора на плату не подается, земли и ресет программатора и платы соединены.

UPD 22:00
Всё-таки, ошибки при передаче остаются, программатор ни при чем.
Держит паяльник хвостом
Сообщения: 963
Зарегистрирован: Чт апр 03, 2014 23:16:55
Откуда: Россия

Сообщение Rtmip »

просто другую программу терминала на всякий случай попробовать?
PS: Еще вариант, перепишите под скорость 9600 и проверьте.
Мудрый кот
Аватара пользователя
Сообщения: 1811
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

На 9600 ошибка в скорости такая же, что и на 19200. Тогда уж 2400 в режиме удвоенной скорости (U2X=1), там ошибка около нуля.
Ну, или, взять скорость, при которой ошибка "в другую сторону", например 28800 с U2X=0 или 57600 с U2X=1. Только в этих случаях ошибка больше и, возможно, глюков будет больше.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Держит паяльник хвостом
Сообщения: 963
Зарегистрирован: Чт апр 03, 2014 23:16:55
Откуда: Россия

Сообщение Rtmip »

Kavka, Ваши рассуждения верны, однако, мой совет про проверку на скорости 9600 основан на:
НАПАЛМ писал(а):Связь с компьютером через FT232RL, терминальная программа - Terminal v1.91b.
Нечто похожее наблюдал при подключениях через USB2com.
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1315
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

Всем привет еще раз. Скачал такую же терминалку, но более ранней версии и всё заработало как надо: и графики чертятся и ошибок при приёме нет никаких. Спасибо большое за помощь.
Сейчас изучаю АЦП и буду пытаться подключить MPXV5100G к микроконтроллеру.
Ответить

Вернуться в «AVR»