ATmega8A учусь использовать прерывания

Обсуждаем контроллеры компании Atmel.
Ответить
sashavir
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Вт дек 30, 2014 21:35:51

ATmega8A учусь использовать прерывания

Сообщение sashavir »

Люди добрые, ткните носом, что делаю не так, только изучаю ассемблер... Цель стояла сделать так, чтобы на порту B горел светодиод 2 сразу, а по нажатию на кнопку соединяющую землю и вывод INT0 на микроконтроллере загоралать вторая лампочка. В моем нынешнем варианте, они просто моргают поочередно...

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

.def temp=r16      ;меняю имя регистра, не с глубогим смыслом, а чтобы поэксперементировать

.cseg
.org 0             ;назначаю адрес и куда загружать

rjmp reset         ;перечисляю все прерывания для ATmega8a из даташита и назначаю им метки
rjmp _int0
rjmp _int1
rjmp timer2_comp
rjmp timer2_ovf
rjmp timer1_capt
rjmp timer1_compa
rjmp timer1_compb
rjmp timer1_ovf
rjmp timer0_ovf
rjmp spi_stc
rjmp usart_rxc
rjmp usart_udre
rjmp usart_txc
rjmp _adc
rjmp ee_rdy
rjmp ana_comp
rjmp twi
rjmp spm_rdy

reset:              ;тут перечисляю метки, выдрано с обучалки с этого сайта, не совсем пока разабрался зачем все перечислять
;_int0:             ;тут не уверен, что правильно сделал... Получается закоментил или просто убрал _int0, чтобы вынести его отдельно 
_int1:
timer2_comp:
timer2_ovf:
timer1_capt:
timer1_compa:
timer1_compb:
timer1_ovf:
timer0_ovf:
spi_stc:
usart_rxc:
usart_udre:
usart_txc:
_adc:
ee_rdy:
ana_comp:
twi:
spm_rdy:

reti                ;выход из обработчика прерываний

_int0:              ;начало программы по внешнему воздействию на порт PD2

ldi temp,0b00000001 ;здесь меняю биты ISC00 на 1 и ISC01 на 0, т.е. любая смена логического состояния, если я правильно разобрался
out MCUCR,temp      ;здесь загружаю биты в регистр

ldi r17,0b11111111  
out DDRB,r17        ;настройка порта B на вывод

ldi r18,0b00000001  
out portb,r18       ;зажигаю первую лампочку

sei                 ;разрешаю прерывания, тут совсем не уверен, что делаю правильно...

reti                ;выход из обработчика прерываний

ldi r17,0b11111111  ;основная программа зажигающая второй светодиод
out DDRB,r17

ldi r18,0b00000010
out portb,r18

sleep               ;воткнул просто ради эксперемента
Реклама
Аватара пользователя
НАПАЛМ
Это не хвост, это антенна
Сообщения: 1314
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Re: ATmega8A учусь использовать прерывания

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

Это весь код? Где инициализация стека, для начала?
Реклама
sashavir
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Вт дек 30, 2014 21:35:51

Re: ATmega8A учусь использовать прерывания

Сообщение sashavir »

Да я ж говорю, я пока полный чайник :)) Тут нужно инициализировать стек обязательно? Если да, то пойду курить про стек, я еще просто до разбора стека не дошел?
Аватара пользователя
НАПАЛМ
Это не хвост, это антенна
Сообщения: 1314
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Re: ATmega8A учусь использовать прерывания

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

Да, обязательно.
http://easyelectronics.ru/category/avr-uchebnyj-kurs
Используйте этот курс, начните с самого начала - там где работа с AVR студией. Всё очень просто и понятно объясняется.
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: ATmega8A учусь использовать прерывания

Сообщение Engineer_Keen »

sashavir писал(а):Люди добрые, ткните носом, что делаю не так, только изучаю ассемблер...
Только начали изучать и сразу полезли в прерывания? Вам бы сначала просто светодиодом поморгать, осознать принцип и структуру программ на ассемблере. В общем вас правильно послали, но не совсем точно. Точнее будет наверно примерно туда, ну +- пара постов.
По порядку.
Спойлер

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

