чтение бита по прерыванию

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

iopq пишет:

да с этим я еще в 36 сообщении разобрался. кто же знал что еще порт в низкий уровень перевести нужно

НАЮХА??????????????????

Простите, ну уже с катушек слетаю, ... полсотни сообщений ... ну сколько можно тупить-то! Ну, поставьте же Вы, наконец, скобки в выражении "~ 1<<2" !!! Чтобы оно сначала сдвигало, а потом инвертировало, а не наоборот, как у Вас сейчас!

Порт ему надо переводить! Разобрался он!

Green
Онлайн
Зарегистрирован: 01.10.2015

Поражаюсь выдержке.) Сам бы уже давно психанул и послал куда подальше.(
Кстати, 2 мкс получил реакцию на прерывание. Чисто ради спортивного интереса.)

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Попробуйте так, согласно таблице

запись байта в память - 2 такта

запись 2 байтов       - 4 такта
запись 4 байтов       - 8 тактов
цикл int (long)       - 6 тактов
int ADD, SUB, MUL     - 6-7 тактов
int DIV               - 235-245 тактов
long ADD, SUB, MUL    - 15-17 тактов (22-23)
long DIV              - 670-680 тактов
int => float          - 70-72 тактов
float ADD, SUB, MUL   - 200-220 тактов
float DIV             - 550-560 тактов
sin(float)            - 2000 тактов / 124 мкс
millis                - 2 мкс
micros                - 4 мкс
digitalWrite          - 6-8 мкс, Mega - 8-9 mcs
digitalRead           - 4-6 мкс, Mega - 7 mcs
pinMode               - 5 мкс
analogRead            - 111-112 мкс
shiftOut              - 180-185 мкс, Mega - 210
 
Может и получится самое затратное это микрос но читаем мы его через раз, так что пробуйте, сам не проверял
bool readbit[8] = {};
bool f_start = 0;
bool minus = 0;
bool viev = 0;
uint32_t  time1;
uint8_t temp = 0;
uint8_t write_bit = 0;

//необходим для старта Чтобы не читать пин а менять minus = !minus;И  економить время
void start() {
  detachInterrupt(0);
  attachInterrupt(0, run, CHANGE);
  time1 = micros();
}
// Основная - считаем только минус <5 = 1 больше = 0 
void run() {
  if (minus) {
    temp = micros() - time1;
    if (f_start) {
      if (temp < 5) readbit[write_bit] = 1;//если минус < 5 = 1
      else readbit[write_bit] = 0;//иначе = 0
      write_bit++;
      if (write_bit == 7){
      write_bit = 0;
      f_start = 0;
      viev = 0;
      } 
    }
	if (temp == 14)f_start = 1;//ждем стартБит
  }
  if (!minus)time1 = micros();
  minus = !minus;
}

void setup() {
	pinMode(2, INPUT);
  Serial.begin(115200);
  attachInterrupt(0, start, FALLING);
}

void loop() {
  if (!viev) {
    for (int i = 0; i < 8; i++) {
      Serial.print(readbit[i]);
      if (i == 7) Serial.println();
      viev = 1;
    }
  }
}


 

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

Green пишет:

Кстати, 2 мкс получил реакцию на прерывание. Чисто ради спортивного интереса.)

Реакцию Вы получите и на полумикросекундное прерывание. Только измерить его длительность не сможете. А в случае PCINT, не сможете и определить, по какой ноге оно пришло.

Green
Онлайн
Зарегистрирован: 01.10.2015

andriano пишет:
Реакцию Вы получите и на полумикросекундное прерывание. Только измерить его длительность не сможете.


Почему нет?
 

#define BUF_SIZE          20
#define CORRECT_US        2

void setup() {
  Serial.begin(9600);
  Serial.println("Int " __DATE__ " " __TIME__);
  TCCR2B = 1<<CS21;                     //1us / 2
  EICRA = (EICRA & ~(1 << ISC00 | 1 << ISC01)) | FALLING << ISC00;
  EIMSK |= 1 << INT0;
}


volatile bool falling;

ISR (INT0_vect, ISR_NAKED) {
  asm volatile("push r24");
  falling = true;
  asm volatile("pop r24");
  reti();
}

uint8_t buf[BUF_SIZE];
uint8_t i;

void loop() {
  if (falling) {
    falling = false;
    TCNT2 = 0;
    while (!(PIND & 1<<2));
    if (i < BUF_SIZE)
      buf[i++] = TCNT2;
    else {
      for (i = 0; i < BUF_SIZE; i++) 
        Serial.println(buf[i] / 2 + CORRECT_US);
      while (1);
    }
  }
}

Результат:

Int Jul 14 2020 09:29:04
5
5
4
5
5
4
5
5
4
5
5
4
5
5
4
5
5
4
5
5
На входе меандр 100 кгц.
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Green, Вы не перепутали 5 мкс и 0.5 мкс?

Опять же, подсчет длительности Вы осуществляете аппаратным таймером, а не прерыванием либо основной программой.

