Страница 1 из 1
Спящий режим для ATmega328P
Добавлено: Чт авг 21, 2014 06:33:18
radist108
Приветствую всех форумчан!
Сколько ни сижу на форумах, сколько ни роюсь в даташитах и книжках, а спящий режим реализовать не могу. Обращаюсь к вам за помощью.
Нужно чтобы микросхема при включении как можно раньше входила в спящий режим. И при внешнем прерывании INT0 программа начинала свою работу.
Набросайте пожалуйста примерчик.
Вот мой неработающий код:
Код: Выделить всё
cseg
.org 0
.org 0x0000 jmp init // Вектор сброса
.org 0x0002 jmp INT_0 // Внешнее прерывание INT0
init:
.def temp = R16
;---Инициализация стека
Lds temp, RAMEND // Записать в регистр temp адрес последней ячейки ОЗУ
sts SPL, temp // записать в младший бит стека значение регистра temp
Lds temp, RAMEND // Записать в регистр temp адрес последней ячейки ОЗУ
sts SPH, temp // записать в старший бит стека значение регистра temp
;--- Инициализация прерываний
ldi temp, (1<<INT0) ; разрешение внешних прерываний INT0(PD2)
out EIMSK, temp
ldi temp, (0<<ISC01)|(0<<ISC00) ; прерывание INT0 уровню
sts EICRA, temp
sei // Глобальное разрешение прерываний
// спящий режим
ldi temp, (1<<SE) // Разрешение спящего режима. Режим Idle
sts MCUCR, temp
sleep // тут надо заснуть
main:
// тут цикл программы
rjmp main
INT_0:
// здесь надо проснуться
sei
ret
Re: Спящий режим для ATmega328P
Добавлено: Чт авг 21, 2014 08:22:21
akl
А так?
Спойлер
Код: Выделить всё
.include "m328def.inc"
.cseg
.org 0
.org 0x0000 jmp init // Вектор сброса
.org 0x0002 jmp INT_0 // Внешнее прерывание INT0
init:
.def temp = R16
;---Инициализация стека
Lds temp, RAMEND // Записать в регистр temp адрес последней ячейки ОЗУ
sts SPL, temp // записать в младший бит стека значение регистра temp
Lds temp, RAMEND // Записать в регистр temp адрес последней ячейки ОЗУ
sts SPH, temp // записать в старший бит стека значение регистра temp
;--- Инициализация прерываний
LDI R22,$04
OUT DDRD,R22
OUT PORTD,R22
CBI DDRD,2
ldi temp, (1<<INT0) ; разрешение внешних прерываний INT0(PD2)
out EIMSK, temp
ldi temp, (0<<ISC01)|(0<<ISC00) ; прерывание INT0 уровню
sts EICRA, temp
;sei // Глобальное разрешение прерываний
// спящий режим
ldi temp, (1<<SE) // Разрешение спящего режима. Режим Idle
sts MCUCR, temp
SER R22
STS EIFR,R22
CLT
SEI // Глобальное разрешение прерываний спящий режим
sleep // тут надо заснуть
main:
BRTC MAIN
CLT
// тут цикл программы
MAIN1:
rjmp main1
INT_0:
// здесь надо проснуться
; sei
SET
RET
Re: Спящий режим для ATmega328P
Добавлено: Чт авг 21, 2014 08:37:00
НАПАЛМ
Так в вашем камне
.equ SPL = 0x3d
.equ SPH = 0x3e
Зачем вы LDS/STS конструкцию используете?
Re: Спящий режим для ATmega328P
Добавлено: Чт авг 21, 2014 22:16:05
radist108
akl писал(а):А так?
Спойлер
Код: Выделить всё
.include "m328def.inc"
.cseg
.org 0
.org 0x0000 jmp init // Вектор сброса
.org 0x0002 jmp INT_0 // Внешнее прерывание INT0
init:
.def temp = R16
;---Инициализация стека
Lds temp, RAMEND // Записать в регистр temp адрес последней ячейки ОЗУ
sts SPL, temp // записать в младший бит стека значение регистра temp
Lds temp, RAMEND // Записать в регистр temp адрес последней ячейки ОЗУ
sts SPH, temp // записать в старший бит стека значение регистра temp
;--- Инициализация прерываний
LDI R22,$04
OUT DDRD,R22
OUT PORTD,R22
CBI DDRD,2
ldi temp, (1<<INT0) ; разрешение внешних прерываний INT0(PD2)
out EIMSK, temp
ldi temp, (0<<ISC01)|(0<<ISC00) ; прерывание INT0 уровню
sts EICRA, temp
;sei // Глобальное разрешение прерываний
// спящий режим
ldi temp, (1<<SE) // Разрешение спящего режима. Режим Idle
sts MCUCR, temp
SER R22
STS EIFR,R22
CLT
SEI // Глобальное разрешение прерываний спящий режим
sleep // тут надо заснуть
main:
BRTC MAIN
CLT
// тут цикл программы
MAIN1:
rjmp main1
INT_0:
// здесь надо проснуться
; sei
SET
RET
Работает! Спасибо
Расскажите, чего не хватало в моем коде? зачем дополнительный цикл main1? Какие здесь ключевые моменты?
P.S. Это точно спящий режим? или программа крутится в цикле? Потому как при удалении команды SLEEP в работе ничего не меняется.
И присыпается MR от любого из двух внешних прерываний
Re: Спящий режим для ATmega328P
Добавлено: Пт авг 22, 2014 05:16:11
akl
radist108 писал(а):Это точно спящий режим? или программа крутится в цикле?
Проверил в студии. Действительно, крутится в цикле, т.к. неправильно задан режим SLEEP IDLE. У mega328 для задания режимов сна отведён специальный регистр SMCR.
Код: Выделить всё
// спящий режим
ldi temp, (1<<SE) // Разрешение спящего режима. Режим Idle
OUT SMCR, temp
; OUT MCUCR, temp ; неправильно!!!!!!!!!
radist108 писал(а):...ключевые моменты
Командой SLEEP контроллер переводится в режим ожидания разрешённых прерываний. После обработки любого из них, контроллер обязательно выполняет следующую после SLEEP команду. Т.к. разрешённых прерываний может быть несколько, то программа должна знать что делать дальше, т.е. должны быть флаги- семафоры. В данном случае использован пользовательский флаг T регистра статуса SREG. В обработчике INT_0 он устанавливается и, при выходе из SLEEP, проверяется на предмет установки командой BRTC. Далее флаг Т очищается и программа зависает на метке MAIN1, которая введена специально для этого примера.
Re: Спящий режим для ATmega328P
Добавлено: Сб авг 23, 2014 23:08:24
radist108
Поменял. Но теперь, если я вторую команду SLEEP вставляю в произвольном месте основного цикла, то МК не засыпает, а продолжает свою работу.