Перейти к содержанию
    

Как делить программу на объекты?

1 hour ago, ViKo said:

Я же не могу сам обработчик прерывания спрятать в класс? 

Можете, вот одно из решений

 

В прерывании по приему заполняем кольцевой буфер, семфорим наверх, что что-то в буфере изменилось.

В фоне задач (под такие проекты лучше использовать RTOS) разгребаем уже кольцевой буфер.

В фоне задач можно легко работать с таймаутами, а это сильно упрощает жизнь.

При передаче - анологично, но уже все наоборот.

В медленных интерфейсах буфером может быть просто "volatile uint8_t", который является частью класса.

Сами очереди (кольцевые буферы) будут являются частью класса задачи, наравне с экземпляром порта и обработчиком прерываний.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, k155la3 сказал:

Я не привязывал бы прием символа к ООП. На уровне прерываний имеет смысл отслеживать перерывы в передаче, заполнение буфера и анализ на заголовок пакета

(если конечно, у Вас "пакетный" обмен данными а не "поточный"). Эти флаги - "отображать" на класс frame_IO.

Куда относить буферы приема и передачи? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А почему не реализовать отдельный файл-драйвер приемника и не выдавать семафор в задачу парсера?

У меня, например, все делается примерно так

image.gif

 

1. ПК кодирует отправляемое сообщение с помощью какого-либо фреймера (например, использованием байт-стаффинга) и отправляет на МК.

2. МК по приему первого разделительного символа резервирует одну ячейку в кольцевом буфере для хранения длины принятого сообщения (иногда удобно разграничивать классы приходящих сообщений по их длине).

3. В том же обработчике приходящие символы раскодируются обратно и складываются в кольцевой буфер. Когда приемник видит завершающий символ, записываем в зарезервированное место кольцевого буфера (см. п. 2) длину сообщения.

4. Выдаем семафор задаче-обработчику входящих сообщений.

Задача-парсер вычитывает управляющую структуру почтового ящика, видит в нем непрочитанное сообщение (по крайней мере одно), видит первым элементом буфера размер сообщения, вычитывает это сообщение, парсит и вызывает соответствующий обработчик.

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

 

Зачем тут ООП?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 minutes ago, ViKo said:

Куда относить буферы приема и передачи? 

Буферы (или указатели на буферы) можете "уложить" в класс frame_IO. В нем - функции и переменные для работы с кольцевыми (если кольцевые) буферами.

"На выходе" класса его "интеллектом" должны формироваться инф. флаги

- буфер приема пуст 

- буфер передачи пуст 

- переполнение

- есть признак (сигнатура) заголовка пакета в буфере приема 

. . . .  итд

Работать с этими данными должен следующий по уровню класс (с его "интеллектом" - функциями), к примеру если есть признак заголовка пакета, то проверять целостность пакета (класс packet).

 

Quote

Еще вот что. Мне не нужно ничего наследовать. Я не пишу универсальных программ. Никаких базовых классов и т.п. Я просто хочу видеть свою программу более структурированной. Но не усложненной.

Наследование - основной плюс в ООП. Вопрос не в универсальности (хотя не без этого), а как раз в том, что вы спрашиваете - 

"Однако, не могу понять, как следовать этой вере.".  Вера в абстракциях, которые дает ООП.

1. В "объект" объединяются логически связанные данные и методы их обработки. 

2. Полученные объекты также объединяются/связываются по томуже принципу.

Вы соглашаетесь с 1. и не хотите использовать 2. 

IMHO

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Э-э... делегатов не хочу. Для меня это неоправданное усложнение.

Так же и двойные буферы.

RTOS тоже не хочу. До этого была, сейчас хочу попроще. Во всяком случае, на данном этапе. У меня взаимодействие с компом простое: принял команду - выполнил - ответил. И ничего кроме. Так вижу работу сейчас. Возможно, позже усложнится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, ViKo сказал:

RTOS тоже не хочу.

Тогда посмотрите в сторону обычных событийных систем: event-driven system. И ООП тут как собаке пятая нога:wink:

 

