attiny13 и PCINT0 в железе

Обсуждаем контроллеры компании Atmel.
Ответить
Прорезались зубы
Сообщения: 217
Зарегистрирован: Ср янв 11, 2012 11:55:51

Сообщение Land »

Собственно суть проблемы. К ногам тиньки 5 и 6 (РВ0 и РВ1) подключены две кнопки. Инициализированы прерывания PCINT0 и, в качестве источника прерываний, определены две ноги:
Спойлер

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

#define  BUTTON_LUX_MEMORY PB1				//вход определения нажатой кнопоки 1
#define  BUTTON_SYGNAL PB0				//вход определения нажатой кнопоки 0

GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания
PCMSK |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL);		//прерывания по входам PCINT0, PCINT1 (PB0, PB1)
GIMSK |= (1<<PCIE);					//разрешаем внешние прерывание
В обработчике прерывания определяю какая кнопка нажата и выполняю нужный код
Спойлер

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

ISR (PCINT0_vect) //обработка прерывания кнопки
{	
	GIMSK &= ~(1<<PCIE);		//запрещаем прерывания
	GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания
	TCCR0B = 0x00;		//останоавливаем таймер
	asm("wdr");		//сброс WDT
	PORTB |= (1<<LED_OUT_PIN);
	
	_delay_ms(500);	//пауза 500 мС
		
	if bit_is_clear (PINB,BUTTON_LUX_MEMORY)
	{
		MEM_value_LUX = read_adc(LUX_IN_PIN); eeprom_write_word(&LUX_MEM,MEM_value_LUX); 	//измеряем уровень освещенностиeeprom, записываем в 
	}
	
	if bit_is_clear (PINB,BUTTON_SYGNAL)
	{
		NUM_SYGNAL+=1; while (NUM_SYGNAL == 7) {NUM_SYGNAL=0x01;} eeprom_write_byte(&SYGNAL_MEM,NUM_SYGNAL);
			switch (NUM_SYGNAL)
			{
				case 1: SYGNAL=0xAA; break;
				case 2: SYGNAL=0xCC; break;
				case 3: SYGNAL=0xF0; break;
				case 4: SYGNAL=0x63; break;
				case 5: SYGNAL=0xD4; break;
				default: SYGNAL=0xE6; break;
			}
	}
	
	_delay_ms(500);
	PORTB &= ~(1<<LED_OUT_PIN);
	GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания	
	TCCR0B |= (1<<CS02);	// запуск таймера
в симулятора 7 студии все отрабатывает без вопросо. Но в железе у меня получается бесконечный цикл вызова прерыания, при этом виновником является вход РВ1 (BUTTON_LUX_MEMORY). Если програмно я не определяю этот вход как источник прерывания (PCMSK |= (1<<BUTTON_SYGNAL);), то кнопка на РВ0 (BUTTON_SYGNAL) работает без нареканий. Заходим в прерывание, выполняем нужное действие, возвращаемся в основной цикл.
Осциллограмма на РВ1 в норме, напряжение питания стоит, никаких дерганий уровня не видно.
Может у кого есть идеи, в какую сторону копать?
Реклама
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

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

   GIMSK &= ~(1<<PCIE);      //запрещаем прерывания
   GIFR |= (1<<INTF0) | (1<<PCIF);         // сброс флагов прерывания
Это - лишнее. Прерывания глобально и так запрещаются при входе в ISR, а флаг прерывания сбрасывается по выходу.
Вы нигде PB1 не дергаете случаем из программы? Ну вот, например, чему равно LED_OUT_PIN?
Ну и чтение АЦП и запись в EEPROM из ISR - очень плохая идея. В прерывании просто поднимайте флаг (переменная), что надо это сделать. А сам замер + запись делайте в основном коде. Там уже предварительно перед записью в EEPROM отключив временно глобально прерывания через cli(), а потом включив через sei().
Реклама
Прорезались зубы
Сообщения: 217
Зарегистрирован: Ср янв 11, 2012 11:55:51

Сообщение Land »

NStorm,

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

#define  LED_OUT_PIN PB3			//выход на светодиоды
что прерывания глобально запрещаются, а флаги сбрасываются -- знаю. Но вряд-ли эти строки загоняют контроллер в цикл с прерываниями. Но для красоты кода -- уберу.
Т.е. вы считаете, что в цикл падаю из-за чтения adc и записи в eeprom ? Ок, как рабочую версию приму, проверю. Спасибо
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

а флаг прерывания сбрасывается по выходу.
При входе в обработчик.
Реклама
Эиком - электронные компоненты и радиодетали
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18675
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Вообще-то обрабатывать прерывание одну секунду - это, имхо, явно не хорошо.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

В тиньке13 PCINT на что реагирует? На смену уровня или на уровень? Если на уровень, то так и не будете вылезать из прерывания, пока не сменится уровень на ноге.

Добавлено after 1 minute 30 seconds:
[uquote="ARV",url="/forum/viewtopic.php?p=3998445#p3998445"]Вообще-то обрабатывать прерывание одну секунду - это, имхо, явно не хорошо.[/uquote]
Если прерывание одно, то по фигу. Можно из него вообще не вылезать. Да даже если и не одно. Как в MSP430...
Реклама
Прорезались зубы
Сообщения: 217
Зарегистрирован: Ср янв 11, 2012 11:55:51

Сообщение Land »

[uquote="ARV",url="/forum/viewtopic.php?p=3998445#p3998445"]Вообще-то обрабатывать прерывание одну секунду - это, имхо, явно не хорошо.[/uquote]
аргументируйте, плз.

Добавлено after 2 minutes 24 seconds:
[uquote="parovoZZ",url="/forum/viewtopic.php?p=3998446#p3998446"]В тиньке13 PCINT на что реагирует? На смену уровня или на уровень? Если на уровень, то так и не будете вылезать из прерывания, пока не сменится уровень на ноге.[/uquote]
PCINT реагирует на любое изменение уровня на ноге.
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Land писал(а):[uquote="parovoZZ",url="/forum/viewtopic.php?p=3998446#p3998446"]В тиньке13 PCINT на что реагирует? На смену уровня или на уровень?[/uquote]
Только на смену.
Land писал(а):аргументируйте, плз.
В любом учебнике, во многих мануалах это написано - обработчик прерывания должен быть как можно более коротким. По разным причинам. Хотя бы потому что в это время у вас не будут выполняться другие прерывания, зато потом "выстрелят" отложенно и можете на этом поиметь грабли.
Land писал(а):Т.е. вы считаете, что в цикл падаю из-за чтения adc и записи в eeprom ? Ок, как рабочую версию приму, проверю. Спасибо
Это не может быть прямой причиной, но вот много всяких граблей бывает из-за долгой обработки прерывания. Лучше сразу привыкайте никогда так не делать, даже когда кажется, что в данном случае неважно.
Опять же в read_adc() и при работе с LUX_IN_PIN нигде не можете затрагивать скажем весь регистр PORTB? Случайно где-нибудь вместо R-M-W сделали присваивание может... Ну или приведите весь код в конце концов.
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

А я вот вижу сброс вачдога, сброс флага INT0....либо это сделано со знанием дела, но сия тайна великая есть, либо это откуда-то "нахапано" кусками. Пока я склоняюсь к версии
затрагивать скажем весь регистр PORTB?
В любом учебнике, во многих мануалах это написано - обработчик прерывания должен быть как можно более коротким.
Это кто-то придумал, а другие тупо скопипастили. Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...
Прорезались зубы
Сообщения: 217
Зарегистрирован: Ср янв 11, 2012 11:55:51

Сообщение Land »

[uquote="NStorm",url="/forum/viewtopic.php?p=3998472#p3998472"]Опять же в read_adc() и при работе с LUX_IN_PIN нигде не можете затрагивать скажем весь регистр PORTB? Случайно где-нибудь вместо R-M-W сделали присваивание может... Ну или приведите весь код в конце концов.[/uquote]
я же не случайно написал, что программное отключение генерации прерывания по РВ1 убирает проблему. Если бы где-то затрагивался весь регистр PORTB, то...

Добавлено after 3 minutes 53 seconds:
[uquote="parovoZZ",url="/forum/viewtopic.php?p=3998479#p3998479"]А я вот вижу сброс вачдога, сброс флага INT0....либо это сделано со знанием дела, но сия тайна великая есть, либо это откуда-то "нахапано" кусками. Пока я склоняюсь к версии
затрагивать скажем весь регистр PORTB?
[/uquote]
думаете wdr зацикливает в прерывании? Или сброс флага INT0 вызывает сбой? Само-собой, как у каждого, у меня есть свои куски кода и я пользуюсь копи-пастом... пока объем памяти позволяет. Если не позволяет -- перехожу на asm.
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

Глянул даташит и понял
PB1 (MISO/AIN1/OC0B/INT0/PCINT1)
По умолчанию INT0 сидит на прерывании по уровню. Если разрешить на INT0 прерывание, то, как я и говорил, из прерывания вылезать не будем при нуле на этом пине. Если обработчика вообще нет, то компилятор GCC выполнение кода по вектору уводит на ресет...
Самсусамыч

Сообщение Самсусамыч »

[uquote="Land",url="/forum/viewtopic.php?p=3998361#p3998361"]Собственно суть проблемы. К ногам тиньки 5 и 6 (РВ0 и РВ1) подключены две кнопки. Инициализированы прерывания PCINT0 и, в качестве источника прерываний, определены две ноги:[/uquote]
Попробуй… прошивка для тини13… кнопки на РВ0 и РВ1… светики на РВ3 и РВ4…
Фьюзы прошивать не нужно, тактируется на заводских установках (1,2 МГц).
Test_INT.hex
Нажал кнопку – светик загорелся. Нажал повторно – потух.
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

[uquote="Land",url="/forum/viewtopic.php?p=3998484#p3998484"]я же не случайно написал, что программное отключение генерации прерывания по РВ1 убирает проблему. Если бы где-то затрагивался весь регистр PORTB, то...[/uquote]
То что "то"? То нет. Вы можете остальные пины и не менять, программа по другим пинам будет как надо работать.
parovoZZ писал(а):Это кто-то придумал, а другие тупо скопипастили. Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...
Не совсем. Это стандартная практика. Никаких проблем нет вести свои флаги, их можно вполне расширить и не просто тупо копировать о срабатывании прерывания. Дело не в этом.
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

1 - кнопки это человекоинтерфейс. Реакция человека десятки, сотни миллисекунд. Реакция микроконтроллера, если кнопка повешана на прерывание - несколько тактов. Хочется спросить, куда вы так торопитесь, все равно не успеете.
На прерывание есть смысл вешать кнопки только в случае энергосбережения, спящего режима. Ещё в случае экономии ввода вывода. И то варианты.
2 - дребезг контактов.
3 - режим внешнего прерывания, по уровню или фронту.
Как здесь уже правильно подметили, могут быть неучтенные отложенные прерывания.
Вывод, разберитесь что такое дребезг контактов. Какие режимы внешнего прерывания, как правильно инициализировать внешние прерывания. И нужно ли вешать кнопки на внешние прерывания, если нет энергосбережения.
Контактная информация:
akl
Друг Кота
Сообщения: 4447
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Разрешать прерывания логическим ИЛИ не совсем хорошо. Как вариант, простое повторение состояния кнопок с жестким разрешением прерывания PCINT
Спойлер

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

.INCLUDE "tn13def.inc"

.CSEG

.ORG $000
	RJMP START
.ORG $002
	IN	R22,PINB
	RETI
;*************************************************
START:
	CBI	ACSR,ACD

	SBI	DDRB,2
	SBI	DDRB,3

	LDI R16, 0b00000011
	OUT PORTB, R16

	LDI R16,1<<PCINT1|1<<PCINT0
	OUT PCMSK, R16


	LDI R16,1<<PCIE ;PCIE: разрешение прерывания при смене состояния лапы
	OUT GIMSK, R16
	OUT	GIFR,R16

	LDI	R16,1<<SE
	OUT	MCUCR,R16

	SEI
WAIT_PCINT:
	SLEEP

	ANDI	R22,0b00000011
	LSL	R22
	LSL	R22
	ORI	R22,0b00000011
	OUT	PORTB,R22
	RJMP	WAIT_PCINT	
	
.EXIT
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

Дело не в этом.
А в чём же?
В прерывании засыпать нельзя, иначе можешь не проснуться. Но это только в AVR. В других МК позволяется всё.
Прорезались зубы
Сообщения: 217
Зарегистрирован: Ср янв 11, 2012 11:55:51

Сообщение Land »

[uquote="NStorm",url="/forum/viewtopic.php?p=3998597#p3998597"][uquote="Land",url="/forum/viewtopic.php?p=3998484#p3998484"]я же не случайно написал, что программное отключение генерации прерывания по РВ1 убирает проблему. Если бы где-то затрагивался весь регистр PORTB, то...[/uquote]
То что "то"? То нет. Вы можете остальные пины и не менять, программа по другим пинам будет как надо работать.[/uquote]
то, что если бы что-то писалось в PORB тупо в лоб, то это бы вызывало в том числе и прерывание по PB0. А здесь проблема в РВ1. POTB упоминается в коде 7 раз:

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

PORTB |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL); //входы кнопок (инициализация)
PORTB &= ~(1<<LED_OUT_PIN);
PORTB |= (1<<LED_OUT_PIN);
PORTB &= ~(1<<LED_OUT_PIN);
PORTB |= (1<<LED_OUT_PIN);
PORTB &= ~(1<<LED_OUT_PIN);
PORTB &= ~(1<<LED_OUT_PIN);
Что самое забавное, зацикливание происходит даже при простой инициализации входа PB1 в качестве источника прерывания. В обработчике ISR можно вообще все закомментить, относящееся к обработке этого пина. Если кому не лень в чужом коде колупаться, листинг под катом. Ткните меня носом. Только, умоляю, не в wdr :)
Спойлер

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

