Sí, la mayoría de los microcontroladores tienen suficiente soporte de hardware para que los hilos sean posibles. Si el mecanismo de llamada / retorno de hardware está basado en la pila, todo lo que realmente necesita es acceso arbitrario a la pila.
He realizado tareas múltiples muchas veces en varios PIC y dsPIC. Todo, desde el PIC 18 en adelante, soporta el enhebrado verdadero. Las partes centrales de 14 y 12 bits no le dan acceso completo a la pila de llamadas, por lo que no puede hacer subprocesos reales. He hecho lo que llamo pseudo-threading unas pocas veces. Aún puedes tener algo que en su mayoría se parece a un hilo independiente del software, aunque hay restricciones.
En general, es una abstracción de software útil para manejar cualquier entrada asíncrona con estado con una tarea separada. Hago esto rutinariamente, por ejemplo, para procesar la secuencia de comandos de UART desde el host.
No caiga en la arquitectura de "súper bucle", excepto para manejar una cantidad de eventos individuales. Entonces realmente se convierte en un bucle de eventos, por lo que es mejor llamarlo así. Por lo general, la tarea original ejecuta el bucle de eventos, después de inicializar el sistema e iniciar cualquier otra tarea que sea necesaria.
Tampoco cometa el error de suponer que la multitarea significa la prevención, o que requiere un RTOS. He realizado más de 100 proyectos de microcontroladores y he usado varias veces tareas múltiples. Hasta ahora no he encontrado un caso en el que la multitarea preventiva o un RTOS tuvieran sentido. Si te encuentras con esa estructura de software, es probable que no estés haciendo un microcontrol y estés más cerca de la informática general, incluso si está integrado.
Básicamente, use una tarea separada siempre que de otra manera quiera usar una máquina de estados llamada periódicamente desde un bucle de blooper. El código es mucho más limpio, más fácil de escribir y más fácil de mantener cuando la PC es la variable de estado. Solo asegúrate de llamar a TASK_YIELD en cualquier bucle donde esperes un evento.
Dado que el bucle de eventos principal es su propia tarea separada, también llama a TASK_YIELD periódicamente. Normalmente pongo la llamada a TASK_YIELD al inicio del bucle de eventos principal. Luego verifica cada evento en secuencia. Cuando encuentra un evento desencadenado, lo maneja y luego vuelve al inicio del bucle.
Mi código multitarea para PIC está disponible de forma gratuita en la versión de PIC Development Tools en enlace . Mire los archivos con "tarea" en su nombre en la FUENTE > Directorio PIC para las partes de 8 bits, y SOURCE > DSPIC para las partes de 16 bits. He usado estas instalaciones ampliamente, por lo que creo que son bastante sólidas.
En un PIC 18, la pila de llamadas está en la memoria dedicada. TASK_YIELD, por lo tanto, cambia la parte utilizada de la pila de llamadas a / desde un área de guardado para cada tarea. En los PIC de 16 bits, la pila es solo W15 apuntando a algún lugar en la memoria principal. Eso facilita el intercambio de tareas. Cada tarea obtiene un área de pila al frente. El intercambio de tareas es empujar los registros en la pila, apuntar W15 a la pila para la nueva tarea, y sacar los registros de la pila.
Recientemente medí el tiempo de bucle de la tarea en un proyecto dsPIC33EP actual. El procesador está funcionando a su velocidad máxima de 70 MHz en el reloj de instrucciones. En este caso, hubo 4 tareas. Éstos debían procesar el flujo UART desde otra micro, recepción de trama CAN de bajo nivel, procesamiento de trama CAN de nivel superior y el bucle de evento principal. Cuando no pasaba nada, el tiempo para un ciclo completo a través de todas las tareas era de 7 µs.
Añadido
Para abordar su ejemplo particular, las lecturas periódicas A / D deben tomarse en una rutina de interrupción. El proceso de SMS debe ser una tarea separada, tal vez dos. No estoy lo suficientemente familiarizado con los SMS para saber si la recepción es realmente asíncrona al envío.
Si es así, use una tarea para manejar lo que venga cada vez que la reciba, y otra tarea para enviar mensajes SMS, con lo que esté esperando en los eventos que puedan incluir. Cuando las tareas de envío de SMS esperan eventos, llama a TASK_YIELD en el bucle, lo que permite que todas las demás tareas continúen mientras esta tarea está bloqueada. Si está esperando las respuestas de SMS, haga que SMS reciba indicadores de conjunto de tareas cada vez que se reciban respuestas particulares. Las tareas de envío de SMS luego esperan en esas banderas, según corresponda.
Todo esto puede manejarse muy bien con tareas múltiples cooperativas. Un RTOS y todo el equipaje que viene con él se interpondría más de lo que ayudaría.