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

Вернуться   Форум обсуждения систем "Умный дом", проектов Ардуино, 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 вне форума   Ответить с цитированием
 


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

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

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

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

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


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


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