Logik
Offline
Зарегистрирован: 05.08.2014

Причем в прерывании таймер не стартует. Только флаг. Затем бог весть сколько ползем по лупу до места, где этот флаг проверится и только потом стартуем таймер. Код в топку. 

И обработчик прерывания с push r24 выглядит многообещающе ))) Откуда уверенность что необходимо и достаточно r24?

 

Если уж так хочется чего померить - пишем buf[i++] = TCNT2; именно в обработчике. Прерывания по изменению уровня. Обнулять таймер не обязательно. Когда буфер кончится - из лупа вывод.

Green
Онлайн
Зарегистрирован: 01.10.2015

andriano пишет:

Green, Вы не перепутали 5 мкс и 0.5 мкс?

Опять же, подсчет длительности Вы осуществляете аппаратным таймером, а не прерыванием либо основной программой.


Я ничего не перепутал.) У ТС минимальная длительность 0-го импульса 3 мкс. Я привёл пример его измерения с помощью INT0. При минимальном времени обработчика.

Green
Онлайн
Зарегистрирован: 01.10.2015

Logik пишет:

Если уж так хочется чего померить - пишем buf[i++] = TCNT2; именно в обработчике. Прерывания по изменению уровня. Обнулять таймер не обязательно. Когда буфер кончится - из лупа вывод.


Это просто пример. Но даже так всё работает.

Green
Онлайн
Зарегистрирован: 01.10.2015

Logik пишет:
И обработчик прерывания с push r24 выглядит многообещающе ))) Откуда уверенность что необходимо и достаточно r24?

Оттуда.
 

00000436 <__vector_1>:
 436:	8f 93       	push	r24
 438:	81 e0       	ldi	r24, 0x01	; 1
 43a:	80 93 43 01 	sts	0x0143, r24	; 0x800143 <falling>
 43e:	8f 91       	pop	r24
 440:	18 95       	reti

 

iopq
Offline
Зарегистрирован: 05.07.2016

подскажите пожалуйста почему ардуино ide не содержит различных вспомогательных функций (того же автокомплита)? и есть ли какой нибудь более функциональный аналог для mac os? (типа phpstorm)

Logik
Offline
Зарегистрирован: 05.08.2014

Green пишет:

Logik пишет:
И обработчик прерывания с push r24 выглядит многообещающе ))) Откуда уверенность что необходимо и достаточно r24?

Оттуда.
 

00000436 <__vector_1>:
 436:	8f 93       	push	r24
 438:	81 e0       	ldi	r24, 0x01	; 1
 43a:	80 93 43 01 	sts	0x0143, r24	; 0x800143 <falling>
 43e:	8f 91       	pop	r24
 440:	18 95       	reti

 

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

Logik
Offline
Зарегистрирован: 05.08.2014

iopq пишет:

подскажите пожалуйста почему ардуино ide не содержит различных вспомогательных функций (того же автокомплита)? 

Интереснейший вопрос после 4-х лет на форуме. И в нужной теме. 

iopq
Offline
Зарегистрирован: 05.07.2016

представляю вариант кода (в виде картинки потому что комментарии сбиваются)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

плохая идея читать что либо в прерывании, лучше так 

volatile bool dataExist = false;

void loop(void){

.

.

if (dataExist) {

count = readbytes();

dataExist = false;

}

.

.

}



