Форум обсуждения систем  

Вернуться   Форум обсуждения систем "Умный дом", проектов Ардуино, OpenWRT и других DIY устройств > Разное > Курилка

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
Старый 13.08.2018, 20:46   #1
Tohin
Moderator
 
Регистрация: 20.07.2014
Адрес: МСК
Сообщений: 991
Вес репутации: 1030
Tohin is a jewel in the roughTohin is a jewel in the roughTohin is a jewel in the rough
По умолчанию Кольцевой буфер в прерываниях (AVR atmega328)

Мучая энкодер, понял, что вывод в Serial тормозит атмегу, что приводить к потере косяков энкодера.
Решил в прерываниях писать в FIFO, а в цикле выводить в Serial.
За пару часов родилось и скомпилировалось это:

Код

Код:
#define set_bit(reg,value) reg |= (_BV(value))
#define unset_bit(reg,value) reg &= ~(_BV(value))

#define BUF_SIZE 256 //размер буфера обязательно равен степени двойки!
#define BUF_MASK (BUF_SIZE-1)
 
uint8_t idxIN, idxOUT;

struct {
    uint8_t ReadPortD;  //тут храним состояние порта D Пины с 0-7 на ардуино UNO
    unsigned long timer;
}buff [BUF_SIZE] ;




ISR(PCINT2_vect){      // сработало прерывание 
  digitalWrite(13, HIGH);   // включает светодиод
  unset_bit (PCICR,PCIE2);  //отключаем прерывание до отработки прерывания, во избежании повторных срабатываний 
  buff[idxIN++] = {PIND, millis()} ;//записываем состояние порта D
  idxIN &= BUF_MASK;
  set_bit (PCICR,PCIE2);  //включаем прерывание. Вроде не забыл
  digitalWrite(13, LOW);   // включает светодиод
}

void setup()  
{
  pinMode(5,INPUT_PULLUP); // Clock Подключаем к INT1, нельзя переназначать
  pinMode(6, INPUT_PULLUP); // второй вывод энкодера
  pinMode(7, INPUT_PULLUP); // кнопка энкодера
  pinMode(13, OUTPUT); // кнопка энкодера
  
  Serial.begin(9600);
  while (!Serial);
  set_bit (PCICR,PCIE2);//Включаем прерывание PCINT16-23 (PortD) PCIE2, регистр PCICR принимает значение  0b00000100;
  PCMSK2 |= (_BV(PCINT23)| _BV(PCINT22) | _BV(PCINT21)); //Указываем, что надо реагировать только на пины 5,7 
  // для порта D соответствуют pcint 16-23
  Serial.println(PCMSK2,BIN);
  sei();//включаем прерывания
  Serial.println("ready");
}



void loop() {
    if (idxIN != idxOUT) {  // если сюда что-то записано, значит был поворот или нажатие кнопки, прерывания отключены. Надо бы не забыть их включить.
      Serial.print(idxIN);
      Serial.print(":");
      Serial.print(idxOUT);
      Serial.print(":");
      Serial.print(buff[idxOUT].timer);
      Serial.print(":");
      Serial.println(buff[idxOUT++].ReadPortD,BIN);
      idxOUT &= BUF_MASK;
     }

}
[свернуть]


Насколько он правильно работает - не знаю. Возможно в нем есть ошибки.
Но в выводе есть странности:
11:4016:11100101
12:4016:10100101
13:4016:10100101
14:4016:10100101
15:4016:10100101
16:4016:11100101

В моем представлении в течении 4016 миллисекунды сначало произошло падение напряжения на 6 пине (с 11 на 12 срабатывание), потом 3 непонятных события (регистр PIND без изменений), и восстановление напряжения.

А есть что-то быстрее чем millis()? Чтобы увидеть насколько разнесены по времени срабатывания.

Последний раз редактировалось Tohin; 16.08.2018 в 21:11.
Tohin вне форума   Ответить с цитированием
Старый 13.08.2018, 21:04   #2
Admin
Administrator
 
Аватар для Admin
 
Регистрация: 12.04.2010
Адрес: Москва
Сообщений: 9,616
Вес репутации: 9820
Admin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant future
По умолчанию

Цитата:
А есть что-то быстрее чем millis()?
micros()
Admin вне форума   Ответить с цитированием
Старый 14.08.2018, 11:04   #3
stD
Senior Member
 
Аватар для stD
 
Регистрация: 02.04.2012
Адрес: Питер
Сообщений: 1,125
Вес репутации: 1310
stD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant futurestD has a brilliant future
По умолчанию

Буфер слопал 60% ОЗУ.
__________________
istarik.ru
stD вне форума   Ответить с цитированием
Старый 16.08.2018, 21:11   #4
Tohin
Moderator
 
Регистрация: 20.07.2014
Адрес: МСК
Сообщений: 991
Вес репутации: 1030
Tohin is a jewel in the roughTohin is a jewel in the roughTohin is a jewel in the rough
По умолчанию

Мне для тестов и 100% не жалко это ж не для устройства, это ж что-то вроде примитивного осцилографа для понимания косяков работы энкодера.
Хотя если есть реализация более правильная - с удовольствием посмотрю!

Micros() тоже не помог:
5 1 6365 11000101
14 2 6365 11000101
14 3 6365 11000101
87 4 6365 11000101
254 5 6365 11100101


Если я правильно трактую рост idxIN в течении одной микросекунды произошло более 200 прерываний.

Последний раз редактировалось Tohin; 16.08.2018 в 21:14.
Tohin вне форума   Ответить с цитированием
Старый 16.08.2018, 21:28   #5
Admin
Administrator
 
Аватар для Admin
 
Регистрация: 12.04.2010
Адрес: Москва
Сообщений: 9,616
Вес репутации: 9820
Admin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant future
По умолчанию

Конденсаторы стоят? Я вроде рекомендовал

Цитата:
Если я правильно трактую рост idxIN в течении одной микросекунды произошло более 200 прерываний.
Это дребезг контактов
Admin вне форума   Ответить с цитированием
Старый 16.08.2018, 21:52   #6
Tohin
Moderator
 
Регистрация: 20.07.2014
Адрес: МСК
Сообщений: 991
Вес репутации: 1030
Tohin is a jewel in the roughTohin is a jewel in the roughTohin is a jewel in the rough
По умолчанию

Я понимаю что это дребезг. Только что напаял 0.09 uF.
Стало лучше. Но есть и ложные срабатывания (5 последних значений одинаковые)
219 202 25528 11000101
219 203 25533 10000101
219 204 25533 10100111
219 205 25533 10000111
219 206 25533 10000111
219 207 25533 10000111
219 208 25533 10000111
219 209 25534 10000111


А что если в самом прерывании сравнивать текущее значение с предыдущим и отбрасывать идентичные? кажется так:
if ((PIND>>5)^(last_PIND>>5))

Последний раз редактировалось Tohin; 21.12.2018 в 21:54.
Tohin вне форума   Ответить с цитированием
Ответ


Здесь присутствуют: 3 (пользователей: 0 , гостей: 3)
 
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход


Текущее время: 12:40. Часовой пояс GMT +3.


Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Яндекс.Метрика