Подскажите по прерываниям.

pmaster
Offline
Зарегистрирован: 23.05.2011

Пока не пришли ардуинки, набираюсь опыта в VBB3

так вот, или он глючит, или я уже не знаю. 

вот простейший пример

 


int pin = 13;
volatile int state = LOW;

void setup()
{
	pinMode(pin, OUTPUT);              
	attachInterrupt(0, blink, CHANGE); 
	ISR(INT0_vect);
}

void loop()
{
	digitalWrite(pin, state);         
}

void blink()
{
	state = !state;                   
}

и он в симуляторе не работает.
 

pmaster
Offline
Зарегистрирован: 23.05.2011

во первых ругается на attachInterrupt(0, blink, CHANGE);

и как ни странно на state = !state;  

Adessit
Adessit аватар
Offline
Зарегистрирован: 12.04.2011

Начните пример прерывания с кнопкой) можете затулить в блинк кнопку при нажатии на которорую меняется стате, а не просто сразу)

pmaster
Offline
Зарегистрирован: 23.05.2011

так это и есть этот пример. и в vbb3 он не работает. вот и хочу узнать, пользовался кто нить этим симулятором и небыло ли таких траблов?

 

Max
Offline
Зарегистрирован: 08.03.2011

 А там часом не описка во второй строчке, можно ли HIGH LOW хранить в переменной типа int, да еще потом к int применять логическую операцию отрицания в 18ой строке?

Max
Offline
Зарегистрирован: 08.03.2011

 Я был неправ. Переменная хранится, операция работает. И вообще код работает, проверил на Arduino Diecimila.

pmaster
Offline
Зарегистрирован: 23.05.2011

спасибо. значит эмуль глючный. 

Adessit
Adessit аватар
Offline
Зарегистрирован: 12.04.2011

Сегодня первый раз игрался с прерываниями, че-то мутно, но в финале добил.

Подтянул встроенные резисторы

digitalWrite(swpin1, HIGH);

Так как у меня теперь мега2560, то прерывание выбрал 2, на 21 контакте

attachInterrupt(2,switch1,CHANGE);

Функция switch1 на три нажатия состояния кнопки, на четвертом нажатии сброс на первое значение

void switch1()
{

buttonState = digitalRead(swpin1);
delayMicroseconds(30000000);
buttonPress++;

if (buttonPress == 3)
{ 
buttonPress = 0;
}
} 

 

Jeterex
Offline
Зарегистрирован: 26.08.2020

Доброго времени суток.
Есть такая конструкция: к ардуино uno подключен acDimmer со своей библиотекой (использует внешнее прерывание для детектора 0), I2C 7ми сегментный индикатор, и датчик DHT 11.

Проблема: периодически, без каких либо закономерностей, экран показывает чушь, иногда с датчика считывается 0.
После поиска на просторах интернета нашёл только одно объяснение: внешнее прерывание может мешать обмену данными по шинам.

Как с этим бороться?

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Использовать библиотеку без прерывания?

Jeterex
Offline
Зарегистрирован: 26.08.2020

Была мысль. Не получится. Там работает детектор нуля. Диммер переменка 220 вольт.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Тогда выход один - ищи закономерности. 

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Диммер без прерываний будет однозначно мигать.

Вероятнее всего ошибка в коде.

Не думаю что проблема в прерываниях.

В I2C нет требований к таймаутам, на которые могут повлиять прерывания.

Как вариант убрать прерывания и диммер, проверить все остальное на длительном тесте без диммера.

 

  

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Jeterex разделите во времени взаимодействие с устройствами.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Komandir пишет:

Jeterex разделите во времени взаимодействие с устройствами.

Да там особо не разделишь.

Каждые 10мс срабатывает прерывание по zero cross. Потом, в зависимости от мощности, в течение 10мс - прерывание по таймеру.

Но я не думаю, что прерывания влияют на обмен по I2C. Думаю, что где то ошибки в коде.

Когда делал WiFi диммеры для дома на ESP8266, я вынес диммер на Тини25 (программный слейв).

ESP8266 подключается к OpenHAB по mqtt, и управляет Тини25 по I2C.

К ESP8266, кроме Тини25, по I2C еще подключен PCF8574 и HDC1080.

Все это работает с 2017-го, и без единого сбоя. Просто работает и все.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

а кнопку на прерывании на ESP8266 кто-нибудь одолел?

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

ua6em пишет:

а кнопку на прерывании на ESP8266 кто-нибудь одолел?

