Как уже упоминалось в комментариях, основная проблема, по-видимому, заключается в том, что доступ к регистру портов, управляющему светодиодами, не защищен ни
PORTB ^= (1<<0); // in task 1
[...]
PORTB ^= (1<<1); // in task 2
[...]
PORTB ^= (1<<2); // in task 3
- atomi c
- ( путем отключения прерываний во время доступа или мер RTOS, таких как мьютекс)
- , развернутых для одной уникальной задачи:
Возможно, вводит в заблуждение, что доступ к регистру HW выполняется с использованием одиночная инструкция в коде C каждый раз. Тем не менее, это не помогает, потому что компилятор генерирует несколько инструкций ассемблера (например, загрузить предыдущее значение порта для регистрации, изменить это значение регистра, записать его обратно в порт). Таким образом, одна задача может прервать другую между этими инструкциями ассемблера / процессора и изменить промежуточное значение. Несколько задач, записывающих «свои» значения регистра в порт, поочередно могут вернуть другие задачи, которые только что были записаны в порт, поэтому вы пропускаете мигание (или несколько, если это происходит систематически).
Поэтому решение состоит в том, чтобы защитить задания друг от друга. В том же порядке, который пронумерован выше, это может означать одно из следующего:
- Проверьте, предлагает ли аппаратное обеспечение регистр "установленного значения" или "значения сброса" рядом с регистром основного порта
PORTB
. Если это так, запись одного бита в этот порт была бы atomi c способом переключения светодиодов. Извините, что не знаю аппаратного интерфейса Atmega. Возможно, это невозможно, и вам нужно go включить непосредственно в 2. и 3. a. Отключите прерывания перед изменением регистра порта, затем включите его снова. Таким образом, планировщик задач не будет работать в течение этого периода (= критическая секция), и никто не мешает задаче, которая обращается к оборудованию.
b. Используйте taskENTER_CRITICAL()
/ taskEXIT_CRITICAL()
c. Используйте мьютекс или подобное.
Создайте четвертое задание, которое ожидает (блокирует) в почтовом ящике / очереди. Всякий раз, когда он получает значение из почтового ящика, он обрабатывает его (например, отправляя XOR в регистр порта). Три существующие задачи не обращаются к регистру светодиодного порта самостоятельно, а вместо этого отправляют такое значение (= сообщение запроса) новой задаче. Присвойте новый приоритет более высокому приоритету, чтобы получить плавный мигающий рисунок.
Если на контроллере возможен вариант 1., он самый быстрый (но для него требуются определенные функции в аппаратная платформа ...). В противном случае я согласен с подсказкой @Richard, вариант 2.b. являются самыми быстрыми (2.a. такими же быстрыми, но не такими чистыми, потому что вы нарушаете многоуровневую структуру FreeRTOS lib).
Вариант 2. c. может привести к значительным накладным расходам, и вариант 3. очень чистый, но полный перебор в вашей ситуации: если ваш вопрос действительно касается только мигающих светодиодов, оставьте бульдозер в гараже и выберите вариант 2.