Вот весь мой main() такого подхода:

#include "EDS.h"
#include "Hardware.h"

int main(void)
{
  EDS_Init();
  HW_MCUInit();
	
  HW_PeriodicTimerStart();
	
  while(1)
  {
    if(EDS_GetEvent())
      EDS_EventHandler(CurrentEvent);
  }
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 минут назад, Arlleex сказал:

Тогда посмотрите в сторону обычных событийных систем: event-driven system. И ООП тут как собаке пятая нога

Но это EDS не запрещает использовать классы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 minutes ago, ViKo said:

Э-э... делегатов не хочу. Для меня это неоправданное усложнение.

Вы увидели страшное слово, но к вашей задаче оно не имеет отношения ))

 

 

Quote

Так же и двойные буферы.

А где вы их увидели? 

 

 

Quote

RTOS тоже не хочу. 

С этого и надо было начинать ))

 

Коли RTOS не нужно, то значит проект очень простой и ООП действительно тут как собаке пятая нога ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, ViKo сказал:

Но это EDS не запрещает использовать классы?

EDS - это всего лишь механизм построения программы без операционной системы.

Внутри - как Вам угодно.

 

У меня EDS основан на том же кольцевом буфере. При возникновении прерывания по UART принимаю в буфер этот символ, а в main() - извлекаю его и отправляю декодеру EDS_EventHandler(). Декодер простейший

void (*HandlerArray[])(void) =
{
  &Callback_PeriodicTimeout,
  &Callback_ExchangeRxData,
  &Callback_ExchangeTxData
};

void EDS_EventHandler(u32 CurrentEvent)
{
  void (*Callback)(void) = HandlerArray[CurrentEvent - 1];
  
  Callback();
  
  return;
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если Вам для контроллера - смотрите scmRTOS.  Cама RTOS на CPP. Использовал, "работает" :)

(в смысле посмотреть реализацию кода).

Не помню, правда, как там вектора прерываний оформлены.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, Arlleex сказал:

Внутри - как Вам угодно.

О том и спрашиваю. Какой класс создать, чтобы не глобальными буферами и указателями оперировать?

3 минуты назад, k155la3 сказал:

Если Вам для контроллера - смотрите scmRTOS.  Cама RTOS на CPP.

Я, возможно, когда-нибудь свою RTOS придумаю, простейшую. Но пока меня удовлетворяет Кейловская.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 minutes ago, ViKo said:

О том и спрашиваю. Какой класс создать, чтобы не глобальными буферами и указателями оперировать?

Обработчик прерываний - обычная C-функция, поэтому все равно в ней придется обращаться к неким глобальных объектам (пусть даже и static).

Поэтому без глобальных объектов в таком решении уж никак не обойтись.

 

 

Quote

Я, возможно, когда-нибудь свою RTOS придумаю, простейшую. Но пока меня удовлетворяет Кейловская.

Изобретать велосипед - это очень увлекательное и познавательно занятие :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 minutes ago, ViKo said:

Я, возможно, когда-нибудь свою RTOS придумаю, простейшую. Но пока меня удовлетворяет Кейловская.

Вы не поняли. Я предлагаю ознакомиться с исходником этой оси, напредмет использования в ней OOP.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, k155la3 сказал:

Вы не поняли. Я предлагаю ознакомиться с исходником этой оси, напредмет использования в ней OOP.

 

А, верно, можно посмотреть на классы. Ок.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

scmRTOS

//------------------------------------------------------------------------------
#pragma vector=SYSTEM_TIMER_VECTOR
OS_INTERRUPT void OS::system_timer_isr()
{
    scmRTOS_ISRW_TYPE ISR;

#if scmRTOS_SYSTIMER_HOOK_ENABLE == 1
    system_timer_user_hook();
#endif

    Kernel.system_timer();

#if scmRTOS_SYSTIMER_NEST_INTS_ENABLE == 1
    ENABLE_NESTED_INTERRUPTS();
#endif

}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...