#define F_CPU 1200000UL  // 1.2 MHz

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/sfr_defs.h>
#include <avr/sleep.h>
#include <util/delay.h>

// Declare your global variables here

#define  LED_OUT_PIN PB3			//выход на светодиоды
#define  Ubat_IN_PIN (1<<MUX0)			//вход измерения напряжения батареи Ubat_IN_PIN ADC1D
#define  BUTTON_LUX_MEMORY PB0				//вход определения нажатой кнопоки 1
#define  BUTTON_SYGNAL PB1				//вход определения нажатой кнопоки 0
#define  LUX_IN_PIN (1<<MUX1)				//вход измерения уровня освещения	LUX_IN_PIN ADC2D
#define ADC_VREF_TYPE ((0<<REFS0) | (0<<ADLAR)) //рефернесное напряжение для АЦП -- напряжение питания


uint16_t LUX_MEM EEMEM;	//создаем метку адреса для значения освещенности в EEPROM
unsigned char SYGNAL_MEM EEMEM; //создаем метку адреса для сигнала мигания uint8_t

volatile unsigned char TIMER_CYCLE;		//счетчик циклов таймера для мигания
volatile unsigned char SYGNAL=0xAA;		//вид сигнала мигания по умолчанию
unsigned char NUM_SYGNAL=1;		//номер сигнала мигания
//unsigned char BUTTON;				//номер кнопки 1- запись уровня освещенности, 2 - изменение номера сигнала мигания
volatile unsigned char TIMER_SLEEP;		//счетчик таймера сна
unsigned char mask;				//локальная переменная маски

