Прерывание и устаревшее состояние порта

std
Offline
Зарегистрирован: 05.01.2012

Хало, all.

Я хочу простую вещь, передать по nRF24L01 нажатие одной из двух кнопок. Всё почти готово, и mega и передатор находятся в состоянии сна и просыпаются только когда клацают кнопку. Но они посылают неактуальную кнопку! То есть. вот допустим нажали кнопку 2. Приёмник принял, показал, типа, послали 2. Потом ещё раз нажали 2, приходит 2. Потом вдруг нажали 1, но приходит снова 2. Теперь, если нажать 1 или 2, придёт 1, т. к. её жали в прошлый раз. А потом если нажать ещё что-то, то опять придёт то что жали в прошлый раз, то есть передача запаздывает на одно состояние кнопки, на одно пробуждение. Куда копать? Вот код:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <avr\sleep.h>

#define btn1  !((PIND & B00100000)>>5)
#define btn2  !((PIND & B01000000)>>6)

boolean onflag=0;
byte data[1]={0};
unsigned long last_on=millis();

void waking(void){
}

void sleeping(void){
  onflag=0;
  Mirf.powerDown();
  delay(100);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  sleep_disable(); 
  Mirf.powerUp();
  last_on=millis();
}

void setup(){
  DDRD &=B10011111;
  PORTD |=B01100000;
  Mirf.spi=&MirfHardwareSpi;
  Mirf.cePin=9;
  Mirf.csnPin=10;
  Mirf.init();
  Mirf.setTADDR((byte *)"send1");
  Mirf.payload=1;
  Mirf.channel=5;
  Mirf.config();
  attachInterrupt(0,waking,LOW);
  sleeping();
}

void loop(){
  if(!onflag){
    onflag=1;
    data[0]=0;
    if(btn1) data[0]=1;
    if(btn2) data[0]=2;
    if(data[0]!=0){
      Mirf.send(data);
      while(Mirf.isSending()){}
      delay(10);
    }
  }
  if(millis()-last_on>=200) sleeping();
}

Возможные вопросы, отвечаю

1. чё тут делает MIRF? Она и спать не умеет?

Уже умеет, сон позаимствован из RF24. Чистоту эксперимента не нарушает, с RF24 всё одинаково, а мне синтаксис проще. Так что звиняйте.

2. ГДЕ detachInterrupt() или noInterrupts(), БЛДЖАД?

Нету. Если внутре sleeping() (перед засыпанием) добавить attachInterrup() из сетюпа, в конец прерывания detachInterrupt() - может навечно заснуть, точнее навечно и засыпает, после первого нажатия любой кнопки, до следующего сброса.

3. Зачем onflag?

Раньше эта переменная обозначала состояние несна, то есть была volatile. Изменять её снаружи прерывания или внутри - ни на что не влияет. Можно вообще выбросить.

4. Почему не заснуть сразу после посылания, зачем ждать 200 мс?

Пробовалось, ничего не дало. Поставлено в таймер на случай, если прерывание возникло, а кнопки не клацали, то есть посылать нечего. Чтобы не осталось в неспящем режиме.

5. Зачем прямая работа с портами?

Казалось, так будет меньше глюков, но нет, этой шаболде всё равно, PIND или digitalRead(). Влом было назад менять, думаю понятно что кнопки на проводах 5 и 6.

Мой вопрос простой, ЧО ЕМУ БЛИН НАДО? ОНО ДОЛЖНО РАБОТАТЬ ТАК КАК НАПИСАНО, проснулось - посмотрело какая кнопка жмётся - послало. Поставило флаг, запрещающий лупу повториться, чтобы кнопку было обязательно отпустить.

Вот схема кнопок:

Araris
Offline
Зарегистрирован: 09.11.2012

Может глупости напишу:

1 - а если опрашивать состояние кнопок из waking() ?

2 - а если после входа в waking() дать какую-то малую паузу, чтобы порты кнопок устоялись/обновились/перечитались, либо как-то их принудительно перечитать/обновить ?

std
Offline
Зарегистрирован: 05.01.2012

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

Я понимаю что в обработчик можно воткнуть нужное значение data[0], втыкаем INT1 и зашибись. А если кнопок 40?

UPD.

Это же продолжается, если разнести кнопки на разные прерывания, без диодов.

Pure f███ing magic.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Не вникал в суть, но  подозрительным показалось слово "LOW" вот здесь : attachInterrupt(0,waking,LOW);

Почему не RISING или FALLING ?
Это-же кнопка, а  нас интересуют только моменты смены её состояния.
Ну и как всегда  "свежее" по кнопкам: http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki?page=2#comment-152876

std
Offline
Зарегистрирован: 05.01.2012

FALLING ставилось, в этом случае МК не просыпается вообще.

У Меги8 не поддерживается?

std
Offline
Зарегистрирован: 05.01.2012

[SOLVED]

Хер его знает, братишки, победить не удалось. Пришлось в цикле передавать 5 раз, а на приёмнике завести массив, и актуальным значением считать его середину. Во всяком случае, сейчас оно работает именно так как замыслено.