ISR(INT0_Vect) {

dataExist = true;

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

iopq пишет:

представляю вариант кода (в виде картинки

 

Никогда так не делайте, если хотите, чтобы это кто-то читал

b707
Offline
Зарегистрирован: 26.05.2017

iopq пишет:

представляю вариант кода (в виде картинки потому что комментарии сбиваются)

потому что не надо пытаться запихнуть в комментарии "Войну и мир". Пишите коротко. Длина строки кода вместе с комментариями не должна превышать 80 символов, а лучше - если 50-60

Поправьте комментарии и вставьте код нормально.

iopq
Offline
Зарегистрирован: 05.07.2016

DetSimen пишет:

плохая идея читать что либо в прерывании, лучше так 

volatile bool dataExist = false;

void loop(void){

.

.

if (dataExist) {

count = readbytes();

dataExist = false;

}

.

.

}



ISR(INT0_Vect) {

dataExist = true;

}

 

 

к сожалению не успевает так прочитаться 

Logik
Offline
Зарегистрирован: 05.08.2014

DetSimen пишет:

плохая идея читать что либо в прерывании, лучше так 

volatile bool dataExist = false;

void loop(void){

.

.

if (dataExist) {

count = readbytes();

dataExist = false;

}

.

.

}



ISR(INT0_Vect) {

dataExist = true;

}

 

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

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

Не смущай человека. Идея читать в прерывании верная. Только так можно мерить время точно. Почему - я выше писал. В прерывании можно все. Но быстро. И аккуратно.

ну-ну... посмотрите на код ТС. "Быстро и аккуратно" - это про него, как думаете?

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

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

Нет, в прерывании, конечно, можно все. Только сперва надо выключить все прерывания, а у ТС как он включил в setup, так они и продолжают работать. А если продолжают работать, цикл while в этом случае категорически противопоказан.

Logik
Offline
Зарегистрирован: 05.08.2014

Ну ту "картинку" действительно обсуждать не стоит. Но похоже она в любом случае завершится за 100-200мксек. Терпимо вполне. Особенно по сравнению, например, с софтовым UART. Работать будет (по крайней мере может работать при правильной реализации), остальному тоже мешать не будет.  Меня больше смущает в таких случаях системные прерывания. Если они "тикнут" немного раньше чем прийдет старт - будет пропуск данных. Но это не часто, к счастью.

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

Ну ту "картинку" действительно обсуждать не стоит. Но похоже она в любом случае завершится за 100-200мксек. Терпимо вполне.

что-то я там вижу длительность на порядок больше... но может это потому. что картинка кривая :)

Пусть вставляет код нормально

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:
и так и будет писать - всю программу в прерывание. как сейчас.
Пусть себе пишет. Проблема-то в чём? Ему уж столько раз объясняли тут ...

Logik
Offline
Зарегистрирован: 05.08.2014

b707 пишет:

Пусть вставляет код нормально

да.

iopq
Offline
Зарегистрирован: 05.07.2016
uint8_t readbytes(){
  DDRD   &= ~_BV (2);      //set D2 on input
  uint8_t count=0;               //here count gets byte
  uint8_t maxTries1 = 40;         //count tries to catch high level
while( (PIND & _BV(2)) == 0 ) //spin cycle while line in low level
if(!--maxTries1) return count;  //if device dont answer pullup line
while(1) {//dont know count started endless cycle                                           
  uint8_t result = 0;  //here put bits
for (uint8_t i = 0; i < 8; i++) { //cycle for read 1 byte
  PORTD  &= ~_BV (2);   //set low level on D2
  uint16_t maxTries = 500;  //count tries to catch low level
while( (PIND & _BV(2)) == 4 ) //spin cycle while line in high level
if(!--maxTries) return count;//if device dont answer pulldown line - bytes ended                             
  _delay_us(5);   //wait for catch middle
  result |= ((PIND & _BV(2)) == 4) << i;//find out what in middle - 0 or 1
  _delay_us(2);   //wait for skip second part bit
}
 temp[count++] = result;                    
}
}

не получается нифига

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

Ну а теперь выкиньте из прерывания все while.

Logik
Offline
Зарегистрирован: 05.08.2014

iopq пишет:

не получается нифига

Посмотри дизасемблированый код строки 15. Думаю удивит ;)

Параметры для _delay_us(...); ставь меньше расчетных. 1мксек - 16 тактов, грубо 10 процессорных команд. Потому сишные операторы сами по себе забирают время близкое к тем что требуются. Это надо учитывать.

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

Logik пишет:

Параметры для _delay_us(...); ставь меньше расчетных. 1мксек - 16 тактов, грубо 10 процессорных команд. Потому сишные операторы сами по себе забирают время близкое к тем что требуются. Это надо учитывать.

Вообще-то это учитывается. Так что ставить меньше расчетных не нужно. другое дело, что рассчитывать нужно правильно - с учетом тех операторов, что используются помимо delay.

Logik
Offline
Зарегистрирован: 05.08.2014

Расчетная - в смысле ту которую рассчитываем получить))

//рассчитывать нужно правильно

Сомневаюсь что автор такты считал. Иначе бы знал, что строка 15 скомпилируется в цикл, проходящий переменное кол-во раз. От 0 до 7. И длительность ее соответственно меняется очень заметно.

Кроме того, учитывая точность процесса, не стоит просто от стартового мерить. Лучше отслеживать фронты на каждом бите и по ним работать. Хотя это похоже пытается делать местами, например стр 12.

iopq
Offline
Зарегистрирован: 05.07.2016

andriano пишет:

Ну а теперь выкиньте из прерывания все while.

 

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

 

подумал логически - прерывание сработало, значит нам не нужно оно больше как минимум до тех пор пока мы не выясним идут ли за ним данные. потому я решил его просто отключить - cli()

теперь у меня все работает в цикле loop -

void loop() {

if(dataExist){
  cli();        //clear interrupt
  uint8_t count = readbytes();                                           
  sei();    //set interrupt
  dataExist = false;
}


}

 

renoshnik
Offline
Зарегистрирован: 11.04.2013

iopq пишет:

andriano пишет:

Ну а теперь выкиньте из прерывания все while.

 

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

 

подумал логически - прерывание сработало, значит нам не нужно оно больше как минимум до тех пор пока мы не выясним идут ли за ним данные. потому я решил его просто отключить - cli()

теперь у меня все работает в цикле loop -

void loop() {

if(dataExist){
  cli();        //clear interrupt
  uint8_t count = readbytes();                                           
  sei();    //set interrupt
  dataExist = false;
}


}

 

 

http://microsin.net/programming/avr/avr-gcc-atomically-and-non-atomically-executed-code-blocks.html