uint16_t value_LUX=0;	//уровень освещенности с датчика
//uint16_t value_BUTTON=0;	//нажатая кнопка
volatile uint16_t MEM_value_LUX; //сохраненное значение value_LUX

void key_func(void);

void sygnal_out(unsigned char);
unsigned char bat_level(void);
void LUX_level(void);
uint16_t read_adc(int);

// Pin change interrupt service routine



/*===================== ФУНКЦИИ =======================*/
void init(void)
{
	// Declare your local variables here

	// Port B initialization
	DDRB |= (1<<LED_OUT_PIN);		//выход 
	PORTB |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL); //входы кнопок
	
	// INT0: Off
	GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания
	PCMSK |= (1<<BUTTON_SYGNAL);//(1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL);		//прерывания по входам PCINT0, PCINT1 (PB0, PB1) 
	
	// Analog Comparator: Off
	//ADCSRA |= (1<<ADPS0) | (1<<ADPS1);
	ADCSRB &= ~(1<<ADTS2) & ~(1<<ADTS1) & ~(1<<ADTS0);
	ADMUX |= (1<<AIN0D) | (1<<AIN1D);		// Digital input buffer on AIN0: Off Digital input buffer on AIN1: Off
		
	// ADC enabled
	ADCSRA |= (1<<ADPS0) | (1<<ADPS1); // ADPS2=1, ADPS1=0,ADPS0=0 -- коэфф. делителя 8
	ADMUX &= ~(1<<REFS0);
	DIDR0 |= (1<<Ubat_IN_PIN) | (1<<LUX_IN_PIN);			// | (0<<ADC3D); //ADC10 -- VCC, ADC20 -- LUX
	
	// Timer/Counter 0 initialization	
	TCCR0A = 0x00;
	TIMSK0 |= (1<<TOIE0);	//прерывания по переполнению разрешены	
	TCNT0 = 0x00;
	OCR0A = 0x00;
	OCR0B = 0x00;
	
	//MCUCR |= (1<<SM1);		//режим POWER DOWN (1<<SE) Sleep Enable	
	// Watchdog timeout action: Reset + Interrupt
	asm("wdr");
	
	WDTCR |= (1<<WDCE) | (1<<WDE);
	WDTCR |= (1<<WDTIF) | (1<<WDTIE) | (1<<WDP0) | (1<<WDP3);		// | (1<<WDIE) разрешаем прерывание WDT, 8 сек.
	
	MEM_value_LUX = eeprom_read_word(&LUX_MEM);		//читаем из памяти сохраненное значение уровня освещенности
}
/*====================*/

