Управление печкой(нагревателем)

Аватара пользователя
R9OFG
Сообщения: 1182
Зарегистрирован: 03 ноя 2019, 22:30
Позывной: R9OFG, ex R0AEK
Город: Новосибирск
Имя: Саша
Благодарил (а): 181 раз
Поблагодарили: 276 раз
Контактная информация:

Управление печкой(нагревателем)

Сообщение R9OFG » 01 сен 2023, 15:43

Парни, нужен коллективный разум...

Схема управления нагревателем 220v
1.jpg
через PC814 (датчик нуля - zero crossing) вызываем прерывание на МК, по этому прерыванию плюсуем счетчик проходов через ноль, задача пропускать n количество полуволн переменки, например одну, загоняю в симулятор (в железе тоже) и получаем вот такую фигню
2.jpg
желтый - переменка
красный - "обрезанная" переменка
синий - сигнал от датчика нуля
зеленый управляющий импульс от МК

вопрос - почему происходит обведенное красным, т.е. МК забывает пропустить один импульс при том, что прерывание сработало? И происходит это хаотично.

Oleg
Сообщения: 363
Зарегистрирован: 22 окт 2019, 16:06
Позывной: R2AVB
Город: Москва
Имя: Олег
Благодарил (а): 48 раз
Поблагодарили: 117 раз

Управление печкой(нагревателем)

Сообщение Oleg » 01 сен 2023, 16:17

Плата Arduino на Atmega2560? Судя по скриншоту, вроде бы она :-)

Если это она, то следующий вопрос. Вы управляющую программу написали как "скетч" (C++) для среды Arduino или же на чистом C в Atmel Studio?
Олег
R2AVB


Аватара пользователя
R9OFG
Сообщения: 1182
Зарегистрирован: 03 ноя 2019, 22:30
Позывной: R9OFG, ex R0AEK
Город: Новосибирск
Имя: Саша
Благодарил (а): 181 раз
Поблагодарили: 276 раз
Контактная информация:

Управление печкой(нагревателем)

Сообщение R9OFG » 01 сен 2023, 16:24

Oleg, верно она самая, в atmel studio

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

ISR(INT4_vect)
{
	if(zero_crossing_counter == 1)
	{
		//подаем импульс для включения плиты нагрева
		PORTD |= (1 << STOVE);
		_delay_us(100);
		PORTD &= ~(1 << STOVE);
	}
	
	zero_crossing_counter++;
	if(zero_crossing_counter > 1) zero_crossing_counter = 0;
}

Oleg
Сообщения: 363
Зарегистрирован: 22 окт 2019, 16:06
Позывной: R2AVB
Город: Москва
Имя: Олег
Благодарил (а): 48 раз
Поблагодарили: 117 раз

Управление печкой(нагревателем)

Сообщение Oleg » 01 сен 2023, 18:16

Хорошо, будем исходить из того, что на PE4 приходят импульсы без пропусков и с правильным уровнем.

Для начала я предлагаю проверить, что переменная zero_crossing_counter не изменяется за пределами подпрограммы обработки прерывания.

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

Аватара пользователя
R9OFG
Сообщения: 1182
Зарегистрирован: 03 ноя 2019, 22:30
Позывной: R9OFG, ex R0AEK
Город: Новосибирск
Имя: Саша
Благодарил (а): 181 раз
Поблагодарили: 276 раз
Контактная информация:

Управление печкой(нагревателем)

Сообщение R9OFG » 01 сен 2023, 18:44

Oleg писал(а):
01 сен 2023, 18:16
Для начала я предлагаю проверить, что переменная zero_crossing_counter не изменяется за пределами подпрограммы обработки прерывания.
Я уже и так сделал, завел объявление этой переменной в функцию с сохранением значения, тут явно она поменяться извне не может

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

void On_Power_Stove(int power)							//включение плиты нагрева с заданной мощностью
{
	//вариант 2: MOC3063 с ZERO-CROSSING, используем внешнее прерывание INT4 на пине PE4
	{
		static int zero_crossing_counter = 0; //счетчик ZERO CROSSING (проход через ноль)
		
		if(zero_crossing_counter == 1)
		{
			//подаем импульс для включения плиты нагрева
			PORTD |= (1 << STOVE);
			//_delay_us(300);
			PORTD &= ~(1 << STOVE);
		}
		
		zero_crossing_counter++;
		if(zero_crossing_counter > 1)
		{
			zero_crossing_counter = 0;
		}
	}
}

ISR(INT4_vect)
{
	On_Power_Stove(0);
}

Больше вообще ни чего не крутится даже в основном цикле while(1){}

Настройка внешнего прерывания на INT4 в main (пробовал настройку и по нарастанию и по смене 0/1)

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

//настройка внешнего прерывания INT4 - пин PE4
	{
		EIMSK = (1<<INT4);
		//настройка прерывания по спаду
		EICRB = (1<<ISC71)|(0<<ISC70);
	}
	
	//разрешаем глобальные прерывания
	sei();
На картинке ниже видно, что "забывчивость" сделать пропуск хаотичная
1.png
уже дым из ушей идет :mrgreen: ну не понимаю природу этого бага! Но есть же какая то причина!

Вот к примеру вообще уберем zero_crossing_counter, т.е. включаться будем по каждому переходу через ноль
2.png
"забывчивость" пропадает и все красиво...

Oleg
Сообщения: 363
Зарегистрирован: 22 окт 2019, 16:06
Позывной: R2AVB
Город: Москва
Имя: Олег
Благодарил (а): 48 раз
Поблагодарили: 117 раз

