Альтернативы потоков для встроенных систем

Aug 16 2020

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

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

Итак, мой код C (еще не реализованный специально для pic) выглядит примерно так:

void display_timer(){
  static struct current_time timer;
  static int is_time_set = 0;
  set_current_time(&timer, &is_time_set);

  while (is_time_set){
    system("clear");
    printf("########\n");
    printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
    printf("########\n");
    sleep(1);
    update_timer(&timer, &is_time_set);
  }
}
int main ()
{
  while (1){
    display_menu();

  }
}

Во время сна () контроллер должен иметь возможность отслеживать новые входные данные и действовать соответственно.

Я решил использовать конечный автомат для хранения нажатия кнопки, разделив функцию сна на 4 или 8 интервалов, примерно так:

  while (is_time_set){
    system("clear");
    printf("########\n");
    printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
    printf("########\n");
    for (int i = 0; i<8; i++){
    if (state_machine_input == 1){state_machine_input = 0; break;}
    sleep(1/8);
    }
    update_timer(&timer, &is_time_set);

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

Ответы

28 Lundin Aug 17 2020 at 07:04

Потоки - это концепция более высокого уровня, чем программирование микроконтроллеров. Проще говоря, потоки реализованы как планировщик, который использует прерывания таймера, который, в свою очередь, сохраняет счетчик программы + указатель стека и т. Д. И устанавливает их в разные места. Таким образом, вполне возможно и легко реализовать аналогичную концепцию с использованием прерываний - с тем преимуществом, что вы получаете специализированные прерывания вместо универсальной многопоточности.

Это почти единственный разумный способ сделать это с ограниченным устаревшим биттером 8, таким как PIC, который чрезвычайно ограничен, когда дело доходит до использования стека. Забудьте об использовании библиотек потоков, даже написанных для микроконтроллеров. Это только добавит чрезмерной раздутости и сложности, ничего не получится. В общем, переносить концепции программирования ПК во встраиваемый мир - плохая идея.

Что вам нужно сделать, так это поместить сканирование кнопок в прерывание циклического таймера, которое выполняется один раз в 10 мс или около того. Изнутри прерывания вы опрашиваете кнопки и сравниваете прочитанную кнопку с предыдущей в целях устранения неполадок. Результат этого сохраняется в переменной, совместно используемой с основной программой, объявленной как volatileсостояние гонки и защищенной от нее. Поскольку вы пишете в переменную только изнутри прерываний, это может быть достаточной защитой, чтобы гарантировать, что чтение составляет 8 бит, но вы должны дизассемблировать, чтобы быть уверенным. Более подробная информация о том , что здесь: Использовании летучего в разработках встраиваемого C .

15 Pelle Aug 17 2020 at 13:23

Используйте прерывания

Вы хотите запустить какой-то код при нажатии кнопки? Используйте прерывание при смене вывода

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

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

Основная программа автоматически приостанавливается при выполнении прерывания.

Распространенный способ обмена данными между прерываниями и основным кодом - через volatileглобальные переменные и временное отключение прерываний при чтении данных из этих глобальных объектов, когда они превышают размер слова контроллера (почти всегда на 8-битном контроллере)

11 AndrewLentvorski Aug 16 2020 at 23:38

Я бы, наверное, предложил совместную библиотеку многозадачности. Раньше я использовал Protothreads:http://www.dunkels.com/adam/pt/

Любая приличная совместная библиотека многозадачности поможет абстрагироваться от неявного конечного автомата, необходимого для отслеживания вещей.

Удачи.

6 bracco23 Aug 17 2020 at 12:53

Когда дело доходит до встроенной системы, существуют разные подходы к многозадачности:

  • Опрос или совместная многозадачность : все выполняется в одном бесконечном цикле, и задачи разработаны таким образом, чтобы занимать минимально возможное время и возвращаться к основному выполнению как можно быстрее, чтобы избежать задержек. Обратите внимание, что задачи, подходящие для этой архитектуры, могут быть не такими, как вы думаете с точки зрения концепции более высокого уровня, например, в вашем приложении может быть одна задача, а может быть update_displayдругая задача, check_buttonи вы должны построить цикл, например:
    while(1){
         check_buttons();
         update_display();
         sleep(0.1); //seconds
     }
  • Прерывания : все возможные входы, связанные с аппаратными прерываниями, и основное выполнение оставлено для вещей, которые не могут быть помещены в прерывание (может быть ничего, и в этом случае обычно микроконтроллер переводится в спящий режим для снижения энергопотребления. Подробнее о том, как это выполняется обычно в зависимости от конкретного используемого микроконтроллера и компилятора.

  • ОСРВ : в зависимости от мощности микроконтроллера можно запустить операционную систему реального времени (ОСРВ), которая может предоставлять API для создания задач или даже потоков. Это зависит от приложения и возможностей оборудования, и для учебных примеров не обязательно (или желательно, imo)

Учтите также, что еще одна важная часть в принятии решения об общей архитектуре приложения - это разделение задач и способы их взаимодействия. Одна из используемых парадигм - это State Machines (ссылка ведет на общую страницу википедии, которая может быть огромной; более простые ресурсы, относящиеся к встроенному программированию, можно найти в вашем учебнике или в Google).

5 ExpinElectronics Aug 17 2020 at 06:15

В основном в 8-битных устройствах есть ограниченный исходный код. Я думаю, что более простое решение - лучшее решение для 8-битных PIC.

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

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