uint16_t read_adc(int adc_input)
{
	TCCR0B = 0;		//останов таймера
	ADMUX= adc_input | ADC_VREF_TYPE;	
	_delay_us(10);	//  Delay needed for the stabilization of the ADC input voltage
	ADCSRA|=(1<<ADEN)|(1<<ADSC);	//Запускаем преобразование	
	while ((ADCSRA & (1<<ADIF))==0);	//Wait for the AD conversion to complete
	ADCSRA|=(1<<ADIF);			// сброс флага прерывания
	ADCSRA &= ~(1<<ADEN);		//останавливаем преобразование
	return ADCW;
}


void sleepy(void)
{
	cli();
	TCCR0B = 0x00;		//останоавливаем таймер
	
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);	//устанавливаем режим сна Power Down
//	set_sleep_mode(SLEEP_MODE_IDLE);																	
//	WDTCR |= (1<<WDTIE);		//		//запускаем WDT
	sleep_enable();
	sei();		// Globally enable interrupts					
}

unsigned char bat_level(void)
{
	//модуль измерения и индикации низкого напряжения батареи
	//PCMSK |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL);	//разрешаем прерывания
	TIMER_CYCLE = 0x00;		//счетчик циклов таймера
	uint16_t value_VCC=0;		//определяем локальные переменные	
	value_VCC = read_adc(Ubat_IN_PIN);	//измеряем напряжение батареи
	
	if (value_VCC < 0x239) {SYGNAL=0xA8;} else			//если напряжение ниже 1.6В (3.2В/2), то выставляем сигнал аларма, иначе
	{NUM_SYGNAL = eeprom_read_byte(&SYGNAL_MEM);	//читаем значение номера сигнала из EEPROM
		switch (NUM_SYGNAL)
		{
			case 1: SYGNAL=0xAA; break;
			case 2: SYGNAL=0xCC; break;
			case 3: SYGNAL=0xF0; break;
			case 4: SYGNAL=0x63; break;
			case 5: SYGNAL=0xD4; break;
			default: SYGNAL=0xE6; break;
		}
	}
	return SYGNAL;
}