Управление печкой(нагревателем)

Сообщение Oleg » 01 сен 2023, 19:44

R9OFG писал(а):
01 сен 2023, 18:44
Вот к примеру вообще уберем zero_crossing_counter, т.е. включаться будем по каждому переходу через ноль

"забывчивость" пропадает и все красиво..
Так именно это я и имел в виду.
Теперь надо искать, где и что происходит с zero_crossing_counter. В принципе можно оставить её как глобальную переменную, ничего страшного. Надо разобраться.
Если возможно, дайте полный исходник (можно на e-mail). Может что-то в голову придет.
Олег
R2AVB

Аватара пользователя
R9OFG
Сообщения: 1182
Зарегистрирован: 03 ноя 2019, 22:30
Позывной: R9OFG, ex R0AEK
Город: Новосибирск
Имя: Саша
Благодарил (а): 181 раз
Поблагодарили: 276 раз
Контактная информация:

Управление печкой(нагревателем)

Сообщение R9OFG » 01 сен 2023, 20:18

Oleg, как всегда направили в нужную сторону! По ходу это был банальный эффект "дребезга", т.е. код инкремента переменной zero_crossing_counter в какой то момент делал лишнюю операцию, на сколько я это понял, перед инкрементом добавил задержку не превышающую длительность полуволны, теперь все красиво

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

void On_Power_Stove(int power)							//включение плиты нагрева с заданной мощностью
{
	//вариант 2: MOC3063 с ZERO-CROSSING, используем внешнее прерывание INT4 на пине PE4
	{
		static volatile int zero_crossing_counter = 0; //счетчик ZERO CROSSING (проход через ноль)
		
		if(zero_crossing_counter == 1)
		{
			//подаем импульс для включения плиты нагрева
			PORTD |= (1 << STOVE);
			PORTD &= ~(1 << STOVE);
		}
		
		_delay_us(100);
		zero_crossing_counter++;
		if(zero_crossing_counter > 1)
		{
			zero_crossing_counter = 0;
		}
	}
}
вот что добавил в коде выше _delay_us(100); правильней наверное будет не задержкой запрет на инкремент делать, а таймером в 8..9 мс

ниже картинка пропуска одной полу волны
3.png
а вот пропуск каждой второй полу волны
4.png

Oleg
Сообщения: 363
Зарегистрирован: 22 окт 2019, 16:06
Позывной: R2AVB
Город: Москва
Имя: Олег
Благодарил (а): 48 раз
Поблагодарили: 117 раз

Управление печкой(нагревателем)

Сообщение Oleg » 01 сен 2023, 21:08

Хорошо, что удалось всё исправить, но вот метод решения проблемы вызвал недоумение :D .
При чем здесь задержка - непонятно. Здесь какой-то баг.
Никак не может быть "лишней операции". Это же примитивный процессор с одним потоком. Конечно же, надо посмотреть промежуточный код на ассемблере, если будет время.

Ещё один момент. В программе обработки прерывания желательно делать всё быстро - заходим, ставим флажки, несколько быстрых действий с переменными - и всё. Остальное - в основном цикле программы. Ну это так - общий подход для более нагруженных систем.
Олег
R2AVB

Аватара пользователя
R9OFG
Сообщения: 1182
Зарегистрирован: 03 ноя 2019, 22:30
Позывной: R9OFG, ex R0AEK
Город: Новосибирск
Имя: Саша
Благодарил (а): 181 раз
Поблагодарили: 276 раз
Контактная информация:

Управление печкой(нагревателем)

Сообщение R9OFG » 02 сен 2023, 04:17

Oleg писал(а):
01 сен 2023, 21:08
При чем здесь задержка - непонятно. Здесь какой-то баг.
До конца еще не вникал в происходящее, но появилось предположение, что функция выполняется из прерывания иногда не один раз, а два, по подобию эффекта дребезга кнопки, в данном случае помогла задержка перед изменением счетчика проходов через ноль.

Повторюсь, это не конечное заключение, пока предположение!
Oleg писал(а):
01 сен 2023, 21:08
Ещё один момент. В программе обработки прерывания желательно делать всё быстро - заходим, ставим флажки, несколько быстрых действий с переменными - и всё. Остальное - в основном цикле программы. Ну это так - общий подход для более нагруженных систем.
Этот момент всегда в голове!

Аватара пользователя
R9OFG
Сообщения: 1182
Зарегистрирован: 03 ноя 2019, 22:30
Позывной: R9OFG, ex R0AEK
Город: Новосибирск
Имя: Саша
Благодарил (а): 181 раз
Поблагодарили: 276 раз
Контактная информация:

Управление печкой(нагревателем)

Сообщение R9OFG » 10 сен 2023, 08:50

Oleg, появилось время по разбираться, нашел свой косяк, неправильно было инициализировано прерывание INT4

было

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

//настройка внешнего прерывания INT4 - пин PE4
	{
		EIMSK = (1<<INT4);
		//настройка прерывания по спаду
		EICRB = (1<<ISC71)|(0<<ISC70);
	}
	
	//разрешаем глобальные прерывания
	sei();
глянув еще раз даташит, все сразу увидел
0.png
вот так будет правильно

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

//инициализация внешнего прерывания INT4
	{
		
		//настройка внешнего прерывания INT4 по спаду
		EICRB = (1<<ISC41)|(0<<ISC40);
		//внешнее прерывание INT4
		EIMSK |= (1<<INT4);
	}
в железе все четко, на картинке пропуск одной полуволны
photo_2023-09-10_12-49-08.jpg

Ответить

Вернуться в «Микроконтроллеры и программирование»