Спящий режим для ATmega328P

Обсуждаем контроллеры компании Atmel.
Ответить
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Пн апр 05, 2010 22:04:20

Сообщение 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
Реклама
akl
Друг Кота
Сообщения: 4468
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение 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

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

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

Так в вашем камне
.equ SPL = 0x3d
.equ SPH = 0x3e
Зачем вы LDS/STS конструкцию используете?
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Пн апр 05, 2010 22:04:20

Сообщение 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 от любого из двух внешних прерываний
Реклама
Эиком - электронные компоненты и радиодетали
akl
Друг Кота
Сообщения: 4468
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение 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, которая введена специально для этого примера.
Реклама
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Пн апр 05, 2010 22:04:20

Сообщение radist108 »

Поменял. Но теперь, если я вторую команду SLEEP вставляю в произвольном месте основного цикла, то МК не засыпает, а продолжает свою работу.
Реклама
Ответить

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