void LUX_level(void)
{
	GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания
	GIMSK |= (1<<PCIE);					//разрешаем внешние прерывание 
	
	value_LUX = read_adc(LUX_IN_PIN);		//измеряем уровень освещенности
		
	asm("wdr");		//сброс WDT
				
	if (value_LUX  > MEM_value_LUX) 
		{TIMER_SLEEP = 0x80; PORTB &= ~(1<<LED_OUT_PIN); sleepy();	//TIMER_SLEEP = 0x80 !!!!!!!!!!!!!!!!
			while (TIMER_SLEEP)
				{
					sleep_cpu();	// спим
				}
			LUX_level();			//перепроверяем уровень освещенности
			
		}		//иначе -- спим 0x25 = 37 циклов таймера сна = 5 мин	
	//else {;}
	{mask=0x80; TIMER_SLEEP = 0xFF;}	// ,если темно, разрешаем прерывания, запускаем WDT	; sygnal_out(SYGNAL) TIMER_SLEEP = 0xFF !!!!!!!!!!!!!!!!
}

 
 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int main(void)
{
	init();
	
	LUX_level();
	
	bat_level();
		
	while (1)
	{
		TIFR0 |= (1<<TOV0);		//сброс флага переполнения TIMR0
		TCCR0B |= (1<<CS02);		//прескалер /256 1.2Mhz/256=1171.875 Hz Period 0.055 sec.
		
		TIMER_CYCLE = 0x00;		//счетчик циклов таймера
		sei();
		//while (TIMER_SLEEP != 0)
		while(1)
		{
			while (TIMER_CYCLE == 0)	//если TMER_CYLE = 0, выполняем вложенное
			{
				if (SYGNAL & mask)			//проверяем по маске бит выводимого сигнала логическое "или"
				{
					PORTB |= (1<<LED_OUT_PIN);	//если в результате 1, выставляем 1
				}
				else
				{
					PORTB &= ~(1<<LED_OUT_PIN);	//если в результате 0, выставляем 0
				}
				mask = mask >> 1; while  (mask == 0) mask=0x80;		//сдвинуть маску. обновить маску
					TIMER_CYCLE = 0x03;			//обновить счетчик таймера
					GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания
						GIMSK |= (1<<PCIE);					//разрешаем внешние прерывание
				if (TIMER_SLEEP == 0) LUX_level(); else{}
			}
		}
	}
}
// External Interrupt 0 service routine
ISR (PCINT0_vect) //обработка прерывания кнопки
{
	GIMSK &= ~(1<<PCIE);		//запрещаем прерывания
	GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания
	TCCR0B = 0x00;		//останоавливаем таймер
	asm("wdr");		//сброс WDT
	PORTB |= (1<<LED_OUT_PIN);
	_delay_ms(250);	//пауза 500 мС
	
	if bit_is_clear (PINB,BUTTON_LUX_MEMORY)
	{
		PORTB &= ~(1<<LED_OUT_PIN);
		//MEM_value_LUX = read_adc(LUX_IN_PIN);		//измеряем уровень освещенности
		//eeprom_write_word(&LUX_MEM,MEM_value_LUX); 	// записываем в память eeprom
	}
	
	if bit_is_clear (PINB,BUTTON_SYGNAL)
	{
		NUM_SYGNAL+=1; while (NUM_SYGNAL == 7) {NUM_SYGNAL=0x01;} eeprom_write_byte(&SYGNAL_MEM,NUM_SYGNAL);
		switch (NUM_SYGNAL)
		{
			case 1: SYGNAL=0xAA; break;
			case 2: SYGNAL=0xCC; break;
			case 3: SYGNAL=0xF0; break;
			case 4: SYGNAL=0x63; break;
			case 5: SYGNAL=0xD4; break;
			default: SYGNAL=0xE6; break;
		}
	}
	
	_delay_ms(500);
	PORTB &= ~(1<<LED_OUT_PIN);
	GIFR |= (1<<INTF0) | (1<<PCIF);			// сброс флагов прерывания
	TCCR0B |= (1<<CS02);	// запуск таймера
}

