Можно выполнить довольно много всего лишь с одной задачей, особенно если у вас есть прерывания. Промежуточное положение между одной очень простой задачей и RTOS является циклическим исполнителем. См. http://www3.nd.edu/~cpoellab/teaching/cse40463/slides10.pdf для краткого обзора спектра функций от циклического управления до полностью упреждающей многозадачной операционной системы. Вы найдете гораздо больше, если будете искать эту фразу и связанные фразы, включая очень сложные схемы для обеспечения того, чтобы система никогда не упускала своих крайних сроков. Если вы являетесь системой управления полетом самолета, забывая проверить угол тангажа самолета каждые X мс, могут возникнуть проблемы в другом месте :-)
Один из способов перезаписи кода, который, естественно, имеет многопоточность, заключается в поддержании модели состояния система, такая как совокупность объектов, каждая из которых представляет собой соединение по Modbus, индексируется идентификатором соединения. Затем напишите процедуру для любого события, которое может произойти, включая приход прерывания тактовой частоты. Когда это событие происходит, эти процедуры обычно определяют, какое соединение задействовано, извлекают из основной коллекции (или создают ее с нуля и вводят там там, если необходимо) выполняют работу, связанную с этим конкретным видом события, а затем возвращают.
Часто бывает удобно хранить очередность будущих событий, индексированных по времени, и иметь подпрограмму, которая создает объект, представляющий что-то, что нужно сделать в будущем (например, вызов метода для проверки истечения срока действия тайм-аут) и помещает этот объект в очередь.
Вам нужно беспокоиться о том, что обработка прерываний вызывается наполовину через процедуру обслуживания событий. Один из способов борьбы с этим - блокировать прерывания, когда это может вызвать проблему. Другой способ заключается в том, что процедура прерывания делает не что иное, как помещать объект в очередь, что что-то еще проверит позже или просто установит флаг. Затем вам нужно только блокировать прерывания, когда вы проверяете элементы в очереди и удаляете их.
Ряд протоколов связи реализован таким образом. Даже в настоящей многозадачной операционной системе вы очень часто не хотите создавать новый поток каждый раз, когда вам нужно создать новое соединение. Две основные проблемы в этом состоит в том, что код менее понятен, чем код, который имеет поток на объект, потому что материал, который естественно объединяется, прерывается в нагрузках событий событий событий, и если какой-либо из методов службы событий сжигает значительные количества cpu, система остановится, потому что больше ничего не произойдет, когда это произойдет.
Вам придется реализовать потоки и небольшой упреждающий планировщик по сравнению с тем, что у вас есть для ОС («не RTOS» и «микроконтроллер» - это не совсем много информации для работы). Это не маленький проект, но это еще не так уж сложно. – Gene