rjmp reset         ;перечисляю все прерывания для ATmega8a из даташита и назначаю им метки
rjmp _int0
rjmp _int1
rjmp timer2_comp
rjmp timer2_ovf
rjmp timer1_capt
rjmp timer1_compa
rjmp timer1_compb
rjmp timer1_ovf
rjmp timer0_ovf
rjmp spi_stc
rjmp usart_rxc
rjmp usart_udre
rjmp usart_txc
rjmp _adc
rjmp ee_rdy
rjmp ana_comp
rjmp twi
rjmp spm_rdy
Можно, но чтобы не загромождать программу лучше писать только нужные метки:

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

	.org	0
	RJMP	RESET
	.org	INT0addr
	RJMP	INT0_A
RESET:	
Кто-то скажет, что если сработает прерывание для которого нет вектора, то заглушка RETI поможет (как это почти сделано у вас). Я скажу что надо уметь пользоваться отладкой и исключать такие ошибки, а не ставить костыли.
Спойлер

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

reset:              ;тут перечисляю метки, выдрано с обучалки с этого сайта, не совсем пока разабрался зачем все перечислять
;_int0:             ;тут не уверен, что правильно сделал... Получается закоментил или просто убрал _int0, чтобы вынести его отдельно 
_int1:
timer2_comp:
timer2_ovf:
timer1_capt:
timer1_compa:
timer1_compb:
timer1_ovf:
timer0_ovf:
spi_stc:
usart_rxc:
usart_udre:
usart_txc:
_adc:
ee_rdy:
ana_comp:
twi:
spm_rdy:

reti                ;выход из обработчика прерываний
Да, вот эти самые заглушки. Но реализация кривая, т.к. первой строкой выполнится всегда rjmp reset, а после метки ресет у вас первой командой (после кучи меток-затычек) идет reti, это уже ошибка, т.к. 1)стек не инициализирован 2)даже при инициализированном стеке не было вызова RCALL или прерывания. Это может привести просто к сбросу или переходу на случайное место, смотря что будет в стеке
Спойлер

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

_int0:              ;начало программы по внешнему воздействию на порт PD2
Допустим правильно...

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

ldi temp,0b00000001 ;здесь меняю биты ISC00 на 1 и ISC01 на 0, т.е. любая смена логического состояния, если я правильно разобрался
out MCUCR,temp      ;здесь загружаю биты в регистр
Настраивать прерывание и условия его возникновения нужно не в самом прерывании, а в инициализации программы. Подозреваю, что вы не совсем понимаете, как это работает...
И сразу советую отучаться писать магические цифры (0b00000001) при настройке регистров, пишите так:

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

ldi temp,(1<<ISC00)|(0<<ISC01) ;так сразу понятно о каких битах речь

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

ldi r17,0b11111111  
out DDRB,r17        ;настройка порта B на вывод
Не обязательно каждый раз настраивать порт на вывод, если это уже сделано при инициализации программы

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

ldi r18,0b00000001  
out portb,r18       ;зажигаю первую лампочку
sei                 ;разрешаю прерывания, тут совсем не уверен, что делаю правильно...
reti                ;выход из обработчика прерываний
Нет смысла ставить SEI перед RETI, т.к RETI=RET+SEI.
Спойлер

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

ldi r17,0b11111111  ;основная программа зажигающая второй светодиод
out DDRB,r17

ldi r18,0b00000010
out portb,r18
Вот что должно было быть после метки reset! Тут же и настройка прерываний и стека, и режима энергосбережения, раз уж:

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

sleep               ;воткнул просто ради эксперемента
И то не совсем верно. Даже если и заснет, что будет после возврата из прерывания? Переход на следующую команду после sleep, а там что? Ничего, пустая флеш-память (0xFF). Результат - некорректный опкод и сброс контроллера. Должен быть обязательно хотя бы пустой цикл

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