// Timer 0 overflow interrupt service routine
ISR (TIM0_OVF_vect)
{
	--TIMER_CYCLE;		// Декремент счетчика циклов таймера
}


ISR(WDT_vect)		// Watchdog timeout interrupt service routine// обработка прерыания WDT
{
	//cli();
	MCUSR &= ~(1<<WDRF);	//сбрасываем Watchdog Reset Flag
	asm("wdr");
	--TIMER_SLEEP;		//декремент счетчика циклов таймера сна
	WDTCR |= (1<<WDTIE); // запуск WDT
}
Добавлено after 5 minutes 8 seconds:
[uquote="akl",url="/forum/viewtopic.php?p=3998637#p3998637"]Разрешать прерывания логическим ИЛИ не совсем хорошо. ][/uquote]
вы говорите, что в регистр GINSK нельзя писать через "или"? Откровенно в первый раз об этом слышу. Ну и потом, для пина PB0 такая конструкция работает. Попробовать 6 ногу лучше пропаять?..
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

вы говорите, что в регистр GINSK нельзя писать через "или"?
Ну а зачем так делать? Сразу целиком писать весь регистр без его предварительного чтения. Ведь какие прерывания необходимы, а каие нет - известно. Тоже самое и регистрами флагов. Там всего 2 флага. Ну так и пиши туда сразу 0xFF. Зачем его читать???
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

