Страница 1 из 2
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 15:43
R9OFG
Парни, нужен коллективный разум...
Схема управления нагревателем 220v
через PC814 (датчик нуля - zero crossing) вызываем прерывание на МК, по этому прерыванию плюсуем счетчик проходов через ноль, задача пропускать n количество полуволн переменки, например одну, загоняю в симулятор (в железе тоже) и получаем вот такую фигню
желтый - переменка
красный - "обрезанная" переменка
синий - сигнал от датчика нуля
зеленый управляющий импульс от МК
вопрос - почему происходит обведенное красным, т.е. МК забывает пропустить один импульс при том, что прерывание сработало? И происходит это хаотично.
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 16:17
Oleg
Плата Arduino на Atmega2560? Судя по скриншоту, вроде бы она
Если это она, то следующий вопрос. Вы управляющую программу написали как "скетч" (C++) для среды Arduino или же на чистом C в Atmel Studio?
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 16:24
R9OFG
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;
}
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 18:16
Oleg
Хорошо, будем исходить из того, что на PE4 приходят импульсы без пропусков и с правильным уровнем.
Для начала я предлагаю проверить, что переменная zero_crossing_counter не изменяется за пределами подпрограммы обработки прерывания.
Оставьте в подпрограмме только формирование импульса без всяких условий, то есть три строчки.
Тогда управляющие импульсы должны следовать в ответ на каждый импульс на входе внешнего прерывания.
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 18:44
R9OFG
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();
На картинке ниже видно, что "забывчивость" сделать пропуск хаотичная
уже дым из ушей идет

ну не понимаю природу этого бага! Но есть же какая то причина!
Вот к примеру вообще уберем zero_crossing_counter, т.е. включаться будем по каждому переходу через ноль
"забывчивость" пропадает и все красиво...
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 19:44
Oleg
R9OFG писал(а): ↑01 сен 2023, 18:44
Вот к примеру вообще уберем zero_crossing_counter, т.е. включаться будем по каждому переходу через ноль
"забывчивость" пропадает и все красиво..
Так именно это я и имел в виду.
Теперь надо искать, где и что происходит с zero_crossing_counter. В принципе можно оставить её как глобальную переменную, ничего страшного. Надо разобраться.
Если возможно, дайте полный исходник (можно на e-mail). Может что-то в голову придет.
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 20:18
R9OFG
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 мс
ниже картинка пропуска одной полу волны
а вот пропуск каждой второй полу волны
Управление печкой(нагревателем)
Добавлено: 01 сен 2023, 21:08
Oleg
Хорошо, что удалось всё исправить, но вот метод решения проблемы вызвал недоумение

.
При чем здесь задержка - непонятно. Здесь какой-то баг.
Никак не может быть "лишней операции". Это же примитивный процессор с одним потоком. Конечно же, надо посмотреть промежуточный код на ассемблере, если будет время.
Ещё один момент. В программе обработки прерывания желательно делать всё быстро - заходим, ставим флажки, несколько быстрых действий с переменными - и всё. Остальное - в основном цикле программы. Ну это так - общий подход для более нагруженных систем.
Управление печкой(нагревателем)
Добавлено: 02 сен 2023, 04:17
R9OFG
Oleg писал(а): ↑01 сен 2023, 21:08
При чем здесь задержка - непонятно. Здесь какой-то баг.
До конца еще не вникал в происходящее, но появилось предположение, что функция выполняется из прерывания иногда не один раз, а два, по подобию эффекта дребезга кнопки, в данном случае помогла задержка перед изменением счетчика проходов через ноль.
Повторюсь, это не конечное заключение, пока предположение!
Oleg писал(а): ↑01 сен 2023, 21:08
Ещё один момент. В программе обработки прерывания желательно делать всё быстро - заходим, ставим флажки, несколько быстрых действий с переменными - и всё. Остальное - в основном цикле программы. Ну это так - общий подход для более нагруженных систем.
Этот момент всегда в голове!
Управление печкой(нагревателем)
Добавлено: 10 сен 2023, 08:50
R9OFG
Oleg, появилось время по разбираться, нашел свой косяк, неправильно было инициализировано прерывание INT4
было
Код: Выделить всё
//настройка внешнего прерывания INT4 - пин PE4
{
EIMSK = (1<<INT4);
//настройка прерывания по спаду
EICRB = (1<<ISC71)|(0<<ISC70);
}
//разрешаем глобальные прерывания
sei();
глянув еще раз даташит, все сразу увидел
вот так будет правильно
Код: Выделить всё
//инициализация внешнего прерывания INT4
{
//настройка внешнего прерывания INT4 по спаду
EICRB = (1<<ISC41)|(0<<ISC40);
//внешнее прерывание INT4
EIMSK |= (1<<INT4);
}
в железе все четко, на картинке пропуск одной полуволны