LOOP:RJMP LOOP
Sleep можно в него запихнуть, если надо...
В общем общая структура такая:

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

0) .include, если нужны кроме описания конкретного контроллера
1) RJMP RESET (JMP для больших контроллеров)
2) векторы прерываний, если нужны, т.е. таблица переходов JMP\RJMP, если обработчик помещается, можно не переходить и писать его прямо тут
3) конец векторов прерываний
---------------------------------
далее в произвольном порядке:
а) метка reset и все что касается инициализации, там же главный цикл программы (например пустой)
б) процедуры прерываний
в) остальные процедуры
г) остальные include, если исходник из нескольких частей.
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Реклама
sashavir
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Вт дек 30, 2014 21:35:51

Re: ATmega8A учусь использовать прерывания

Сообщение sashavir »

Engineer_Keen, НАПАЛМ Огромное спасибо за расшифровку и что показали, что почитать, изучаю... После Ревича (не в обиду ему :) ), что-то совсем каша, по Вашим ссылкам материал понятней разъяснен, да и в обучалке статейка хорошая...
Реклама
sashavir
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Вт дек 30, 2014 21:35:51

Re: ATmega8A учусь использовать прерывания

Сообщение sashavir »

Я опять к Вам друзья, вроде простые вещи, а как застопаришься на одном и ни туда и ни сюда... Работаю в отладчике atmel studio 6.2 может просто не совсем правильно пользуюсь им, а может ошибка в программе, я уж не знаю... Но суть в следующем, не работает так как я хочу прерывание, нажимаю start debugging and break и по F11 прокручиваю всю программу до зацикливания в метке M1, потом добавляю руками в IO View бит RXC, что должно вызвать по логике прерывание и перепрыгнуть на метку USART_RXC, потом выйти и вернуться к моему циклу, но ничего не происходит, тупо бит по нажатию F11 пропадает и прыжка не происходит, т.е. просто продолжает работать цикл. Постарался подробно описать, помогите понять, что делаю не так, уже часа два сижу :))

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

.include "m8adef.inc"      ;хотя, как я понял эта запись в 6-ой студии, как собаке пятая нога, он его похоже тянет автоматом
;= Start macro.inc ==============

; Тут будут макросы, потом.

;= End macro.inc ================


; RAM =========
                  .DSEG                 ; Сегмент ОЗУ


; FLASH =======
                  .CSEG                
rjmp RESET ; Reset Handler
nop ;rjmp EXT_INT0 ; IRQ0 Handler
nop ;rjmp EXT_INT1 ; IRQ1 Handler
nop ;rjmp TIM2_COMP ; Timer2 Compare Handler
nop ;rjmp TIM2_OVF ; Timer2 Overflow Handler
nop ;rjmp TIM1_CAPT ; Timer1 Capture Handler
nop ;rjmp TIM1_COMPA ; Timer1 CompareA Handler
nop ;rjmp TIM1_COMPB ; Timer1 CompareB Handler
nop ;rjmp TIM1_OVF ; Timer1 Overflow Handler
nop ;rjmp TIM0_OVF ; Timer0 Overflow Handler
nop ;rjmp SPI_STC ; SPI Transfer Complete Handler
rjmp USART_RXC ; USART RX Complete Handler
nop ;rjmp USART_UDRE ; UDR Empty Handler
nop ;rjmp USART_TXC ; USART TX Complete Handler
nop ;rjmp ADC ; ADC Conversion Complete Handler
nop ;rjmp EE_RDY ; EEPROM Ready Handler
nop ;rjmp ANA_COMP ; Analog Comparator Handler
nop ;rjmp TWSI ; Two-wire Serial Interface Handler
nop ;rjmp SPM_RDY ; Store Program Memory Ready Handler