[uquote="parovoZZ",url="/forum/viewtopic.php?p=3998479#p3998479"]Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...[/uquote]Старые, это какие?
в 13, 2313 и прочих, с которыми я работал можно и без прерываний флаги читать, программно сбоасывать... т.е. тело прерывания и разрешение прерывания совсем необязательны чтобы работать с флагами событий.
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

Старые, это какие?
Это 8-ми битки, кроме: xmega, серия DA, 0-ая и 1-ая серия. В трёх последних флаги в прерываниях не сбрасываются, либо сбрасываются после выполнения определённых условий. Появились два уровня приорита прерываний, карусель прерываний... Это некая коллаборация mega и xmega.

Добавлено after 3 minutes 16 seconds:
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=3998783#p3998783"][uquote="parovoZZ",url="/forum/viewtopic.php?p=3998479#p3998479"]Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...[/uquote]
в 13, 2313 и прочих, с которыми я работал можно и без прерываний флаги читать, программно сбоасывать... т.е. тело прерывания и разрешение прерывания совсем необязательны чтобы работать с флагами событий.[/uquote]
Флаги можно читать в любых МК. Они абсолютно независмы и отражают наступление какого-либо события. Речь о другом: выйти из сна в AVR можно только с помощью разрешённого прерывания, а его обработчик сбросит флаги автоматом.
Ответить

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