Вопрос к знатокам прерываний На 4-х разрядный модуль дисплея TM1637 вывожу бегущую строку: byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0, _S,_t,_A,_r,_t}; disp.runningString(buf, sizeof(buf), 500); // время в мс Делаю прерывание по срабатыванию на нажатие кнопки attachInterrupt(0, buttonTick, FALLING); Все отрабатывает, но есть нюанс, который меня не устраивает: вызов функции запуска программы после нажатия кнопки происходит только по финалу прокрутки строки, а мне надо НЕМЕДЛЕННО. Как закончить выполнение текущей функции, кода, операции при возникновения прерывания. То же кстати касается и если прерывание возникло при выполнение какого-то кода. Прерывание будет зафиксировано, но использовано будет только в порядке очередности выполнения программы. Как запускать процессы немедленно? процессы длительные. например 1-2 минуты
функция или код должны постоянно проверять например некую переменную и если оная (в прерывании) была изменена - заканчивать свое выполнение. или если по-умному - делать код полностью асинхронным
как это сделать в функции runningString? простите, про асинхронным не понял честно сказать вас не понял. по прерыванию меняю значение некой переменной volatile byte f = 0; по прерыванию ставлю f = 1; вы про это, или подобное?
Псевдо - в обработчике меняете состояние флаг на 1 В функции постоянно в if проверяете состояние этого флага - если он 1 то ставите ему 0 и break; флагу надо 0 при выходе чтобы зайдя в бегущую функцию сразу не выйти. Там ещё есть способы...
спасибо, но тут то все понятно. а вот как прервать выполнение byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0, _S,_t,_A,_r,_t}; disp.runningString(buf, sizeof(buf), 500); // время в мс
код у меня - куча проб, вряд ли наглядно будет. набросал короткий вариант, для наглядности плата, ардуино нано Код (C++): #define CLK 5 #define DIO 4 #include "TM1637.h" TM1637 disp(CLK, DIO); volatile byte f = 0; int led = 13;//светодиод на плате void setup() { // подключили кнопку на D2 и GND pinMode(2, INPUT_PULLUP); \ // D2 это прерывание 0 // обработчик - функция buttonTick // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим attachInterrupt(0, buttonTick, FALLING); pinMode(led, OUTPUT);//светодиод на плате digitalWrite(led, LOW); // turn the LED off by making the voltage LOW disp.clear(); disp.brightness(7); // яркость минимум =0, стандарт=2, максимум=7) } void buttonTick() { f = 1; // + нажатие digitalWrite(led, HIGH); //зажигаю светодиод на плате } void loop() { if ( f==1){ //кнопка старт была нажата //запускает функцию таймера. ее не привожу для простоты }else{ // в режиме ожидания гоняет текст на дисплее byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0,_S,_t,_A,_r,_t }; disp.runningString(buf, sizeof(buf), 500); }//END IF кнопка старт была нажата }//end loop
чет не нашел в библиотеке TM1637.h функции runningstring. в гайверовской аналогичной есть. предположим что это то же самое попробуй вот это Код (C++): #define CLK 5 #define DIO 4 #include "TM1637.h" TM1637 disp(CLK, DIO); volatile byte f = 0; int led = 13;//сетодиод на плате void setup() { // подключили кнопку на D2 и GND pinMode(2, INPUT_PULLUP); \ // D2 это прерывание 0 // обработчик - функция buttonTick // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим attachInterrupt(0, buttonTick, FALLING); pinMode(led, OUTPUT);//светодиод на плате digitalWrite(led, LOW); // turn the LED off by making the voltage LOW disp.clear(); disp.brightness(7); // яркость минимум =0, стандарт=2, максимум=7) } void buttonTick() { f = 1; // + нажатие digitalWrite(led, HIGH); //зажигаю светодиод на плате } void loop() { if ( f==1){ //кнопка старт была нажата //запускает функцию таймера. ее не привожу для простоты }else{ // в режиме ожидания гоняет текст на дисплее byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0,_S,_t,_A,_r,_t }; runningString(buf, sizeof(buf), 500, &f); }//END IF кнопка старт была нажата }//end loop void runningString(uint8_t DispData[], byte amount, int delayMs, uint8_t* interrupt_flag) { uint8_t segm_data[amount + 8]; // оставляем место для 4х пустых слотов в начале и в конце for (byte i = 0; i < 4; i++) { // делаем первые 4 символа пустыми segm_data[i] = 0x00; } for (byte i = 0; i < amount; i++) { // далее забиваем тем что на входе (сам текст строки) segm_data[i + 4] = DispData[i]; } for (byte i = amount + 4; i < amount + 8; i++) { // и последние 4 тоже забиваем пустыми символами segm_data[i] = 0x00; } for (byte i = 0; i <= amount + 4; i++) { // выводим disp.displayByte(segm_data[i], segm_data[i + 1], segm_data[i + 2], segm_data[i + 3]); int i=delayMs; while(i>0){ delay(1); i--; if(*interrupt_flag){break;} } if(*interrupt_flag){break;} } } поправил - делать *interrupt_flag=0; не надо, т.к. это переменная f - она должна остаться 1 чтобы запустить таймер или че там. и конечно, в этой функции должно быть disp.displayByte
да, как оказалось, вроде гайверовская или на его основе: ####################################### # Syntax Coloring Map For GyverTM1637 ####################################### формально, вы просто вместо библиотеки выводите строку бегущую "своей" функцией, и при наличии прерывания останавливаете ее. Правильно? Спасибо, правда такой вариант я уже обдумывал, и, даже хотел в библиотеке подправить под себя. То есть, я ошибался в главном, и оказывается, что прерывания не могут ничего прерывать сами по себе, они могут только поймать сигнал (от кнопки например) и сформировать флаг, который можно использовать в своем коде. Прерывания отличаются от обычного чтения порта только тем, что делают проверку намного чаще и при любых условиях. Так? Спасибо большое за код и за труды
да, аналогично можно подправить эту функцию прямо в библиотеке. только там еще надо будет в файле .h тоже подправить добавив этот указатель на переменную-флаг если код асинхронный (то есть "без delay()), и нет необходимости отслеживать события с особо высокой скоростью и гарантированностью - то можно обойтись и без прерываний прерывания не остлеживают порт чаще или реже - они просто позволяют гарантированно фиксировать событие на этом проту (или в других местах, есть разные прерывания). но тут же отреагировать на событие можно только в пределах функции-обработчика, повлиять на другие функции можно опосредованно
спасибо. решил воспользоваться вашим кодом. в нем надо поправить небольшую ошибку. Вы повторно объявляете переменную i в этой строке: int ix=delayMs; Код (C++): #define CLK 5 #define DIO 4 #include "TM1637.h" TM1637 disp(CLK, DIO); volatile byte f = 0; int led = 13;//сетодиод на плате void setup() { // подключили кнопку на D2 и GND pinMode(2, INPUT_PULLUP); \ // D2 это прерывание 0 // обработчик - функция buttonTick // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим attachInterrupt(0, buttonTick, FALLING); pinMode(led, OUTPUT);//светодиод на плате digitalWrite(led, LOW); // turn the LED off by making the voltage LOW disp.clear(); disp.brightness(7); // яркость минимум =0, стандарт=2, максимум=7) } void buttonTick() { f = 1; // + нажатие digitalWrite(led, HIGH); //зажигаю светодиод на плате } void loop() { if ( f==1){ //кнопка старт была нажата disp.clear(); //запускает функцию таймера. ее не привожу для простоты }else{ // в режиме ожидания гоняет текст на дисплее byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0,_S,_t,_A,_r,_t }; runningString(buf, sizeof(buf), 500, &f); }//END IF кнопка старт была нажата }//end loop void runningString(uint8_t DispData[], byte amount, int delayMs, uint8_t* interrupt_flag) { uint8_t segm_data[amount + 8]; // оставляем место для 4х пустых слотов в начале и в конце for (byte i = 0; i < 4; i++) { // делаем первые 4 символа пустыми segm_data[i] = 0x00; } for (byte i = 0; i < amount; i++) { // далее забиваем тем что на входе (сам текст строки) segm_data[i + 4] = DispData[i]; } for (byte i = amount + 4; i < amount + 8; i++) { // и последние 4 тоже забиваем пустыми символами segm_data[i] = 0x00; } for (byte i = 0; i <= amount + 4; i++) { // выводим disp.displayByte(segm_data[i], segm_data[i + 1], segm_data[i + 2], segm_data[i + 3]); int ix=delayMs; while(ix>0){ delay(1); ix--; if(*interrupt_flag){break;} } if(*interrupt_flag){break;} } } Выше рабочий вариант, если несложно подправьте свой пост, а то кто-то скопирует, если неопытный, начнутся вопросы Ну и еще добавил очистку экрана, а то последнее что было на экране застывает. disp.clear(); честно говоря, не понял вашу мысль. как пользоваться disp.displayByte понятно, но к чему вы это, не понял, поясните, вдруг чего-то интересное упускаю disp.displayByte(0, _P);
там можно ваще вот так while(delayMs>0){ delayMs--; а нет так нельзя в этой функции, если б один раз надо было отсчитать тогда можно было бы про disp.displayByte к тому, что у меня там было просто displayByte как в библиотечной фенкции, потом исправил чтобы нормально сделать советую почитать про конечные автоматы http://wiki.amperka.ru/программирование:конечный-автомат