;Тут простите за такую корявую таблицу, я знаю, что запись кривая, просто выдрал из даташита и на скорую руку поправил,
;адресацию вроде сохранил, использовал разные способы представления таблицы, в том числе с абсолютной адресацией и c
;метками один черт, все равно не работает так, как я себе это представляю... 

RESET: ldi r16,high(RAMEND) ;инициализация стека
       out SPH,r16
       ldi r16,low(RAMEND)
       out SPL,r16
       sei                  ;разрешить прерывания

	   LDI r17,(1<<RXCIE)   ;это взято с уроков http://easyelectronics.ru/, смысл в слудующем, чтобы при ручном вводе
	   OUT UCSRB,r17        ;в отладчике "atmel studio 6.2" бита RXC срабатовало прерывание и осуществлялся прыжок на 
	                        ;на метку USART_RXC: потом выход с прерывация и возврат к зацикленной программе м1

m1:    
       nop                  ;тут просто зацикленный кусок программы
       nop
	   nop
	   nop
	   rjmp m1

USART_RXC:                  ;метка на прерывание
       nop
	   nop
	   nop

       reti                 ;выход из прерывания и возвращение к адресу прерванного прерывание, если опять же я правильно
	                        ;понял работу оператора reti    
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: ATmega8A учусь использовать прерывания

Сообщение Engineer_Keen »

sashavir писал(а):ничего не происходит, тупо бит по нажатию F11 пропадает и прыжка не происходит, т.е. просто продолжает работать цикл.
Студия 4.17. Все работает как надо, в прерывание заходит, даже наоборот бит всегда остается взведен (чтобы убрался, надо UDR считать в прерывании) :dont_know:
Или глюк 6й студии, или вы что-то не так нажимаете...
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
sashavir
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Вт дек 30, 2014 21:35:51

Re: ATmega8A учусь использовать прерывания

Сообщение sashavir »

Да, действительно в студии 4.14 все отлично работает... Что за ерунда, не понимаю... А в 6.20 нифига, просто не реагирует на этот бит отладчик...
Вот тебе и выражение "Новое, враг надежного"...
А в 4.17 уже есть ATmega8a или тоже только ATmega8, я так понимаю там отличия только в тактовой частоте и все?
sashavir
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Вт дек 30, 2014 21:35:51

Re: ATmega8A учусь использовать прерывания

Сообщение sashavir »

Подскажите, как вы боритесь с дребезжанием кнопки, вроде подтягивающий резистр воткнул на 10К, а все равно прыжок, то через одну лампочку, то через 3 :)) Фильтр сделать не могу, по причине банального отсутствия конденсаторов (временно).
Может я в коде неправильно что делаю...
Вот программа
Спойлер

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

.include "c:\avr\project\m8adef.inc"

.def temp=r16
.def temp1=r17
;= Start macro.inc ==============


;= End macro.inc ================


; RAM =========
                  .DSEG          


; FLASH =======
                  .CSEG                
		 .ORG 0        ; (RESET) 
         RJMP   Reset
         .ORG INT0addr
         RJMP    button   ; (INT0) External Interrupt Request 0
         .ORG INT1addr
         RETI             ; (INT1) External Interrupt Request 1
         .ORG OC2addr
         RETI		      ; (TIMER2 COMP) Timer/Counter2 Compare Match
         .ORG OVF2addr
         RETI             ; (TIMER2 OVF) Timer/Counter2 Overflow
         .ORG ICP1addr
         RETI		      ; (TIMER1 CAPT) Timer/Counter1 Capture Event
         .ORG OC1Aaddr
         RETI             ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
         .ORG OC1Baddr
         RETI             ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
         .ORG OVF1addr
         RETI             ; (TIMER1 OVF) Timer/Counter1 Overflow
         .ORG OVF0addr
         RETI             ; (TIMER0 OVF) Timer/Counter0 Overflow
         .ORG SPIaddr
         RETI             ; (SPI,STC) Serial Transfer Complete
         .ORG URXCaddr
         RETI             ; (USART,RXC) USART, Rx Complete
         .ORG UDREaddr
         RETI             ; (USART,UDRE) USART Data Register Empty
         .ORG UTXCaddr
         RETI             ; (USART,TXC) USART, Tx Complete
         .ORG ADCCaddr
         RETI		      ; (ADC) ADC Conversion Complete
         .ORG ERDYaddr
         RETI             ; (EE_RDY) EEPROM Ready
         .ORG ACIaddr
         RETI             ; (ANA_COMP) Analog Comparator
         .ORG TWIaddr
         RETI             ; (TWI) 2-wire Serial Interface
         .ORG SPMRaddr
         RETI             ; (SPM_RDY) Store Program Memory Ready

 