а нужно?

Я по таймеру все кнопки и контакты обрабатываю.
С устранением дребезга,  по всем входам за раз, без циклов, параллельно.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

SergeiL пишет:

ua6em пишет:

а кнопку на прерывании на ESP8266 кто-нибудь одолел?

а нужно?

Я по таймеру все кнопки и контакты обрабатываю.
С устранением дребезга,  по всем входам за раз, без циклов, параллельно.

пример?

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

ua6em пишет:

пример?

Для 8-ми входов данные с входов портов загружаются в переменную uint8_t SWKEYS.

Каждый вход - определенный бит.

//------------------ ФУНКЦИЯ УСТР. ДРЕБЕЗГА --------------------------------------

// биты в байтах ниже взводятся обработчике дребезга, в прерывании от таймера и сбрасываются программой обработчиком событий  (здесь в Input_Process() )
uint8_t LATCH_ON   = 0;     // вход перешел в 1
uint8_t LATCH_OFF  = 0;     // вход вернулся в 0

void Input_CHK(void)         // вызывается каждые 10 мсек, лучше из таймера  главное понять суть флагов LATCH_ON и LATCH_OFF
{
    static uint8_t SLATCH = 0;            // текущее устоявшееся значение входов после устранения дребезга
    static uint8_t VCBIT0 = 0;            // Вертикальный счетчик бит 0
    static uint8_t VCBIT1 = 0;            // Вертикальный счетчик бит 1

    uint8_t        SWKEYS = 0;            // состояние вводов
    uint8_t        VCTEMP = 0;            // промежуточная переменная
    uint8_t        VCMASK = 0;            // Маска


    SWKEYS = Input_Read();         // загрузим текущие значения входов в переменную SWKEYS

    VCMASK = SWKEYS ^ SLATCH;                     // скинем счетчики для установившихся и неактивных значений
    VCBIT0 &= VCMASK;
    VCBIT1 &= VCMASK;
                                                  //  Каждая '1' в SLATCH представляет установившееся значение
    SLATCH ^= (VCTEMP = VCMASK & VCBIT0 & VCBIT1);

    if( VCTEMP )                                  // есть изменения входов, взведем флаги
    {
       LATCH_ON  |= VCTEMP &  SWKEYS;             // взведем биты нажатых кнопок и сработавших входов.
       LATCH_OFF |= VCTEMP & ~SWKEYS;             // Биты сбрасываются в обработчиках.
    }
    VCBIT1 ^= (VCMASK & VCBIT0);                   // инкрементируем счетчик.
    VCBIT0 ^= (VCMASK);
}

Примеры и подробное описание работы тут

 

 

Green
Offline
Зарегистрирован: 01.10.2015

Бред!

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Ну выглядит бредово :-) Было уже такое, тему еще в 2016 создавал на Амперке, не поняли.

А у меня работает надежно и быстро, код очень короткий, что очень неплохо для обработчика таймера. 

Да и все входы обрабатываются параллельно, без циклов.

Green
Offline
Зарегистрирован: 01.10.2015

Всё хотел спросить. Что такое "вертикальный счётчик"? И чем он отличается от диагонального?

Upper
Offline
Зарегистрирован: 23.06.2020

Так спросите у яндекса и получите ответ

https://www.embedders.org/blog/gdi/debouncing.html

Green
Offline
Зарегистрирован: 01.10.2015

Upper пишет:

Так спросите у яндекса и получите ответ


Просто лень.)
OK. Получается время дребезга = кол-ву счётчиков * период опроса? Удобно ли?
Вот по моему, всё тоже, но без заумностей. Период опроса любой, меньше длительности дребезга.
Сама длительность устанавливается через DEBOUNCE_TIME. 16/32 входа по желанию.

  static uint8_t deb_timer;
  static uint8_t valid;                 //последнее значение без дребезга
  static uint8_t old;

  uint8_t key = get_key();
  if (old != key) {                     //new
    old = key;
    deb_timer = DEBOUNCE_TIME;
  }
  else if (deb_timer && !--deb_timer && valid != key)
    valid = key;

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

каждые 10 миллисекунд опрашивать кнопку нажать которую могут раз сутки, как-то некомильфо, может так - отловили через прерывание нажатие, запустили процедуру обработки кнопки с опросом по таймеру каждые 10 миллисекунд, через минуту таймер погасили...

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Green пишет:
OK. Получается время дребезга = кол-ву счётчиков * период опроса? Удобно ли?

