Вопрос касательно быстрой остановки счетчика прерываний
- Войдите на сайт для отправки комментариев
Здравствуйте.
Здесь уже не раз обсуждались счетчики, однако я не совсем понял один момент:
возьмем простой пример
volatile int a = 0; // переменная
int b = 500; // нужное число импульсов
pinMode(3,INPUT); // нужный пин
void setup()
{
pinMode(13,OUTPUT);
digitalWrite(13,1);
attachInterrupt(1, imp_detect, RISING); } void loop() { if (a >= b) { digitalWrite(13,0); a = 0; } } void imp_detect() { a++; }
тут вроде бы все просто и диод погаснет отсчитав нужное кол-во импульсов, ОДНАКО если код значительно больше и в тушке loop куча всего - учитывая это разве погаснет диод в нужное время ?
быть может проверку кол-ва и выключение диода можно как то переместить в функцию прерывания ?
Меня это интересует так как возникла необходимость написать программу для работы мотора, которая бы включала его при определенном событии и отключала бы при достижении заданного кол-ва пройденных оборотов, которые подсчитываются при помощи прерывания.
Код у меня получается довольно большой, а учитывая большую скорость оборотов мотора я боюсь прогадать
извините код коряво вставился
volatile int a = 0; // переменная int b = 500; // нужное число импульсов pinMode(3,INPUT); // нужный пин void setup() { pinMode(13,OUTPUT); digitalWrite(13,1); attachInterrupt(1, imp_detect, RISING); } void loop() { if (a >= b) { digitalWrite(13,0); a = 0; } } void imp_detect() { a++; }Для начала нужно понять, что "одновременно" и "в тот же момент" и "нужное время" - это исключительно человеческие фантазии. Оперируйте временем, в течении которого должно совершиться действие. Вполне может статься, что частота поступления импульсов меньше, чем частота прохождения loop().
И, да, дернуть за ногу вполне себе можно и в прерывании. Конечно это займет определенное время и часть импульсов будет утеряна. Чтобы уменьшить потерю - дергать за пин стоит напрямую через регистры.
И, да, дернуть за ногу вполне себе можно и в прерывании.
подскажите как это называется правильно (название команд) - я пробовал в теле прерывания использовать if и while но не получилось
Прерывание потому и называется прерыванием, потому что за время порядка микросекунды прерывает выполнение программы. Тут главное долго в нём не сидеть и выходить до того, как оно сработает снова. Все команды в прерывании работают штатно. От длины основной программы не зависит, но только если в основной программе на долго не запрещаются прерывания. Приведите пример программы которая не получилась и что конкретно не получилось?
И, да, дернуть за ногу вполне себе можно и в прерывании.
подскажите как это называется правильно (название команд) - я пробовал в теле прерывания использовать if и while но не получилось
В смысле не получилось? Должно получиться! Попробуйте b сделать константой, или именованной константой. А в теле обработчика поставьте условие if(a>b)PORTD=0b1000000;//включили7пин порта D.
...
Я не знаю что произошло, однако сегодня действительно получилось - буквально пару дней назад я пробовал по всякому подставлять IF в функцию прерывания (также пробовал и различные другие методы которые приходили в голову) но программа просто "зависала" после одного прохода, а сегодня бац и заработало.
не долго я радовался - дома на макетке все было норм но приехал на работу и подключил к бандуре и получил пшик.
проблема та же - мотор не останавливается в нужный момент.
пожалуйста посмотрите мой код - быть может я допустил нелепую ошибку:
#include <EEPROM.h> // библиотека для работы с памятью ардуинки #include <Wire.h> #include <LiquidCrystal_I2C.h> // Подключаем библиотеку индикатора и I2C LiquidCrystal_I2C lcd(0x27, 16,2); //настройка экрана #include <Keypad.h> // Подключаем библиотеку кнопок volatile int kol=0; // переменная для подсчета прерываний volatile int Lkol=3; // переменная для проверки фоторезистора volatile uint16_t datal; // переменные хранящие 3 изменяемые позиции volatile uint16_t datak; volatile uint16_t datat; // настройка матричной клавиатуры const byte ROWS = 4; // 4 строки const byte COLS = 4; // 4 столбца char keys[ROWS][COLS] = { {'1','4','7','*'}, {'2','5','8','0'}, {'3','6','9','#'}, {'A','B','C','D'} }; byte rowPins[ROWS] = {7,6, 5, 4}; byte colPins[COLS] = {11, 10, 9, 8}; Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); byte menu=0; // переменная определяющая какое из меню отобразить на экране boolean first=true; // функции для преобразования чисел и удобной записи в память void EEPROMWriteInt(int p_address, int p_value) { byte lowByte = ((p_value >> 0) & 0xFF); byte highByte = ((p_value >> 8) & 0xFF); EEPROM.write(p_address, lowByte); EEPROM.write(p_address + 1, highByte); } //This function will read a 2 byte integer from the eeprom at the specified address and address + 1 unsigned int EEPROMReadInt(int p_address) { byte lowByte = EEPROM.read(p_address); byte highByte = EEPROM.read(p_address + 1); return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00); } void setup() { datak=EEPROMReadInt(0); // присваиваем переменным данные из памяти datal=EEPROMReadInt(4); datat=EEPROMReadInt(8); lcd.init(); lcd.backlight();// Включаем подсветку дисплея Serial.begin(9600); pinMode(3,INPUT_PULLUP); // сюда пойдет счетчик pinMode(13,OUTPUT); // пин для вкл\выкл мотора digitalWrite(13,LOW); detachInterrupt(1); } void loop(){ // если фоторезистор перекрыт if (analogRead(0)<=datal){ Lkol=0; } // если фоторезистор опять открыт if (Lkol==0&&analogRead(0)>=datal){ Lkol=1; kol=0; lcd.clear(); //очистить дисплей attachInterrupt(1, blink, RISING); // запускаем прерывание для подсчета оборотов } // если фоторезистор перекрыт в первый раз то включаем мотор через определенное время if (Lkol==0){ delay(datat); digitalWrite(13,HIGH); } // построение простого меню где при нажатии на кнопки ABC -отображается на экране строка для ввода значения переменных, при нажатии на * происходит обнуление переменной, а при нажатии на D сохраняются изменения и отображаются основные показатели char key = keypad.getKey(); //опрос клавиатуры switch (key){ case ('A'): lcd.clear(); //очистить дисплей menu=1; lcd.setCursor(0, 0); lcd.print("Menu vibora "); lcd.setCursor(0, 1); lcd.print("kol-vo: "); lcd.setCursor(9, 1); lcd.print(datak); break; case ('B'): lcd.clear(); menu=2; lcd.setCursor(0, 0); lcd.print("Menu vibora "); lcd.setCursor(0, 1); lcd.print("secund: "); lcd.setCursor(9, 1); lcd.print(datat); break; case ('C'): lcd.clear(); menu=4; lcd.setCursor(0, 0); lcd.print("Menu vibora "); lcd.setCursor(0, 1); lcd.print("svet: "); lcd.setCursor(9, 1); lcd.print(datal); break; case ('D'): lcd.clear(); //очистить дисплей EEPROMWriteInt(0, datak); EEPROMWriteInt(4, datal); EEPROMWriteInt(8, datat); menu=0; break; } if(menu==1){ if(isDigit(key)){ datak = datak*10+key-48; lcd.setCursor(9, 1); lcd.print(datak); } } if(menu==1&&key=='*'){ datak=0; lcd.setCursor(9, 1); lcd.print(datak); lcd.setCursor(7, 1); lcd.print(" "); lcd.setCursor(10, 1); } if(menu==2){ if(isDigit(key)){ datat = datat*10+key-48; lcd.setCursor(9, 1); lcd.print(datat); } } if(menu==2&&key=='*'){ datat = 0; lcd.setCursor(9, 1); lcd.print(datat); lcd.setCursor(7, 1); lcd.print(" "); lcd.setCursor(10, 1); } if(menu==4){ if(isDigit(key)){ datal = datal*10+key-48; lcd.setCursor(9, 1); lcd.print(datal); } } if(menu==4&&key=='*'){ datal = 0; lcd.setCursor(9, 1); lcd.print(datal); lcd.setCursor(7, 1); lcd.print(" "); lcd.setCursor(10, 1); } if (menu==0){ lcd.setCursor(0, 0); lcd.print("Svet:" ); lcd.setCursor(5, 0); lcd.print(datal); lcd.setCursor(9, 0); lcd.print("L- " ); lcd.setCursor(12, 0); lcd.print(analogRead(0)); lcd.setCursor(0, 1); lcd.print("Shag:"); lcd.setCursor(5, 1); lcd.print(datak); lcd.setCursor(10, 1); lcd.print("T:"); lcd.setCursor(12, 1); lcd.print(datat); } } // собственно функция прерывания где происходит подсчет оборотов и остановка мотора void blink() { kol++; if (kol>=datak) { digitalWrite(13,LOW); menu=0; detachInterrupt(1); } }что собственно происходит не так как задумывалось - мотор зачастую останавливается в разное время.
ставлю я к примеру значение при котором должно произойти отключение равным 10 - но наглядно видно что кусок бумаги (а мотор крути валы что тянут бумагу) то проезжает 5 мм, то 15, то еще сколько то - и это при довольно таки низких оборотак мотора
если же повысить скорость мотора то бумага может уехать вообще на несколько см, хотя в теории скорость оборотов не должна влиять на то сколько пройдет этих оборотов до отключения мотора
вот как выглядет самодельный энкодер (датчик Sharp - дребезга нет)
В перрывании Вы используете menu, но не объявили её volatile.
Никто не знает, чему у Вас равна datak в момент работы с прерыванием, если недавно отработала строка 137 (datak = 0;), то условие в прерывании не выполнится никогда.
Вообще, код слшком велик и "расхристан" для поиска таких тонких ляпов. Такой огромный код Вы не отладите. Сделайте так:
1. Из кода выбросьте всё. При это всё означает ВСЁ.
2. Оставьте константные (просто присваиниваем) переменные datak и kol.
3. В setup включите Ваш двигатель и откройте прерывание.
Больше в коде не должно быть ничего, от слова совсем. Хотя, нет, можете вставить в loop печать в сериал значения kol, чтобы видеть, как она меняется при оборотах.
Добейтесь, чтобы Ваш двигатель останавливался и только потом вставляйте то, что получилось, в большой код.
до действительно про меню забыл, а про datak - там значение есть всегда отличное от 0, разве что кто то спец внесет изменение
datak - там значение есть всегда отличное от 0,
Если выполнится строка 137, то оно станет 0
В любом случаем, сделайте как я сказал. Если на простейшем коде не будет работать, ищем аппаратные проблемы (например, прерывание может вадисть в больших количествах при работе двигателя). А если будет работать надёжно, то смотрим на остальной код.
Только печатайте в loop свою kol, чтобы видеть как часто прерывания валятся.