Reset:
         LDI  temp,Low(RAMEND)
	 OUT  SPL,temp
 
	 LDI  temp,High(RAMEND)
	 OUT  SPH,temp
 
	 SEI


	 LDI  temp,3
	 OUT  MCUCR,temp

	
	 LDI  temp,(1<<INT0)
	 OUT  GICR,temp

	 LDI  temp,0xFF
	 OUT  DDRB,temp

Start:
         LDI  temp,0x01
         OUT  PortB,temp
 
M1:
         rjmp m1	 

button:
         CPI  temp,0x80
	 BREQ m2

     LSL  temp
	 OUT  PortB,temp
     
	 LDI  temp1,0
Delay:
         DEC  temp1
         BRNE Delay

Delay1:
         DEC  temp1
         BRNE Delay1

Delay2:
         DEC  temp1
         BRNE Delay2

Delay3:
     DEC  temp1
     BRNE Delay3

Delay4:
     DEC  temp1
     BRNE Delay4

Delay5:
     DEC  temp1
     BRNE Delay5

Delay6:
     DEC  temp1
     BRNE Delay6

Delay7:
     DEC  temp1
     BRNE Delay7

Delay8:
     DEC  temp1
     BRNE Delay8

Delay9:
     DEC  temp1
     BRNE Delay9

Delay10:
     DEC  temp1
     BRNE Delay10     ;тут я пробовал побороть программно, не помогло

	 RETI

 M2:
         LDI  temp,0x01
         OUT  PortB,temp
	 BCLR 1


	 RETI

; EEPROM ======
                  .ESEG                ;EEPROM
Последний раз редактировалось sashavir Ср янв 21, 2015 08:02:48, всего редактировалось 1 раз.
sashavir
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Вт дек 30, 2014 21:35:51

Re: ATmega8A учусь использовать прерывания

Сообщение sashavir »

Интересные глюки вываливаются, справился вроде программной задержкой, но метод конечно, как стрельба из дробовика по воробьям, да еще и крайне ненадежный, дребезжание плавает в зависимости от времени нажатия, а если еще нажимать быстро, то вообще труба... Буду изучать вопрос далее...

1 MHz
Спойлер

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

.include "c:\avr\project\m8adef.inc"

.def temp=r16
.def temp1=r17
.def temp2=r18
.def temp3=r19

;= Start macro.inc ==============


;= End macro.inc ================


; RAM =========
                  .DSEG          