Вот по моему, всё тоже, но без заумностей. Период опроса любой, меньше длительности дребезга.
Сама длительность устанавливается через DEBOUNCE_TIME. 16/32 входа по желанию.

  static uint8_t deb_timer;
  static uint8_t valid;                 //последнее значение без дребезга
  static uint8_t old;

  uint8_t key = get_key();
  if (old != key) {                     //new
    old = key;
    deb_timer = DEBOUNCE_TIME;
  }
  else if (deb_timer && !--deb_timer && valid != key)
    valid = key;

На один вход, так даже по командам чуть короче получится. На AVR примерно команд на 10 короче думаю.

А если на два входа - уже предложенный мной вариант короче получится.

Как вы планируете написать на 16/32 входов?

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

ua6em пишет:

каждые 10 миллисекунд опрашивать кнопку нажать которую могут раз сутки, как-то некомильфо, может так - отловили через прерывание нажатие, запустили процедуру обработки кнопки с опросом по таймеру каждые 10 миллисекунд, через минуту таймер погасили...

Так да, все зависит от задачи и питания.

Если батарея - нужно спать. :-) 

Если сеть - все равно крутимся в цикле.

Green
Offline
Зарегистрирован: 01.10.2015

SergeiL пишет:

Как вы планируете написать на 16/32 входов?


Всё короче, да короче. У кого короче?)
Я не планирую - у меня работает!
uint8_t key = get_key(); - это разве не 8 входов?

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Green пишет:

Всё короче, да короче. У кого короче?)

Я не планирую - у меня работает!
uint8_t key = get_key(); - это разве не 8 входов?

Ну понятно  :-)

И время для них одно и то же.

Вот в этом то и разница, как минимум в 8 раз. :-)

Bruzzer
Offline
Зарегистрирован: 17.03.2020

Возможно Green считает, что для типичной кнопочной задачи, когда кнопки нажимаются пальцами и это не пианино, достаточно обрабатывать дребезг без конкретизации кнопки. Или, возможно, он таки не видит разницы в этих алгоритмах.

Green
Offline
Зарегистрирован: 01.10.2015

У меня типично кнопочная задача, которая с этими кнопками отлично справляется. Мы ведь о дребезге кнопок? И я не вижу никаких причин её усложнять.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Bruzzer пишет:

когда кнопки нажимаются пальцами и это не пианино...

это жеж электроника, нежнее надо, нежнее, прям как Лола Астанова )))

Green
Offline
Зарегистрирован: 01.10.2015

Bruzzer пишет:

Возможно Green считает, что для типичной кнопочной задачи, когда кнопки нажимаются пальцами и это не пианино, достаточно обрабатывать дребезг без конкретизации кнопки. Или, возможно, он таки не видит разницы в этих алгоритмах.


Я то вижу разницу. Этот алгоритм хорош в случаях когда много одновременных источников с дребезгом.
А вот где такое возможно - представить себе не могу. Наверно в пианино. (На пианино играл по молодости с подругой, и то однажды.) С обычными кнопками такой ситуации нет. В моём случае длительность дребезга задаёшь в удобоваримом виде (в мс) и не привязываешься к счётчику (на 3 или 4), который нужно менять в программе. Так же не привязываешься к периоду опроса, который может быть весьма экзотическим, 15625 us например.
Посмотрел листинг на трезвую голову - 8 байт разницы. Но это и так было видно.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

У меня и кнопки и все входы, одной функцией обрабатываются. Функция вызывается из таймера.

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

Куда уж проще то?

Ну и ситуация когда один вход на другой может повлиять, пусть даже и в теории, я бы у себя не стал делать.  Но это ИМХО.

Green
Offline
Зарегистрирован: 01.10.2015

SergeiL пишет:

Куда уж проще то?


А эта странная манера бессмысленные переменные, да ещё и заглавными.) Ужос! Или это для запутывания?
Какой один вход на другой? Вы бы разобрались сначала. И показали бы как такое возможно.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Green пишет:

А эта странная манера бессмысленные переменные, да ещё и заглавными.) Ужос! Или это для запутывания?

Так было у автора :-), написано же нашел в интернете. Меня это не напрягает ;-)

Мне понравилась компактность и оптимальность, я пользуюсь, доволен,  никому не навязываю.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Для ESP8266 пользую так, лучше пока не одолел:
(хотелось бы отлавливать и отпускание кнопки)
 

#pragma GCC optimize ("-Ofast")

