Страница 1 из 1

Длительность прерывания

Добавлено: 17 фев 2018, 19:54
Михаил_Я
Здравствуйте!

Программировать только учусь, поэтому не знаю гораздо больше, чем знаю.

Возникла необходимость в скетче для устройства точечной сварки. Энкодером задаётся длительность импульса (0.....3 сек.), после нажатия на кнопку контроллер должен выдавать в течении заданного времени меандр частотой 20.....30 кГц для работы инвертора.

С виду всё просто. Скетч для энкодера и таймера написал, но потом столкнулся с проблемой: меандр с такой частотой в функции loop получить невозможно из-за длительности выполнения как её самой, так и вложенных в неё других функций. Естественный выход - перенести генерацию меандра во внешнее прерывание от кнопки.

Проблема в том, что при работе прерывания функция loop не работает и отсчитывать время не может. С другой стороны - в прерывании не работают millis() и micros(). В итоге после нажатия на кнопку я получаю длящийся до бесконечности меандр.

Суть вопроса: можно ли программно ограничить длительность прерывания? Или, возможно, есть какие-то другие пути для решения стоящей задачи?
PS: контроллер Arduino. В наличии есть UNO, Nano, ProMini_16MHz и ProMini_8MHz. Все - китайские.

Re: Длительность прерывания

Добавлено: 17 фев 2018, 20:06
Эдуард
Здравствуйте!
Вы можете считать число периодов прерывания и таким образом вычислять время.
А почему бы вам не сформировать меандр с помощью аппаратного ШИМ?

Re: Длительность прерывания

Добавлено: 17 фев 2018, 20:19
Михаил_Я
В данном случае аппаратный ШИМ оставит на долю контроллера только таймер, который тоже легко реализовать аппаратно. Если не найду другого выхода, то так и прийдётся сделать. Но хотелось бы, всё же, попытаться реализовать это на контроллере.
А прерывание - внешнее, по нажатию кнопки, поэтому считать нечего. Я не очень представляю, чем определяется длительность аппаратного прерывания. Возможно ли, что что она (длительность) будет больше или равна периоду? Тогда, наверное, прерывания сольются в одно большое. Но где тогда "ловить" начала периодов, чтоб их сосчитать?

Re: Длительность прерывания

Добавлено: 17 фев 2018, 21:42
Эдуард
Я имел в виду аппаратный ШИМ микроконтроллера, т.е. ничего к плате добавлять не надо.

Re: Длительность прерывания

Добавлено: 17 фев 2018, 22:30
Михаил_Я
Точно! Я ж видел Ваш урок!!! Почему-то не связал одно с другим.
Пробовать буду в понедельник, т.к. всё на работе. Хотелось бы предварительно уточнить некоторые детали, а именно:
Можно ли установку параметров ШИМ оставить, как в Вашем примере (урок 37), в setup, а analogWrite запускать в loop? Либо перенести в loop всё?
И не помешает ли работе ШИМ отсчёт времени?
В любом случае - огромное спасибо за подсказку!!!

Re: Длительность прерывания

Добавлено: 17 фев 2018, 22:47
Эдуард
В уроке 37 есть соответствие ШИМ и таймеров. Если используете ШИМ, то соответствующий таймер трогать нельзя.
А по поводу задания режимов решайте сами. Можете устанавливать в loop перед каждым запуском. Циклически устанавливать нельзя. Но можете считывать значения регистров режима таймера, и если они ошибочны, то переустанавливать.

Re: Длительность прерывания

Добавлено: 20 фев 2018, 21:22
Михаил_Я
Здравствуйте, Эдуард!
Для моих целей в конце концов оказалось удобнее использовать функцию tone(),но и Вашу рекомендацию я проверил. В общем-то, всё работает нормально, но выявились некоторые тонкости. Первое - в 9-битном режиме почему-то не удалось получить точно 50% ШИМ - при аргументе 255 на выходе устанавливается 1 вместо меандра. При любых других значениях (из тех, что я пробовал) всё нормально. Вторая "непонятка" вызвала у меня и моих коллег изумление. Никто из нас не смог даже предположить что-либо внятное. Использовал этот скетч:

unsigned long previousMillis = 0;
boolean state;
boolean previnstate;
int setTim=3000;
#define switchPin 12
#define outPin 9

void setup()
{
pinMode(outPin,OUTPUT);
pinMode(switchPin,INPUT_PULLUP);
state = digitalRead(switchPin);
TCCR1A = TCCR1A & 0xe0 | 2;
TCCR1B = TCCR1B & 0xe0 | 0x09;
}

void loop() {
if ((state==LOW)&&(previnstate==HIGH))
{
analogWrite(9, 254);
previousMillis=millis();
}
if (millis()-previousMillis >= setTim)
{
analogWrite(9, 0);
state=previnstate;
}
}

Так вот - генерация запускалась (на заданное время) от взмаха (на расстоянии 10 - 20 см) руки! Плата, конечно, китайская (12 МГц), но не до такой же степени!
Говорю об этом просто как о забавном казусе, не ожидая разъяснений. Да их, думаю, и быть не может.

PS: в ближайшее время доделаю "железо" и выложу проект на форуме - вдруг кому-то пригодится?

Re: Длительность прерывания

Добавлено: 21 фев 2018, 12:46
Эдуард
Здравствуйте!
По поводу работы ШИМ при значении 255 написано в этой теме.

Re: Длительность прерывания

Добавлено: 09 мар 2018, 12:00
Михаил_Я
Здравствуйте, Эдуард!
Продолжаю работу над скетчем. Пришлось немало повозиться с выбором таймеров. Для запуска
инвертора (прерывание по кнопке) использовал timer0. Для регенерации дисплея и
считывания данных с энкодера - timer1. Хотя tone() использует timer2, в меандр почему-
то вклинивались импульсы 250мкс (период прерывания timer1). Для воспроизведения звука
это, может, и не очень важно, но в данном случае ведёт к нагреву силового трансформатора
и ключевого транзистора (трансформатор ещё и "пищит"). Поэтому для энкодера и дисплея
пришлось использовать timer2. Меандр получился идеальным, вот только из-за остановки
аппаратного прерывания во время работы инвертора на дисплее высвечивается случайный
разряд.
На функционал это, конечно, не влияет, но, как и любая недоработка - раздражает. Уж
лучше на это время индикатор просто гасить.
Для этого попытался в скетче (отправляю его Вам личным сообщением, поскольку вариант
неокончательный) во внешнем прерывании перед функцией tone() добавить строку для
установки разрядов в 1 (индикатор с общим катодом) с помощью прямой записи в регистр
порта:

PORTB = B00011111;

Индикатор гаснет при работе инвертора примерно в 50% случаев. Тогда попробовал гасить
каждый разряд:

disp.digit[0]= B0000000;
disp.digit[1]= B0000000;
disp.digit[2]= B0000000;

Результат аналогичен предыдущему. Попробовал также

disp.print(setTime, 0, 1);

- вообще безрезультатно.
Подскажите, пожалуйста - есть ли в Led4Digits возможность временно гасить индикатор
полностью? Или есть какие-то другие способы? Можно, конечно, погасить его с помощью
внешних ключей, но это - самый крайний вариант.

Re: Длительность прерывания

Добавлено: 10 мар 2018, 14:24
Михаил_Я
Здравствуйте!
Я понял, что без регенерации программно погасить дисплей невозможно. Сегодня выдалось свободное время и я собрал схему гашения на внешних ключах. Под руку подвернулись транзисторы TC144T, оказались идеальным вариантом. В их базовые цепи уже встроены нужные резисторы и напряжение насыщения всего 0,5В. В результате схема состоит из 5 транзисторов, 2 резисторов и 1 конденсатора.
Надеюсь, что на этой неделе будет возможность "добить" силовую часть. Если будет так, то к следующим выходным выложу на форуме полное описание.