; FLASH =======
                  .CSEG                
		 .ORG 0        ; (RESET) 
         RJMP   Reset
         .ORG INT0addr
         RJMP    button   ; (INT0) External Interrupt Request 0
         .ORG INT1addr
         RETI             ; (INT1) External Interrupt Request 1
         .ORG OC2addr
         RETI		      ; (TIMER2 COMP) Timer/Counter2 Compare Match
         .ORG OVF2addr
         RETI             ; (TIMER2 OVF) Timer/Counter2 Overflow
         .ORG ICP1addr
         RETI		      ; (TIMER1 CAPT) Timer/Counter1 Capture Event
         .ORG OC1Aaddr
         RETI             ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
         .ORG OC1Baddr
         RETI             ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
         .ORG OVF1addr
         RETI             ; (TIMER1 OVF) Timer/Counter1 Overflow
         .ORG OVF0addr
         RETI             ; (TIMER0 OVF) Timer/Counter0 Overflow
         .ORG SPIaddr
         RETI             ; (SPI,STC) Serial Transfer Complete
         .ORG URXCaddr
         RETI             ; (USART,RXC) USART, Rx Complete
         .ORG UDREaddr
         RETI             ; (USART,UDRE) USART Data Register Empty
         .ORG UTXCaddr
         RETI             ; (USART,TXC) USART, Tx Complete
         .ORG ADCCaddr
         RETI		      ; (ADC) ADC Conversion Complete
         .ORG ERDYaddr
         RETI             ; (EE_RDY) EEPROM Ready
         .ORG ACIaddr
         RETI             ; (ANA_COMP) Analog Comparator
         .ORG TWIaddr
         RETI             ; (TWI) 2-wire Serial Interface
         .ORG SPMRaddr
         RETI             ; (SPM_RDY) Store Program Memory Ready

 
Reset:
     LDI  temp,Low(RAMEND)
	 OUT  SPL,temp
 
	 LDI  temp,High(RAMEND)
	 OUT  SPH,temp
 
	 SEI


	 LDI  temp,3
	 OUT  MCUCR,temp

	
	 LDI  temp,(1<<INT0)
	 OUT  GICR,temp

	 LDI  temp,0xFF
	 OUT  DDRB,temp

Start:
     LDI  temp,0x01
     OUT  PortB,temp
 
M1:
     rjmp m1	 

button:
     CPI  temp,0x80
	 BREQ m2

     LSL  temp
	 OUT  PortB,temp
     
	 LDI  temp1,0
     LDI  temp2,0
	 LDI  temp3,4

Delay:
        
     DEC  temp1
     BRNE Delay

	 DEC  temp2
	 BRNE Delay

	 DEC  temp3
	 BRNE Delay
 
	 RETI

 M2:
     LDI  temp,0x01
     OUT  PortB,temp
	 BCLR 1


	 RETI

; EEPROM ======
                  .ESEG                ;EEPROM
akl
Друг Кота
Сообщения: 4445
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ATmega8A учусь использовать прерывания

Сообщение akl »

А так,в предположении, что кнопка стоит между общим и PD2
Спойлер

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

.include "m8def.inc"

.CSEG               
.ORG 0        ; (RESET)
	RJMP   Reset
.ORG INT0addr
button:
	CBI	PORTD,2
	SBI	DDRD,2		; заблокировать кнопку выводом 0

	IN	R16,PORTB
	ROL	R16
	BRCC	PC+2	
	SBR	R16,$01
	OUT	PORTB,R16
	SET
	RET

Reset:
	LDI  R16,Low(RAMEND)
    OUT  SPL,R16
 
    LDI  R16,High(RAMEND)
    OUT  SPH,R16
 
	SBI	DDRD,2
	SBI	PORTD,2
	CBI	DDRD,2

    LDI  R16,2
    OUT  MCUCR,R16

    LDI  R22,0xFF
    OUT  DDRB,R22
	LDI  R22,0x01
	OUT  PortB,R22
Start:
    LDI  R22,(1<<INT0)
    OUT  GICR,R22
    OUT  GIFR,R22
	CLT
    SEI
M1:
	BRTC	M1

	RCALL	DELAY
	CBI	DDRD,2
	SBI	PORTD,2		;разблокировать кнопку
WAIT:
	RCALL	DELAY
	SBIS	PIND,2	; кнопка ещё нажата
	RJMP	WAIT	; да, подождём
	RCALL	DELAY
	SBIS	PIND,2	; а может это был дредезг при отпускании?
	RJMP	WAIT	; да, это дребезг
	rjmp START   	; наконец-то кнопка отпущена
DELAY:
	LDI		XH,20
	CLR	XL

	SBIW	XL,1
	BRNE	PC-1

	RET
.EXIT
Ответить

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