#include <ArduinoJson.h>
#include <bearssl/bearssl.h>
#include <TypeConversion.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <Ticker.h>
#include <EEPROM.h>
#include <ESP8266WebServer.h>

#define USE_DHT
#ifdef USE_DHT
// Install "DHT sensor library" if you get an error
#include <DHT.h>
// Change D1 to the pin you've connected your sensor to
#define DHTPIN D1
// Set DHT11 or DHT22 accordingly
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
#endif

// код для дисплея
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
#define TFT_CS         D0
#define TFT_RST        D3
#define TFT_DC         D4
#define TFT_SCK        D5 //HSPI SCK
#define TFT_SDA        D7 //HSPI MOSI       
#define TFT_LED        D8 //HSPI CS

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);
Ticker tftTimer;
#define TFT_TIMEOUT   12000 // время зажигания дисплея

// кнопка активации дисплея на пине D6
#define interruptPin D6  //D0 (GPIO16) использовать нельзя
volatile uint8_t n = 1;
Ticker buttonTimer;
#define BUTTON_TIMEOUT 200

unsigned long tftCurrentMillis = 0;
unsigned long tftTimeOutMillis = TFT_TIMEOUT;

// New TFT OFF via millis()
void IRAM_ATTR tftcb(void) {
  // if (millis() - tftCurrentMillis > TFT_TIMEOUT)
  // millis при использовании библиотеки DHT.h не работает
  digitalWrite(TFT_LED, LOW);
  tftTimer.detach();
  n = 1;
}

void IRAM_ATTR test_key()
{ if (n == 1) {
    detachInterrupt(digitalPinToInterrupt(interruptPin));
    digitalWrite(TFT_LED, HIGH);
    buttonTimer.attach_ms(BUTTON_TIMEOUT, buttonFeed);
    tftTimer.attach_ms(TFT_TIMEOUT, tftcb); //запускаем таймер отображения TFT дисплея
    n = 0;
    // Serial.println("on");

  } else {
    detachInterrupt(digitalPinToInterrupt(interruptPin));
    n = 1;
    digitalWrite(TFT_LED, LOW);
    buttonTimer.attach_ms(BUTTON_TIMEOUT, buttonFeed);
    tftTimer.detach();
    // Serial.println("off");
  }
}

void buttonFeed(void) {
  buttonTimer.detach();
  attachInterrupt(digitalPinToInterrupt(interruptPin), test_key, FALLING);
}


void setup() {
  Serial.begin(115200);
  
   // инициализация дисплея
  pinMode(TFT_LED, OUTPUT);
  digitalWrite(TFT_LED, HIGH); 
  tft.initR(INITR_18GREENTAB);                 // Initialize ST7735R screen 
  tft.setTextWrap(false);
  tft.fillScreen(ST77XX_BLACK);
  tft.setRotation(1);
  tft.setCursor(4, 30);
  tft.setTextColor(ST77XX_GREEN);
  tft.setTextSize(2);
  tft.println("THE UA6EM");
  
  //инициализация кнопки
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin),test_key, FALLING);
}

void loop() {
// здесь может быть ваш блокирующий код
}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Green пишет:

Этот алгоритм хорош в случаях когда много одновременных источников с дребезгом.

А вот где такое возможно - представить себе не могу. Наверно в пианино. (На пианино играл по молодости с подругой, и то однажды.) С обычными кнопками такой ситуации нет.

Наоборот.

На клавишном инструменте, где дребезг больше 2-5 мс, играть невозможно.

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

Green
Offline
Зарегистрирован: 01.10.2015

Ну да. В любой теме/специфике есть свои нюансы. Причём ТАКИЕ, что обыватель даже и не предполагает о них.) И зачастую их СТОЛЬКО, что волосы дыбом становятся от этих нюансов.)

Green
Offline
Зарегистрирован: 01.10.2015

Посмотрел, увидел минусы. Ну объяснились бы, если не разделяете моё мнение.
Или же, минусы ставлю, а язык в жо.( Печально, что многое у нас так.(

Upper
Offline
Зарегистрирован: 23.06.2020

Green пишет:

А эта странная манера бессмысленные переменные, да ещё и заглавными.) Ужос! Или это для запутывания?

Какой один вход на другой? Вы бы разобрались сначала. И показали бы как такое возможно.

Что значит "бессмысленные переменные"? Если без них было бы понятнее, то покажите как. Если в именах переменных нет смысла, то на мой взгляд там все сокращения имеют смысл, вы действительно не видите?

"Какой один вход на другой?". Не верится, что вы сами не можете придумать пример. Представьте, что это домашнее задание. Например одна линия от кнопки в силу каких то причин стала антенной для наводок, и блокирует работу остальных кнопок. Если подключен датчик, то постоянный дребезг в случае его поломки тоже может быть вероятен.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018
Еще, если сработали по очереди два входа, с интервалом меньше чем DEBOUNCE_TIME.
Не узнать, какой сработал первым :-(
 
Green
Offline
Зарегистрирован: 01.10.2015

Upper пишет:

Что значит "бессмысленные переменные"?

Бессмысленные переменные - это переменные не отражающие их смысл. Да, могут быть локальные переменные, которые однозначно понятны и которые могут вообще иметь односимвольные значения. Тут же VCBIT0 или VCBIT1. Понятно, когда вы уже просекёте, вы уже можете сообразить что они значат... Или тот же SLATCH или VCTEMP - это бред, причём написанный заглавными буквами.
Конечно, вы можете выражать свои мысли как вам заблагорассудится, но все же, есть какие то правила. Или нет?
При том что вы хотите довести свои мысли до других.
А если нет, то почему вы пишете с заглавной строки и со знаками препинания? Или вам не насрать на собеседника?

 
Green
Offline
Зарегистрирован: 01.10.2015

SergeiL пишет:

Еще, если сработали по очереди два входа, с интервалом меньше чем DEBOUNCE_TIME.
Не узнать, какой сработал первым :-(
 


Да это пофигу. Пока не успокоитесь оба входа - не будет результата.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Green пишет:

Да это пофигу. Пока не успокоитесь оба входа - не будет результата.

Ну если вам "пофигу", то и не не буду ничего писать, именно по этому и не стал объяснять детали.

А если мне не "пофигу", то этот алгоритм мне уже не подходит. Например энкодер.

Green
Offline
Зарегистрирован: 01.10.2015

Блин! Ну смотрите. К примеру, 2 кнопки. С одной всё понятно. К примеру, нажали одну, затем вторую.
Есть нажатие одной. И пока есть дребезг второй состояние первой не изменится. Пока не устаканится состояние первой и второй - результата не будет.
Ну какие могут быть отрицательные моменты с двумя, тремя, н-ным количеством кнопок в этом случае? Ведь у вас не 100 рук! Максимум 3 кнопки. Ну, пусть, 5. И что? Дребезг одной кнопки удлиняет результат для всех. Но это же естественно. Если вы жмёте кучу кнопок, нужно же определиться сколько вы нажали. Не так ли?
 

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Green, Вы троллите или не понимаете?

Green
Offline
Зарегистрирован: 01.10.2015

Вы меня дураком хотите выставить? Тогда выставляйте. Подробно, без этих вот ЗАУМНЫХ высказываний.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Green пишет:

Вы меня дураком хотите выставить? Тогда выставляйте. Подробно, без этих вот ЗАУМНЫХ высказываний.

Да ни в коем случае, обидеть не хотел, просто вы как то очень категорично... :-(

sadman41
Offline
Зарегистрирован: 19.10.2016

Green, насколько я понял - в каждый бит числа читается бинарное представление входа. Потом этот бит переползает в одну переменную, вторую и третью. Т.е. если за три вызова состояние путешествующего бита не менялось, то считается, что вход зафиксировался. Одновременно через эти переменные ползут 8 входов. Считаю, что фиксация изменения вполне себе независимая. Т.е. вместо одно защитного интервала применяется три проверки через некоторые промежутки. Это просто другой способ. Хуже/лучше он - от ситуации зависит.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

sadman41 пишет:
Green, насколько я понял - в каждый бит числа читается бинарное представление входа. Потом этот бит переползает в одну переменную, вторую и третью. Т.е. если за три вызова состояние путешествующего бита не менялось, то считается, что вход зафиксировался. Одновременно через эти переменные ползут 8 входов. Считаю, что фиксация изменения вполне себе независимая. Т.е. вместо одно защитного интервала применяется три проверки через некоторые промежутки. Это просто другой способ. Хуже/лучше он - от ситуации зависит.

Все правильно, там по ссылке из  #18  (тут прямая ссылка) добавил еще один разряд вертикального счетчика, чтобы сделать проверку не на 4, а на 8 установившихся состояний. Все зависит от задачи.  По коду изменений - минимум, как говорят - найди 4 отличия.